- 最后登录
- 2017-4-1
- 注册时间
- 2011-7-26
- 阅读权限
- 90
- 积分
- 24690
  
- 纳金币
- 24658
- 精华
- 6
|
现在,组件再被启动时,星星不再出现。不幸的是,它不再相应修改。幸好,这很容易解决。
SerializedObject.ApplyModifiedProperties方法可以返回任何修改的实际情况。这样,我们就能很简单的调用target的UpdateStar方法。我们需要显式转换target的类型,因为编辑器需要为所有类型提供支持,所以target的类型被定义成了Object。
译者注,有一种方法可以简单的解决这个问题,写一个基类如下
public class InspectorBase<T> : Editor where T : UnityEngine.Object
{
protected T Target { get { return (T)target; } }
}
然后全部的编辑器类都继承这个基类如下
[CustomEditor(typeof(Star))]
public class StarEditor : InspectorBase< Star >
{
......
}
这样在以后的代码里,target会自动成为你想要的类型。
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Star))]
public class StarInspector : Editor {
private static GUIContent
insertContent = new GUIContent("+", "duplicate this point"),
deleteContent = new GUIContent("-", "delete this point"),
pointContent = GUIContent.none,
teleportContent = new GUIContent("T");
private static GUILayoutOption
buttonWidth = GUILayout.MaxWidth(20f),
colorWidth = GUILayout.MaxWidth(50f);
private SerializedObject star;
private SerializedProperty
points,
frequency,
centerColor;
private int teleportingElement;
void OnEnable () { … }
public override void OnInspectorGUI () {
star.Update();
GUILayout.Label(" oints");
for(int i = 0; i < points.arraySize; i++){
EditorGUILayout.BeginHorizontal();
SerializedProperty point = points.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(point.FindPropertyRelative("offset"), pointContent);
EditorGUILayout.PropertyField(point.FindPropertyRelative("color"), pointContent, colorWidth);
if(GUILayout.Button(teleportContent, EditorStyles.miniButtonLeft, buttonWidth)){
if(teleportingElement >= 0){
points.MoveArrayElement(teleportingElement, i);
teleportingElement = -1;
teleportContent.tooltip = "start teleporting this point";
}
else{
teleportingElement = i;
teleportContent.tooltip = "teleport here";
}
}
if(GUILayout.Button(insertContent, EditorStyles.miniButtonMid, buttonWidth)){
points.InsertArrayElementAtIndex(i);
}
if(GUILayout.Button(deleteContent, EditorStyles.miniButtonRight, buttonWidth)){
points.DeleteArrayElementAtIndex(i);
}
EditorGUILayout.EndHorizontal();
}
if(teleportingElement >= 0){
GUILayout.Label("teleporting point " + teleportingElement);
}
EditorGUILayout.PropertyField(frequency);
EditorGUILayout.PropertyField(centerColor);
if(star.ApplyModifiedProperties()){
((Star)target).UpdateStar();
}
}
}
编辑中的星星
![]()
现在,Mesh没有立即更新。这让编辑轻松许多!可惜的是,它还没有支持Undo!
不幸的是,在Unity中没有一种简单的方法来支持Undo事件,但我们可以做到接近支持。在我们的案例中,我们可以检查ValidateCommand事件是否发生,来判断Undo操作。当前被选中的对象这个事件的目标,我们假设它被修改过。
What's a ValidateCommand?
ValidateCommand is a type of GUI event, which indicates that some special action happened, like undo or redo. So why isn't it called something like ExecuteCommand? Actually, that command type exists as well. While they have a slightly different meaning, in practice you use them for the exact same purpose. Unfortunately, depening on exactly where you're checking and how you're cons***cting your GUI, either one or the other event happens, but not both. Why this is so, I do not know.
So to be perfectly safe, you have to check for both command types. In this case, however, you can suffice with checking ValidateCommand.
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Star))]
public class StarInspector : Editor {
private static GUIContent
insertContent = new GUIContent("+", "duplicate this point"),
deleteContent = new GUIContent("-", "delete this point"),
pointContent = GUIContent.none,
teleportContent = new GUIContent("T");
private static GUILayoutOption
buttonWidth = GUILayout.MaxWidth(20f),
colorWidth = GUILayout.MaxWidth(50f);
private SerializedObject star;
private SerializedProperty
points,
frequency,
centerColor;
private int teleportingElement;
void OnEnable () { … }
public override void OnInspectorGUI () {
star.Update();
GUILayout.Label(" oints");
for(int i = 0; i < points.arraySize; i++){
EditorGUILayout.BeginHorizontal();
SerializedProperty point = points.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(point.FindPropertyRelative("offset"), pointContent);
EditorGUILayout.PropertyField(point.FindPropertyRelative("color"), pointContent, colorWidth);
if(GUILayout.Button(teleportContent, EditorStyles.miniButtonLeft, buttonWidth)){
if(teleportingElement >= 0){
points.MoveArrayElement(teleportingElement, i);
teleportingElement = -1;
teleportContent.tooltip = "start teleporting this point";
}
else{
teleportingElement = i;
teleportContent.tooltip = "teleport here";
}
}
if(GUILayout.Button(insertContent, EditorStyles.miniButtonMid, buttonWidth)){
points.InsertArrayElementAtIndex(i);
}
if(GUILayout.Button(deleteContent, EditorStyles.miniButtonRight, buttonWidth)){
points.DeleteArrayElementAtIndex(i);
}
EditorGUILayout.EndHorizontal();
}
if(teleportingElement >= 0){
GUILayout.Label("teleporting point " + teleportingElement);
}
EditorGUILayout.PropertyField(frequency);
EditorGUILayout.PropertyField(centerColor);
if(
star.ApplyModifiedProperties() ||
(Event.current.type == EventType.ValidateCommand &&
Event.current.commandName == "UndoRedoPerformed")
){
((Star)target).UpdateStar();
}
}
}
最后,一个舒服的编辑过程!还有什么需要做吗?在编辑器的右上角有一个齿轮图标能够重置组件。当我们重置Star组件的时候我们的Mesh没有及时更新。
你可以定义Reset方法来监听一个组件的重置。这事Unity为Editor及其子类提供的一个方法。当这个事件发生,我们只要及时更新我们的星星就可以了。
using System;
using UnityEngine;
[ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class Star : MonoBehaviour {
[Serializable]
public class Point { … }
public Point[] points;
public int frequency = 1;
public Color centerColor;
private Mesh mesh;
private Vector3[] vertices;
private Color[] colors;
private int[] triangles;
public void UpdateStar () { … }
void OnEnable () { … }
void OnDisable () { … }
void Reset () {
UpdateStar();
}
} |
|