关于星空制作的动作编辑器拓展

发布于 2021-08-17  168 次阅读


因为在制作动作的时候,希望能看到一些特效的配合,实时表现,所以诞生了这篇文章。
因为编辑器原本并不支持在编辑模式下,预览执行,添加的ActionNode,所以我自己拓展了一下,以便于开发。
首先找到ActionConfigAttribute脚本,添加字段,用来标识,这个ActionNode会在编辑器下运行

然后在ActionMachineHelper脚本下对GetActionHandler进行修改,在寻找ActionNode时,标识是否只获取在编辑器下运行的Node

最后找到ActionEditorSetting,添加UpdateExecuteInEditorActionNode方法,添加在这里
代码我就不进行讲解了,自己看吧

private void UpdateExecuteInEditorActionNode()
        {
            foreach (var item in currentState.actions)
            {
                int beginFrame = 0;
                int endFrame = currentState.frames.Count;
                var action = ActionMachineHelper.GetActionHandler(item.GetType(), true);
                if (null != action)
                {
                    if (item is IHoldFrames holdFrames)
                    {
                        beginFrame = holdFrames.GetBeginFrame();
                        endFrame = holdFrames.GetEndFrame();
                    }

                    ActionNode actionNode = ActionMachineHelper.CreateActionNode();
                    var actionMachineController = actionMachineTest.GetComponent<ActionMachineController>();
                    actionMachineController.actionMachine = new ActionMachine();
                    actionMachineController.actionMachine.controller = actionMachineController;
                    actionNode.actionMachine = actionMachineController.actionMachine;
                    actionNode.config = item;
                    actionNode.SetUpdateCnt(frameSelectIndex - beginFrame);
                    actionNode.handler = action;

                    if (frameSelectIndex >= beginFrame
                        && frameSelectIndex <= endFrame)
                    {
                        if (beginFrame == frameSelectIndex)
                        {
                            actionNode.handler.Enter(actionNode);
                        }
                        actionNode.handler.Update(actionNode, setting.frameRate);
                        if (endFrame == frameSelectIndex)
                        {
                            actionNode.handler.Exit(actionNode);
                        }
                    }
                }
            }
        }

最后应该会有一个报错,记得加个参数设置为false就好了

actionNode.handler = ActionMachineHelper.GetActionHandler(action.GetType(), false);

现在应该就能在编辑模式下,执行我们自己添加的Node了,需要注意,Node中的Data我没有进行保存,有需要就自己改把,所以如果有需要的话编辑器下的代码要做区分。

这里再顺手贴一个基于帧变化的粒子控制节点,和动画节点,因为贴图制作时会特效不会和动画绑定在一起,而且当攻速发生变化的时候,动画和粒子也需要统一进行缩放变化,报错的话,自己删了改成常量就行了,根据自己项目需求来。

粒子

using TFramework.ECS.MonoBehaviours;
using TFramework.Extensions;
using UnityEngine;
using XMLib.AM;

[System.Serializable]
[ActionConfig(typeof(ParticleSystemAction), true)]
public class ParticleSystemActionConfig : HoldFrames
{
    public string ParticleName;
}

public class ParticleSystemAction : IActionHandler
{
    public class Data
    {
        public ParticleSystem ParticleSystem;
        public ActionMachineComponent ActionMachineComponent;
    }

    private ParticleSystem GetParticleSystem(ActionNode node)
    {
        ParticleSystem particleSystem;
        Data data = node.data as Data;
        if (null != data
        && null != data.ParticleSystem)
        {
            particleSystem = data.ParticleSystem;
        }
        else
        {
            ActionMachineController controller = (ActionMachineController)node.actionMachine.controller;
            var config = node.config as ParticleSystemActionConfig;
            particleSystem = controller.modelRoot.Find(config.ParticleName).GetComponent<ParticleSystem>();
            if (null != data)
            {
                data.ParticleSystem = particleSystem;
            }
        }
        return particleSystem;
    }

    private ActionMachineComponent GetActionMachineComponent(ActionNode node)
    {
        Data data = node.data as Data;
        if (null != data
        && null != data.ActionMachineComponent)
        {
            return data.ActionMachineComponent;
        }
        else
        {
            ActionMachineController controller = (ActionMachineController)node.actionMachine.controller;
            var entityView = controller.modelRoot.GetComponent<EntityView>();
            if (null != entityView)
            {
                if (null != data)
                {
                    data.ActionMachineComponent = entityView.Entity.GetComponent<ActionMachineComponent>();
                    return data.ActionMachineComponent;
                }
            }
            return null;
        }
    }

    public void Enter(ActionNode node)
    {
        Data data = new Data();
        node.data = data;
        var particleSystem = GetParticleSystem(node);
        if (null != particleSystem)
        {
            var mainModule = particleSystem.main;
            particleSystem.gameObject.SetActive(true);
            particleSystem.Play();
            particleSystem.Simulate(0, true, true);
            particleSystem.time = 0;
            var actionMachineComponent = GetActionMachineComponent(node);
            mainModule.simulationSpeed = null == actionMachineComponent ? 1 : actionMachineComponent.Speed;
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }

    public void Update(ActionNode node, float deltaTime)
    {
        var particleSystem = GetParticleSystem(node);
        if (null != particleSystem)
        {
            var mainModule = particleSystem.main;
            bool rest = particleSystem.time >= mainModule.startLifetime.constantMax ? true : false;
            particleSystem.Simulate(deltaTime * node.updateCnt, true, rest);
            var actionMachineComponent = GetActionMachineComponent(node);
            mainModule.simulationSpeed = null == actionMachineComponent ? 1 : actionMachineComponent.Speed;
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }

    public void Exit(ActionNode node)
    {
        var particleSystem = GetParticleSystem(node);
        if (null != particleSystem)
        {
            var mainModule = particleSystem.main;
            mainModule.simulationSpeed = 1;
            particleSystem.Stop();
            particleSystem.gameObject.SetActive(false);
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }
}

动画

using System;
using TFramework.ECS.MonoBehaviours;
using TFramework.Extensions;
using UnityEngine;
using XMLib.AM;

[System.Serializable]
[ActionConfig(typeof(EffectAnimatorAction), true)]
public class EffectAnimatorConfig : HoldFrames
{
    public string PreafabName;
    public string EffectName;
    public Vector3 StartPosition;
}

public class EffectAnimatorAction : IActionHandler
{
    public class Data
    {
        public Animator Animator;
        public ActionMachineComponent ActionMachineComponent;
    }

    private Animator GetAnimatorController(ActionNode node)
    {
        Data data = node.data as Data;
        if (null != data
        && null != data.Animator)
        {
            return data.Animator;
        }
        else
        {
            ActionMachineController controller = (ActionMachineController)node.actionMachine.controller;
            var config = node.config as EffectAnimatorConfig;
            var animator = controller.modelRoot.Find(config.PreafabName).GetComponent<Animator>();
            if (null != data)
            {
                data.Animator = animator;
            }
            return animator;
        }
    }

    private ActionMachineComponent GetActionMachineComponent(ActionNode node)
    {
        Data data = node.data as Data;
        if (null != data
        && null != data.ActionMachineComponent)
        {
            return data.ActionMachineComponent;
        }
        else
        {
            ActionMachineController controller = (ActionMachineController)node.actionMachine.controller;
            var entityView = controller.modelRoot.GetComponent<EntityView>();
            if (null != entityView)
            {
                if (null != data)
                {
                    data.ActionMachineComponent = entityView.Entity.GetComponent<ActionMachineComponent>();
                    return data.ActionMachineComponent;
                }
            }
            return null;
        }
    }

    public void Enter(ActionNode node)
    {
        Data data = new Data();
        node.data = data;
        var animator = GetAnimatorController(node);
        if (null != animator)
        {
            var config = node.config as EffectAnimatorConfig;
            animator.transform.localPosition = config.StartPosition;
            animator.gameObject.SetActive(true);
            var actionMachineComponent = GetActionMachineComponent(node);
            animator.speed = null == actionMachineComponent ? 1 : actionMachineComponent.Speed;
            animator.Play(config.EffectName, 0, 0);
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }

    public void Update(ActionNode node, float deltaTime)
    {
        var animator = GetAnimatorController(node);
        if (null != animator)
        {
            var actionMachineComponent = GetActionMachineComponent(node);
            animator.speed = null == actionMachineComponent ? 1 : actionMachineComponent.Speed;
            if (Application.isPlaying)
            {
                animator.Update(deltaTime);
            }
            else
            {
                float time = deltaTime * node.updateCnt;
                var config = node.config as EffectAnimatorConfig;
                GetCurrentAnimationClip(animator, config.EffectName).SampleAnimation(animator.gameObject, time);
            }
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }

    public AnimationClip GetCurrentAnimationClip(Animator animator, string state)
    {
        return Array.Find(animator.runtimeAnimatorController.animationClips, t => string.Compare(state, t.name) == 0);
    }

    public void Exit(ActionNode node)
    {
        var animator = GetAnimatorController(node);
        if (null != animator)
        {
            animator.speed = 1;
            animator.gameObject.SetActive(false);
#if UNITY_EDITOR
            UnityEditor.SceneView.RepaintAll();
#endif
        }
    }
}

最后贴一下编辑器地址


学无止境,知行合一,学以致用,举一反三。