TimeLine的拓展使用

前言

在使用TimeLine的过程中,需要一个在其clip开始或者结束仅执行一次自定义方法的功能。

解决方案

  • 首先引用【Default Playables】的插件来方便自定义事件的开发
  • 再在创建的自定义脚本中绑定指定事件即可

感谢B站用户【小小故事汇】TimeLine的进阶玩法,用Playable自定义轨道_哔哩哔哩_bilibili

  • 下面解决仅在clip的开始或者clip的尾部执行自定义方法
    • 跟着步骤创建完自定义轨道脚本后找到相应的【Behaviour】脚本例如【DeductiveStoryBehaviour】向该脚本添加事件
      [Serializable]
      public class DeductiveStoryBehaviour : PlayableBehaviour
      {
          // 这里的UnityEvent也可以改为Action, 使用UnityEvent是为了方便看
      
          public UnityEvent OnStart;
          public UnityEvent OnFrame;
          public UnityEvent OnEnd;
      }
    • 找到相应的【MixerBehaviour】脚本例如的【DeductiveStoryMixerBehaviour】修改内容
          private float[] weights;
          private bool initWeight = false;
      
      public override void PrepareFrame(Playable playable, FrameData info)
          {
              base.PrepareFrame(playable, info);
              int inputCount = playable.GetInputCount();
      
              if (!initWeight && inputCount > 0)
              {
                  weights = new float[inputCount];
                  initWeight = true;
              }
              for (int i = 0; i < inputCount; i++)
              {
                  float inputWeight = playable.GetInputWeight(i);
                  ScriptPlayable<DeductiveStoryBehaviour> inputPlayable = (ScriptPlayable<DeductiveStoryBehaviour>)playable.GetInput(i);
                  DeductiveStoryBehaviour input = inputPlayable.GetBehaviour();
      
                  if (weights[i] == 0 && inputWeight > 0)
                  {
                      input.OnStart?.Invoke();
                  }
      
                  input.OnFrame?.Invoke();
      
                  if (weights[i] > 0 && inputWeight == 0)
                  {
                      input.OnEnd?.Invoke();
                  }
      
      
                  weights[i] = inputWeight;
              }
          }

测试

在TimeLine中创建自定义轨道并创建Clip后在监视版中即可查看到结果,并执行

对Director的播放、暂停、恢复,停止的拓展

这里我先是创建了一个名为【TimeLineDirector】的脚本,脚本中仅有对TimeLine的基本操作

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;

/****************************************************
	文件:TimeLineDirector.cs
	作者:GTY
	日期:2024/4/27 15:24:27
	功能:TimeLine
*****************************************************/

public enum TimeLineDirectorEventType
{
    Play,
    Stop,
    Pause,
    Resume,

}
public class TimeLineDirector : MonoBehaviour
{
    public PlayableDirector playableDirector;
    public Action onFinish;
    public Action<PlayableDirector> onPlayed;
    public Action<PlayableDirector> onStopped;
    public Action<PlayableDirector> onPaused;

    public float GetDuration { get => (float)playableDirector.duration; }
    public float Time { get => (float)playableDirector.time; set { playableDirector.time = value; } }

    private void Awake()
    {
        if (playableDirector == null) playableDirector = GetComponent<PlayableDirector>();

        playableDirector.played += onPlayed;
        playableDirector.stopped += onStopped;
        playableDirector.paused += onPaused;
    }


    public float Play()
    {
        playableDirector.Play();
        float duration = (float)playableDirector.duration;
        Invoke("FinishInvoke", duration);
        return duration;
    }
    public float Play(PlayableAsset playableAsset)
    {
        playableDirector.Play(playableAsset);
        float duration = (float)playableDirector.duration;
        Invoke("FinishInvoke", duration);
        return duration;
    }

    public void Stop()
    {
        playableDirector.Stop();
    }

    public void Pause()
    {
        playableDirector.Pause();
    }

    public void Resume()
    {
        // 暂停后才能用
        playableDirector.Resume();
    }

    void FinishInvoke()
    {
        Debug.Log("TimeLine播放结束");
        onFinish?.Invoke();
    }
}

接着我创建了一个名为【TimeLineDirectorCtrl】的自定义轨道

在【Behaviour】中添加

[Serializable]
public class TimeLineDirectorCtrlBehaviour : PlayableBehaviour
{
    public TimeLineDirectorEventType timeLineDirectorEventType;
}

在【MixerBehaviour】中获取到绑定的【TimeLineDirector】并添加如下代码

public class TimeLineDirectorCtrlMixerBehaviour : PlayableBehaviour
{

    private float[] weights;
    private bool initWeight = false;

    void BindingEvent(TimeLineDirector trackBinding, TimeLineDirectorCtrlBehaviour behaviour)
    {
        switch (behaviour.timeLineDirectorEventType)
        {
            case TimeLineDirectorEventType.Play:
                trackBinding.Play();
                break;
            case TimeLineDirectorEventType.Pause:
                trackBinding.Pause();
                break;
            case TimeLineDirectorEventType.Resume:
                trackBinding.Resume();
                break;
            case TimeLineDirectorEventType.Stop:
                trackBinding.Stop();
                break;
        }
    }
    // NOTE: This function is called at runtime and edit time.  Keep that in mind when setting the values of properties.
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        TimeLineDirector trackBinding = playerData as TimeLineDirector;

        if (!trackBinding)
            return;

        int inputCount = playable.GetInputCount();

        if (!initWeight && inputCount > 0)
        {
            weights = new float[inputCount];
            initWeight = true;
        }

        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);
            ScriptPlayable<TimeLineDirectorCtrlBehaviour> inputPlayable = (ScriptPlayable<TimeLineDirectorCtrlBehaviour>)playable.GetInput(i);
            TimeLineDirectorCtrlBehaviour input = inputPlayable.GetBehaviour();

            if (weights[i] == 0 && inputWeight > 0)
            {
                // input.OnStart?.Invoke();
                BindingEvent(trackBinding, input);
            }

            // input.OnFrame?.Invoke();

            // if (weights[i] > 0 && inputWeight == 0)
            // {
            //     input.OnEnd?.Invoke();
            // }


            weights[i] = inputWeight;
        }
    }
}

这样就会在该Clip一开始或者结束时执行播放、停止、暂停,恢复等操作

结尾

 这个功能应该能很好的解决默认Clip一直执行的问题(确信)。

猜你喜欢

转载自blog.csdn.net/ViYeye/article/details/138803136