Unity3d obtains state machine transition parameters such as exitTime when running

Article directory

question

If you want to get some parameter settings during state transition, you can use the AnimatorController class. Because AnimatorController is in the command space of the editor class UnityEditor.Animations, it cannot be referenced at runtime. How to deal with it?
Insert image description here

solve

Because these transition parameters of the state machine will basically not change after running, and unity only provides very limited API modifications, you can use AnimatorController to read the required parameters before packaging and write them to files for use at runtime.

For example, get the following running time from Part1 -> Part2:

Insert image description here

using UnityEditor;
using UnityEditor.Animations;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

public class MeteorHammerSkillStateProcessor: Editor, IPreprocessBuildWithReport
{
    
    
    public int callbackOrder {
    
     get; }
    
    [MenuItem("AnimatorUtil/OutputMeteorSkillTime")]
    public static void WriteSkillClipTime()
    {
    
    
        var controller = AssetDatabase.LoadAssetAtPath<AnimatorController>("Assets/#C2_Animations/Play/Configure/Robot.controller");
        
        var _meteorSkillAnimatorStatePart1 = GetAnimationState(controller, "MeteorHammerSkill_Part1");
        var _meteorSkillAnimatorStatePart2 = GetAnimationState(controller, "MeteorHammerSkill_Part2");
        var _meteorSkillAnimatorStatePart3 = GetAnimationState(controller, "MeteorHammerSkill_Part3");
        var _meteorSkillAnimatorStatePart4 = GetAnimationState(controller, "MeteorHammerSkill_Part4");
        
        float time = 0f;
        
        if (_meteorSkillAnimatorStatePart1.speed <= 0
            || _meteorSkillAnimatorStatePart2.speed <= 0
            || _meteorSkillAnimatorStatePart3.speed <= 0
            || _meteorSkillAnimatorStatePart4.speed <= 0)
        {
    
    
            return;
        }
        
        // TODO : 这里未考虑到 animator.speed 的值(默认 state的speed 运行时也不改变),如果运行时,animator.speed != 1, 需要将
        // 获取的 clipTime 再除以 animator.speed    
        float clip1Time = GetClip("MeteorHammerSkill_Part1", controller).length / _meteorSkillAnimatorStatePart1.speed 
                          * (_meteorSkillAnimatorStatePart1.transitions[0].exitTime - 0);
        float clip2Time = GetClip("MeteorHammerSkill_Part2", controller).length / _meteorSkillAnimatorStatePart2.speed
                         * (_meteorSkillAnimatorStatePart2.transitions[0].exitTime - _meteorSkillAnimatorStatePart1.transitions[0].offset);
        float clip3Time = GetClip("MeteorHammerSkill_Part3", controller).length / _meteorSkillAnimatorStatePart3.speed
                         * (_meteorSkillAnimatorStatePart3.transitions[0].exitTime - _meteorSkillAnimatorStatePart2.transitions[0].offset);
        float clip4Time = GetClip("MeteorHammerSkill_Part4", controller).length / _meteorSkillAnimatorStatePart4.speed
                         * (_meteorSkillAnimatorStatePart4.transitions[0].exitTime - _meteorSkillAnimatorStatePart3.transitions[0].offset);
        
        Debug.Log($"{
      
      clip1Time}, {
      
      clip2Time}, {
      
      clip3Time}, {
      
      clip4Time}, total {
      
      clip1Time + clip2Time + clip3Time + clip4Time}");
    }
    
    public void OnPreprocessBuild(BuildReport report)
    {
    
    
        // AnimatorController 在运行时不可引用。可以在打包前,将需要的参数写入 ScriptableObject 中,在运行时读取。
#if WRITE_METEOR_SKILL_TIME
        WriteSkillClipTime();
#endif
    }
    
    public static AnimationClip GetClip(string clip, AnimatorController controller)
    {
    
    
        AnimationClip[] tAnimationClips = controller.animationClips;
        if (null == tAnimationClips || tAnimationClips.Length <= 0) return null;
        AnimationClip tAnimationClip;
        for (int tCounter = 0, tLen = tAnimationClips.Length; tCounter < tLen; tCounter++)
        {
    
    
            tAnimationClip = controller.animationClips[tCounter];
            if (null != tAnimationClip && tAnimationClip.name == clip)
                return tAnimationClip;
        }
        return null;
    }

    public static AnimatorState FindAnimatorState(AnimatorStateMachine stateMachine, string stateName)
    {
    
    
        for (int i = 0; i < stateMachine.states.Length; i++)
        {
    
    
            if (stateMachine.states[i].state.name.Equals(stateName))
            {
    
    
                return stateMachine.states[i].state;
            }
        }
    
        for (int i = 0; i < stateMachine.stateMachines.Length; i++)
        {
    
    
            var child = stateMachine.stateMachines[i];
            var state = FindAnimatorState(child.stateMachine, stateName);
    
            if (state)
            {
    
    
                return state;
            }
        }
    
        return null;
    }
    
    public static AnimatorState GetAnimationState(AnimatorController controller, string stateName)
    {
    
    
        AnimatorStateMachine stateMachine = controller.layers[0].stateMachine;
        
        return FindAnimatorState(stateMachine, stateName);
    }
}

Guess you like

Origin blog.csdn.net/WGYHAPPY/article/details/129820071