|
一、设计意图
使用Unity中的Timeline功能进行技能效果或者过场剧情开发的都知道,对于Timeline功能的扩展,凡是要扩展以下几个类:
- TrackAsset:轨道资源,用来创建片段和Playable混合器,提供序列化数据与Binding。
- PlayableAsset:片段资源,用来创建Playable以及提供序列化数据。
- PlayableBehaviour:逻辑行为,用来实现Playable具体的业务逻辑。
然而,在扩展过程中,会发现一些不便当的情况,最明显的就是PlayableBehaviour的回调函数,对于不熟悉Playable的开发者来说,需要必然的理解成本。为此,我对Timeline的布局进行了进一步的封装。
二、设计思路
对于TrackAsset和PlayableAsset来说,设计上但愿它们只是提供具体序列化数据,而屏蔽掉对于Playable的创建过程。而对于PlayableBehaviour来说,但愿它仅用于实现业务逻辑,同时提炼回调函数使其友好于普通的Unity游戏开发者,而不需要过多了解Playable的机制。
三、实现方式
1、PlayableBehaviour封装
先来对PlayableBehaviour进行封装,定义BaseBehaviour类,对原有的回调函数使用修饰符sealed,定义通用的回调函数(OnCreate,OnDestroy,OnStart,OnUpdate,OnStop),同时提供一些获取数据的接口(GetData,Time,Duration,Percent)。
全部代码如下:- namespace TimelineKit
- {
- using UnityEngine.Playables;
-
- public abstract class BaseBehaviour : PlayableBehaviour
- {
- private bool _started;
- private bool _played;
- private object _playerData;
- private Playable _playable = Playable.Null;
- private PlayableAsset _asset;
-
- public static Playable CreatePlayable<T>(PlayableGraph graph, PlayableAsset data) where T : BaseBehaviour, new()
- {
- var playable = ScriptPlayable<T>.Create(graph);
- T behaviour = playable.GetBehaviour();
- behaviour._asset = data;
- behaviour._playable = playable;
- return playable;
- }
- #region protected
- protected T GetData<T>() where T : PlayableAsset => _asset as T;
- protected float Time => (float)_playable.GetTime();
- protected float Duration => (float) _playable.GetDuration();
- protected float Percent => (float) (_playable.GetDuration().Equals(0) ? 0 : _playable.GetTime() / _playable.GetDuration());
- #endregion protected
- #region base
- protected virtual void OnCreate() { }
- protected virtual void OnDestroy() { }
- protected virtual void OnStart(object binding) { }
- protected virtual void OnUpdate(object binding, float deltaTime) { }
- protected virtual void OnStop(object binding) { }
- #endregion base
- #region sealed
- public sealed override void OnBehaviourPlay(Playable playable, FrameData info)
- {
- if (_played)
- return;
- _started = false;
- _played = true;
- }
- public sealed override void OnBehaviourPause(Playable playable, FrameData info)
- {
- if (!_played)
- return;
- OnStop(_playerData);
- _played = false;
- }
- public sealed override void OnPlayableCreate(Playable playable)
- {
- OnCreate();
- }
- public sealed override void OnPlayableDestroy(Playable playable)
- {
- OnDestroy();
- }
- public sealed override void OnGraphStart(Playable playable) { }
- public sealed override void OnGraphStop(Playable playable) { }
- public sealed override void PrepareData(Playable playable, FrameData info) { }
- public sealed override void PrepareFrame(Playable playable, FrameData info) { }
- public sealed override void ProcessFrame(Playable playable, FrameData info, object playerData)
- {
- if (!_played)
- return;
- if (!_started)
- {
- _started = true;
- _playerData = playerData;
- OnStart(_playerData);
- }
- OnUpdate(_playerData, info.deltaTime);
- }
- #endregion sealed
- }
- }
复制代码 2、PlayableAsset封装
为了和对应的PlayableBehaviour进行绑定,这里使用泛型对PlayableAsset进行封装,定义类型BaseClipAsset<T>,并实现了CreatePlayable的方式。因此担任此类型的子类只需要提供序列化数据即可。
全部代码如下:- namespace TimelineKit
- {
- using UnityEngine;
- using UnityEngine.Playables;
-
- public class BaseClipAsset<T> : PlayableAsset where T : BaseBehaviour, new()
- {
- public sealed override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
- {
- return BaseBehaviour.CreatePlayable<T>(graph, this);
- }
- }
- }
复制代码 3、TrackAsset封装
TrackAsset的封装和PlayableAsset的封装思路类似,也是对Create方式进行重载权限设置,定义了BaceTrackAsset和BaceTrackAsset<T>两种类型,此中使用泛型的类型可以用来创建Mixer混合器。
全部代码如下:- namespace TimelineKit
- {
- using UnityEngine;
- using UnityEngine.Playables;
- using UnityEngine.Timeline;
- public class BaseTrackAsset : TrackAsset
- {
- protected sealed override Playable CreatePlayable(PlayableGraph graph, GameObject gameObject, TimelineClip clip)
- {
- return base.CreatePlayable(graph, gameObject, clip);
- }
- public sealed override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
- {
- return base.CreateTrackMixer(graph, go, inputCount);
- }
- }
- public class BaseTrackAsset<T> : TrackAsset where T : BaseBehaviour, new()
- {
- protected sealed override Playable CreatePlayable(PlayableGraph graph, GameObject gameObject, TimelineClip clip)
- {
- return base.CreatePlayable(graph, gameObject, clip);
- }
- public sealed override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
- {
- var mixer = BaseBehaviour.CreatePlayable<T>(graph, this);
- mixer.SetInputCount(inputCount);
- return mixer;
- }
- }
- }
复制代码 四、使用案例
使用上面包装好的Timeline组件,可以很容易的对Timeline功能进行扩展,例如我们要实现一个Timeline控制光强的功能。
TrackAsset:- namespace TimelineKit
- {
- using UnityEngine;
- using UnityEngine.Timeline;
-
- [TrackColor(1f,1f,0f)]
- [TrackClipType(typeof(LightClipAsset))]
- [TrackBindingType(typeof(Light))]
- public class LightTrackAsset : BaseTrackAsset { }
- }
复制代码 BaseClipAsset实现:- namespace TimelineKit
- {
- public class LightClipAsset : BaseClipAsset<LightBehaviour>
- {
- public float StartIntensity;
- public float EndIntensity;
- }
- }
复制代码 BaseBehaviour实现:- namespace TimelineKit
- {
- using UnityEngine;
- public class LightBehaviour : BaseBehaviour
- {
- protected override void OnUpdate(object binding, float deltaTime)
- {
- if (binding is Light light)
- {
- var data = GetData<LightClipAsset>();
- light.intensity = Mathf.Lerp(data.StartIntensity,data.EndIntensity, Percent);
- }
- }
- }
- }
复制代码 做了个简易的场景,最终效果如下:
https://www.zhihu.com/video/1630530910461411328 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|