BehaviorTree / Editor / GraphElements / FlowEdge.cs
FlowEdge.cs
Raw
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Experimental.GraphView;
using System.Linq;
using UnityEditor;
using UnityEngine.UIElements;
using System;

namespace AI.BT
{
    public class FlowEdge : Edge
    {
        public bool EnableFlow
        {
            get => _isFlowEnabled;
            set
            {
                if(_isFlowEnabled != value)
                {
                    _isFlowEnabled = value;
                    if(_isFlowEnabled )
                    {
                        Add(m_FlowImage);
                    }
                    else
                    {
                        Remove(m_FlowImage);
                    }
                }
            }
        }
        private double m_PhaseStartTime;
        private double m_PhaseDuration;
        private float m_FlowSpeed = 150f;
        private float m_PhaseLength;
        private int m_PhaseIndex;
        private float _FlowSize = 6f;
        private float m_CurrentPhaseLength;
        private bool _isFlowEnabled;
        private readonly Image m_FlowImage;

        public float FlowSize
        {
            get => _FlowSize;
            set
            {
                _FlowSize = value;
                m_FlowImage.style.width = new Length(_FlowSize, LengthUnit.Pixel);
                m_FlowImage.style.height = new Length(_FlowSize, LengthUnit.Pixel);
            }
        }

        public FlowEdge()
        {
            var radius = new Length(FlowSize / 2, LengthUnit.Pixel);
            m_FlowImage = new Image()
            {
                name = "flow-image",
                style =
                {
                    width = new Length(FlowSize, LengthUnit.Pixel),
                    height = new Length(FlowSize, LengthUnit.Pixel),
                    borderTopLeftRadius = radius,
                    borderBottomLeftRadius = radius,
                    borderBottomRightRadius = radius,
                    borderTopRightRadius = radius,
                    backgroundColor = new StyleColor(Color.white)
                }
            };

            edgeControl.RegisterCallback<GeometryChangedEvent>(OnEdgeGeometryChanged);
        }

        private void OnEdgeGeometryChanged(GeometryChangedEvent evt)
        {
            m_PhaseIndex = 0;

            m_PhaseStartTime = EditorApplication.timeSinceStartup;
            m_CurrentPhaseLength = Vector2.Distance(edgeControl.controlPoints[m_PhaseIndex],
                edgeControl.controlPoints[m_PhaseIndex + 1]);
            m_PhaseDuration = m_PhaseLength / m_FlowSpeed;
        }


        public void UpdateFlow()
        { 
            var progress = (EditorApplication.timeSinceStartup - m_PhaseStartTime) / m_PhaseDuration;
            Vector3 start = edgeControl.controlPoints[m_PhaseIndex];
            Vector3 end = edgeControl.controlPoints[m_PhaseIndex + 1];
            var flowPos = Vector2.Lerp(start, end, (float)progress);

            m_FlowImage.transform.position = flowPos - Vector2.one * FlowSize / 2;

            if(progress >= 0.99999f)
            {
                m_PhaseIndex++;
                if(m_PhaseIndex >= edgeControl.controlPoints.Length - 1)
                {
                    m_PhaseIndex = 0;
                }

                m_PhaseStartTime = EditorApplication.timeSinceStartup;
                m_CurrentPhaseLength = Vector2.Distance(edgeControl.controlPoints[m_PhaseIndex],
                    edgeControl.controlPoints[m_PhaseIndex + 1]);
                m_PhaseDuration = m_CurrentPhaseLength / m_FlowSpeed;
            }
        }
    }
}