您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
174 行
5.7 KiB
174 行
5.7 KiB
using System;
|
|
using UnityEditor;
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
using UOP1.StateMachine.ScriptableObjects;
|
|
using static UnityEditor.EditorGUI;
|
|
|
|
namespace UOP1.StateMachine.Editor
|
|
{
|
|
internal class AddTransitionHelper : IDisposable
|
|
{
|
|
internal SerializedTransition SerializedTransition { get; }
|
|
private readonly SerializedObject _transition;
|
|
private readonly ReorderableList _list;
|
|
private readonly TransitionTableEditor _editor;
|
|
private bool _toggle = false;
|
|
|
|
internal AddTransitionHelper(TransitionTableEditor editor)
|
|
{
|
|
_editor = editor;
|
|
_transition = new SerializedObject(ScriptableObject.CreateInstance<TransitionItemSO>());
|
|
SerializedTransition = new SerializedTransition(_transition.FindProperty("Item"));
|
|
_list = new ReorderableList(_transition, SerializedTransition.Conditions);
|
|
SetupConditionsList(_list);
|
|
}
|
|
|
|
internal void Display(Rect position)
|
|
{
|
|
var rect = position;
|
|
float listHeight = _list.GetHeight();
|
|
float singleLineHeight = EditorGUIUtility.singleLineHeight;
|
|
|
|
// Display add button only if not already adding a transition
|
|
if (!_toggle)
|
|
{
|
|
position.height = singleLineHeight;
|
|
|
|
// Reserve space
|
|
GUILayoutUtility.GetRect(position.width, position.height);
|
|
|
|
if (GUI.Button(position, "Add Transition"))
|
|
{
|
|
_toggle = true;
|
|
SerializedTransition.ClearProperties();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Background
|
|
{
|
|
position.height = listHeight + singleLineHeight * 4;
|
|
DrawRect(position, ContentStyle.LightGray);
|
|
}
|
|
|
|
// Reserve space
|
|
GUILayoutUtility.GetRect(position.width, position.height);
|
|
|
|
// State Fields
|
|
{
|
|
position.y += 10;
|
|
position.x += 25;
|
|
StatePropField(position, "From", SerializedTransition.FromState);
|
|
position.x = rect.width / 2 + 25;
|
|
StatePropField(position, "To", SerializedTransition.ToState);
|
|
}
|
|
|
|
// Conditions List
|
|
{
|
|
position.y += 30;
|
|
position.x = rect.x + 10;
|
|
position.height = listHeight;
|
|
position.width -= 20;
|
|
_list.DoList(position);
|
|
}
|
|
|
|
// Add and cancel buttons
|
|
{
|
|
position.y += position.height + 5;
|
|
position.height = singleLineHeight;
|
|
position.width = rect.width / 2 - 20;
|
|
if (GUI.Button(position, "Add Transition"))
|
|
{
|
|
if (SerializedTransition.FromState.objectReferenceValue == null)
|
|
Debug.LogException(new ArgumentNullException("FromState"));
|
|
else if (SerializedTransition.ToState.objectReferenceValue == null)
|
|
Debug.LogException(new ArgumentNullException("ToState"));
|
|
else if (SerializedTransition.FromState.objectReferenceValue == SerializedTransition.ToState.objectReferenceValue)
|
|
Debug.LogException(new InvalidOperationException("FromState and ToState are the same."));
|
|
else
|
|
{
|
|
_editor.AddTransition(SerializedTransition);
|
|
_toggle = false;
|
|
}
|
|
}
|
|
position.x += rect.width / 2;
|
|
if (GUI.Button(position, "Cancel"))
|
|
{
|
|
_toggle = false;
|
|
}
|
|
}
|
|
|
|
void StatePropField(Rect pos, string label, SerializedProperty prop)
|
|
{
|
|
pos.height = singleLineHeight;
|
|
LabelField(pos, label);
|
|
pos.x += 40;
|
|
pos.width /= 4;
|
|
PropertyField(pos, prop, GUIContent.none);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(_transition.targetObject);
|
|
_transition.Dispose();
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private static void SetupConditionsList(ReorderableList reorderableList)
|
|
{
|
|
reorderableList.elementHeight *= 2.3f;
|
|
reorderableList.drawHeaderCallback += rect => GUI.Label(rect, "Conditions");
|
|
reorderableList.onAddCallback += list =>
|
|
{
|
|
int count = list.count;
|
|
list.serializedProperty.InsertArrayElementAtIndex(count);
|
|
var prop = list.serializedProperty.GetArrayElementAtIndex(count);
|
|
prop.FindPropertyRelative("Condition").objectReferenceValue = null;
|
|
prop.FindPropertyRelative("ExpectedResult").enumValueIndex = 0;
|
|
prop.FindPropertyRelative("Operator").enumValueIndex = 0;
|
|
};
|
|
|
|
reorderableList.drawElementCallback += (Rect rect, int index, bool isActive, bool isFocused) =>
|
|
{
|
|
var prop = reorderableList.serializedProperty.GetArrayElementAtIndex(index);
|
|
rect = new Rect(rect.x, rect.y + 2.5f, rect.width, EditorGUIUtility.singleLineHeight);
|
|
var condition = prop.FindPropertyRelative("Condition");
|
|
if (condition.objectReferenceValue != null)
|
|
{
|
|
string label = condition.objectReferenceValue.name;
|
|
GUI.Label(rect, "If");
|
|
GUI.Label(new Rect(rect.x + 20, rect.y, rect.width, rect.height), label, EditorStyles.boldLabel);
|
|
EditorGUI.PropertyField(new Rect(rect.x + rect.width - 180, rect.y, 20, rect.height), condition, GUIContent.none);
|
|
}
|
|
else
|
|
{
|
|
EditorGUI.PropertyField(new Rect(rect.x, rect.y, 150, rect.height), condition, GUIContent.none);
|
|
}
|
|
EditorGUI.LabelField(new Rect(rect.x + rect.width - 120, rect.y, 20, rect.height), "Is");
|
|
EditorGUI.PropertyField(new Rect(rect.x + rect.width - 60, rect.y, 60, rect.height), prop.FindPropertyRelative("ExpectedResult"), GUIContent.none);
|
|
EditorGUI.PropertyField(new Rect(rect.x + 20, rect.y + EditorGUIUtility.singleLineHeight + 5, 60, rect.height), prop.FindPropertyRelative("Operator"), GUIContent.none);
|
|
};
|
|
|
|
reorderableList.onChangedCallback += list => reorderableList.serializedProperty.serializedObject.ApplyModifiedProperties();
|
|
reorderableList.drawElementBackgroundCallback += (Rect rect, int index, bool isActive, bool isFocused) =>
|
|
{
|
|
if (isFocused)
|
|
EditorGUI.DrawRect(rect, ContentStyle.Focused);
|
|
|
|
if (index % 2 != 0)
|
|
EditorGUI.DrawRect(rect, ContentStyle.ZebraDark);
|
|
else
|
|
EditorGUI.DrawRect(rect, ContentStyle.ZebraLight);
|
|
};
|
|
}
|
|
|
|
// SO to serialize a TransitionItem
|
|
internal class TransitionItemSO : ScriptableObject
|
|
{
|
|
public TransitionTableSO.TransitionItem Item = default;
|
|
}
|
|
}
|
|
}
|