You've already forked taptap2024_GJ_chidouren
393 lines
14 KiB
C#
393 lines
14 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEditor.Graphs;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UIElements;
|
||
|
|
|
||
|
|
namespace XFFSM
|
||
|
|
{
|
||
|
|
public class FSMTransitionBackground : ImmediateModeElement
|
||
|
|
{
|
||
|
|
private float edgeDistanceMultiplier => Mathf.Clamp(graphView.scale, 0.1f, 1);
|
||
|
|
|
||
|
|
private float edgeSizeMultiplier => Mathf.Clamp( graphView.scale,0.1f,1);
|
||
|
|
|
||
|
|
private static Slot s_TargetDraggingSlot;
|
||
|
|
|
||
|
|
private FSMStateGraphView graphView;
|
||
|
|
|
||
|
|
private static Vector3 edgeToSelfOffsetVector => new Vector3(0f, 30f, 0f);
|
||
|
|
|
||
|
|
private static Color selectedEdgeColor => new Color(0.42f, 0.7f, 1f, 1f);
|
||
|
|
|
||
|
|
public FSMTransitionData CloseTransition { get;internal set; }
|
||
|
|
|
||
|
|
public FSMTransitionData Selection { get; set; }
|
||
|
|
|
||
|
|
private FSMTransitionData entryToDefault = new FSMTransitionData();
|
||
|
|
|
||
|
|
private Vector3[] vectors = new Vector3[2];
|
||
|
|
|
||
|
|
private Vector3[] points = new Vector3[2];
|
||
|
|
|
||
|
|
private static Color defaultTransitionColor => new Color(0.6f, 0.4f, 0f, 1f);
|
||
|
|
|
||
|
|
private static FSMTransitionData current_change_transition;
|
||
|
|
private float current_change_transition_timer = 0;
|
||
|
|
|
||
|
|
#region 退出当前子状态
|
||
|
|
private FSMStateNode currentState;
|
||
|
|
private bool state_exiting = false;
|
||
|
|
private string exit_state_parent;
|
||
|
|
private string exit_state_name;
|
||
|
|
private string exit_state_to_name;
|
||
|
|
private float exit_state_timer = 0;
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
// Fix编码
|
||
|
|
protected override void ImmediateRepaint()
|
||
|
|
{
|
||
|
|
List<FSMTransitionData> transitions = Context.Instance.GetCurrentShowTransitionData();
|
||
|
|
//if (transitions == null || transitions.Count == 0)
|
||
|
|
// return;
|
||
|
|
|
||
|
|
if (Event.current.type == EventType.Repaint)
|
||
|
|
{
|
||
|
|
VisualElement visualElement = base.parent;
|
||
|
|
graphView = visualElement as FSMStateGraphView;
|
||
|
|
if (graphView == null)
|
||
|
|
throw new InvalidOperationException("FSMTransitionBackground can only be added to a GraphView");
|
||
|
|
|
||
|
|
if (transitions != null)
|
||
|
|
{
|
||
|
|
foreach (var transition in transitions)
|
||
|
|
{
|
||
|
|
DrawTransiton(transition,Color.white);
|
||
|
|
DrawCurrentTransition(transition);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
List<FSMStateNodeData> nodes = Context.Instance.GetCurrentShowStateNodeData();
|
||
|
|
if (nodes != null)
|
||
|
|
{
|
||
|
|
entryToDefault.fromStateName = string.Empty;
|
||
|
|
entryToDefault.toStateName = string.Empty;
|
||
|
|
|
||
|
|
foreach (var item in nodes)
|
||
|
|
{
|
||
|
|
if (item.IsEntryState)
|
||
|
|
entryToDefault.fromStateName = item.name;
|
||
|
|
if(item.defaultState)
|
||
|
|
entryToDefault.toStateName = item.name;
|
||
|
|
}
|
||
|
|
|
||
|
|
DrawTransiton(entryToDefault, defaultTransitionColor);
|
||
|
|
}
|
||
|
|
|
||
|
|
DrawMakeTransition();
|
||
|
|
|
||
|
|
DrawStateExitTransition();
|
||
|
|
}
|
||
|
|
|
||
|
|
if(graphView.HoverNode == null)
|
||
|
|
CloseTransition = FindClosestTransition();
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawTransiton(FSMTransitionData data,Color color )
|
||
|
|
{
|
||
|
|
|
||
|
|
FSMNodeView fromNode = graphView.GetNode(data.fromStateName);
|
||
|
|
FSMNodeView toNode = graphView.GetNode(data.toStateName);
|
||
|
|
|
||
|
|
if (fromNode == null || toNode == null)
|
||
|
|
return;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
if (data == Selection)
|
||
|
|
color = selectedEdgeColor;
|
||
|
|
|
||
|
|
Vector3[] edgePoints = GetTransitionPoints(data );
|
||
|
|
|
||
|
|
DrawTransiton(edgePoints, color, data == CloseTransition, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawTransiton(Vector3[] edgePoints ,Color color,bool bold,bool isDrawArrow)
|
||
|
|
{
|
||
|
|
Texture2D tex = (Texture2D)Styles.connectionTexture.image;
|
||
|
|
float arrowSize = 5f * edgeSizeMultiplier;
|
||
|
|
float outlineWidth = 2f * edgeSizeMultiplier;
|
||
|
|
float arrowLength = 13f * edgeSizeMultiplier;
|
||
|
|
Handles.color = color;
|
||
|
|
float width = 10f * edgeSizeMultiplier;
|
||
|
|
|
||
|
|
if (bold)
|
||
|
|
{
|
||
|
|
arrowSize *= 1.5f;
|
||
|
|
width *= 1.5f;
|
||
|
|
}
|
||
|
|
|
||
|
|
Handles.DrawAAPolyLine(tex, width, edgePoints[0], edgePoints[1]);
|
||
|
|
if (isDrawArrow) {
|
||
|
|
Vector3 cross = Vector3.Cross((edgePoints[0] - edgePoints[1]).normalized, Vector3.forward);
|
||
|
|
DrawArrows(color, cross, edgePoints, isSelf: false, arrowSize, outlineWidth, arrowLength);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Vector3[] GetTransitionPoints(FSMTransitionData data )
|
||
|
|
{
|
||
|
|
return GetTransitionPoints(data.fromStateName, data.toStateName);
|
||
|
|
}
|
||
|
|
|
||
|
|
private Vector3[] GetTransitionPoints(string fromStateName,string toStateName)
|
||
|
|
{
|
||
|
|
FSMNodeView fromNode = graphView.GetNode(fromStateName);
|
||
|
|
FSMNodeView toNode = graphView.GetNode(toStateName);
|
||
|
|
|
||
|
|
if (fromNode == null || toNode == null)
|
||
|
|
return null;
|
||
|
|
|
||
|
|
float num = 5f * edgeDistanceMultiplier;
|
||
|
|
|
||
|
|
points[0] = GetNodeViewPosition(fromNode);
|
||
|
|
points[1] = GetNodeViewPosition(toNode);
|
||
|
|
|
||
|
|
Vector3 cross = Vector3.Cross((points[0] - points[1]).normalized, Vector3.forward);
|
||
|
|
points[0] += cross * num;
|
||
|
|
points[1] += cross * num;
|
||
|
|
return points;
|
||
|
|
}
|
||
|
|
|
||
|
|
private Vector3 GetNodeViewPosition(FSMNodeView node)
|
||
|
|
{
|
||
|
|
return graphView.contentViewContainer.transform.matrix.MultiplyPoint(node.GetPosition().center);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void DrawArrows(Color color, Vector3 cross, Vector3[] edgePoints, bool isSelf, float arrowSize, float outlineWidth, float arrowLength)
|
||
|
|
{
|
||
|
|
Vector3 vector = edgePoints[1] - edgePoints[0];
|
||
|
|
Vector3 normalized = vector.normalized;
|
||
|
|
Vector3 vector2 = vector * 0.5f + edgePoints[0];
|
||
|
|
vector2 -= cross * 0.5f;
|
||
|
|
float num = Mathf.Min(arrowLength * 1.5f, (vector2 - edgePoints[0]).magnitude) * 0.66f;
|
||
|
|
int num2 = 1;
|
||
|
|
|
||
|
|
for (int i = 0; i < num2; i++)
|
||
|
|
{
|
||
|
|
Color color2 = color;
|
||
|
|
|
||
|
|
Vector3 center = vector2 + (float)((num2 == 1) ? i : (i - 1)) * num * (isSelf ? cross : normalized);
|
||
|
|
DrawArrow(color2, cross, normalized, center, arrowSize, outlineWidth);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void DrawArrow(Color color, Vector3 cross, Vector3 direction, Vector3 center, float arrowSize, float outlineWidth)
|
||
|
|
{
|
||
|
|
if (Event.current.type == EventType.Repaint)
|
||
|
|
{
|
||
|
|
Vector3[] array = new Vector3[4];
|
||
|
|
array[0] = center + direction * arrowSize;
|
||
|
|
array[1] = center - direction * arrowSize + cross * arrowSize;
|
||
|
|
array[2] = center - direction * arrowSize - cross * arrowSize;
|
||
|
|
array[3] = array[0];
|
||
|
|
Shader.SetGlobalColor("_HandleColor", color);
|
||
|
|
Handles.color = color;
|
||
|
|
Handles.DrawAAPolyLine((Texture2D)Styles.connectionTexture.image, outlineWidth, array);
|
||
|
|
Handles.DrawAAConvexPolygon(array);
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public FSMTransitionData FindClosestTransition()
|
||
|
|
{
|
||
|
|
FSMTransitionData result = null;
|
||
|
|
float num = float.PositiveInfinity;
|
||
|
|
Vector3 vector = Event.current.mousePosition;
|
||
|
|
|
||
|
|
List<FSMTransitionData> transitions = Context.Instance.GetCurrentShowTransitionData();
|
||
|
|
if (transitions == null || transitions.Count == 0)
|
||
|
|
return null;
|
||
|
|
|
||
|
|
foreach (var transition in transitions)
|
||
|
|
{
|
||
|
|
Vector3[] edgePoints = GetTransitionPoints(transition);
|
||
|
|
|
||
|
|
if(edgePoints == null) continue;
|
||
|
|
|
||
|
|
float num2 = float.PositiveInfinity;
|
||
|
|
num2 = ((!(edgePoints[0] == edgePoints[1])) ? HandleUtility.DistancePointLine(vector, edgePoints[0], edgePoints[1]) : Vector3.Distance(edgeToSelfOffsetVector + edgePoints[0], vector));
|
||
|
|
if (num2 < num && num2 < 10f)
|
||
|
|
{
|
||
|
|
num = num2;
|
||
|
|
result = transition;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void OnTransitionSelection(FSMTransitionData transition)
|
||
|
|
{
|
||
|
|
if (this.Selection != null && transition == null)
|
||
|
|
{
|
||
|
|
FSMTransitionInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
this.Selection = transition;
|
||
|
|
//Debug.Log("OnTransitionSelection");
|
||
|
|
|
||
|
|
|
||
|
|
if(Selection != null)
|
||
|
|
{
|
||
|
|
EditorApplication.delayCall -= DelayCallSelection;
|
||
|
|
EditorApplication.delayCall += DelayCallSelection;
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawMakeTransition()
|
||
|
|
{
|
||
|
|
if (!graphView.isMakeTransition)
|
||
|
|
return;
|
||
|
|
|
||
|
|
vectors[0] = GetNodeViewPosition(graphView.MakeTransitionFrom);
|
||
|
|
|
||
|
|
if (graphView.HoverNode != null && !graphView.HoverNode.Data.isBuildInState)
|
||
|
|
vectors[1] = GetNodeViewPosition(graphView.HoverNode);
|
||
|
|
else
|
||
|
|
vectors[1] = Event.current.mousePosition;
|
||
|
|
|
||
|
|
DrawTransiton(vectors , Color.white,false, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 绘制当前状态切换的过渡
|
||
|
|
/// </summary>
|
||
|
|
private void DrawCurrentTransition(FSMTransitionData transition )
|
||
|
|
{
|
||
|
|
if (Context.Instance.FSMController == null)
|
||
|
|
return;
|
||
|
|
if (Context.Instance.FSMController.RuntimeFSMController == null)
|
||
|
|
return;
|
||
|
|
if (Context.Instance.RuntimeFSMController == null)
|
||
|
|
return;
|
||
|
|
|
||
|
|
float width = 10f * edgeSizeMultiplier;
|
||
|
|
|
||
|
|
if (CloseTransition == transition)
|
||
|
|
width *= 1.5f;
|
||
|
|
|
||
|
|
Vector3[] edgePoints = GetTransitionPoints(transition);
|
||
|
|
|
||
|
|
int index = Context.Instance.FSMController.RuntimeFSMController.IndexOf(Context.Instance.RuntimeFSMController);
|
||
|
|
|
||
|
|
// 找到当前的过渡
|
||
|
|
|
||
|
|
FSMTransition current_transition = Context.Instance.FSMController.GetCurrentTransition(index);
|
||
|
|
if (current_transition == null) return;
|
||
|
|
if (!transition.Key.Equals(current_transition.Data.Key)) return;
|
||
|
|
|
||
|
|
if (current_change_transition != current_transition.Data)
|
||
|
|
{
|
||
|
|
current_change_transition = current_transition.Data;
|
||
|
|
current_change_transition_timer = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (current_change_transition.Key.Equals(current_transition.Data.Key) && current_change_transition_timer >= 1)
|
||
|
|
return;
|
||
|
|
|
||
|
|
FSMStateNodeData from = Context.Instance.RuntimeFSMController.GetStateNodeData(current_change_transition.fromStateName);
|
||
|
|
|
||
|
|
if (from == null || from.Parent != Context.Instance.LayerParent)
|
||
|
|
{
|
||
|
|
current_change_transition_timer = 1;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
current_change_transition_timer += Time.unscaledDeltaTime * 3;
|
||
|
|
|
||
|
|
if (edgePoints != null && edgePoints.Length >= 2)
|
||
|
|
{
|
||
|
|
Handles.color = selectedEdgeColor;
|
||
|
|
Handles.DrawAAPolyLine(width, edgePoints[0], Vector2.Lerp(edgePoints[0], edgePoints[1], current_change_transition_timer));
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DrawStateExitTransition()
|
||
|
|
{
|
||
|
|
if (Event.current.type != EventType.Repaint)
|
||
|
|
return;
|
||
|
|
|
||
|
|
if (!Application.isPlaying) return;
|
||
|
|
if (Context.Instance.FSMController == null)
|
||
|
|
return;
|
||
|
|
if (Context.Instance.FSMController.RuntimeFSMController == null)
|
||
|
|
return;
|
||
|
|
if (Context.Instance.RuntimeFSMController == null)
|
||
|
|
return;
|
||
|
|
|
||
|
|
float width = 10f * edgeSizeMultiplier;
|
||
|
|
|
||
|
|
int index = Context.Instance.FSMController.RuntimeFSMController.IndexOf(Context.Instance.RuntimeFSMController);
|
||
|
|
FSMStateNode stateNode = Context.Instance.FSMController.GetCurrentStateInfo(index, Context.Instance.LayerParent);
|
||
|
|
|
||
|
|
if (currentState != null && stateNode == null)
|
||
|
|
{
|
||
|
|
state_exiting = true;
|
||
|
|
exit_state_parent = currentState.data.Parent;
|
||
|
|
exit_state_name = currentState.data.name;
|
||
|
|
exit_state_timer = 0;
|
||
|
|
|
||
|
|
List<FSMStateNodeData> nodes = Context.Instance.GetCurrentShowStateNodeData();
|
||
|
|
|
||
|
|
if (nodes != null)
|
||
|
|
{
|
||
|
|
foreach (var item in nodes)
|
||
|
|
{
|
||
|
|
if (item.isBuildInState && item.buildInStateName.Equals(FSMConst.up))
|
||
|
|
{
|
||
|
|
exit_state_to_name = item.name;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
if (state_exiting)
|
||
|
|
{
|
||
|
|
exit_state_timer += Time.unscaledDeltaTime * 3;
|
||
|
|
|
||
|
|
Handles.color = selectedEdgeColor;
|
||
|
|
Vector3[] edgePoints = GetTransitionPoints(exit_state_name, exit_state_to_name);
|
||
|
|
|
||
|
|
if(edgePoints != null)
|
||
|
|
Handles.DrawAAPolyLine(width, edgePoints[0], Vector2.Lerp(edgePoints[0], edgePoints[1], exit_state_timer));
|
||
|
|
|
||
|
|
if (exit_state_timer >= 1 || !exit_state_parent.Equals(Context.Instance.LayerParent))
|
||
|
|
{
|
||
|
|
state_exiting = false;
|
||
|
|
exit_state_parent = null;
|
||
|
|
exit_state_name = null;
|
||
|
|
exit_state_to_name = null;
|
||
|
|
exit_state_timer = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
currentState = stateNode;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DelayCallSelection()
|
||
|
|
{
|
||
|
|
FSMTransitionInspectorHelper.Instance.Inspect(Context.Instance.RuntimeFSMController, Selection);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|