Timeline - PlayableBehavior轨道
实现CanvasGroup的补间动画
1) 轨道片段数据
using UnityEngine; using UnityEngine.Playables; [System.Serializable] public class CanvasGroupClip : PlayableAsset { [SerializeField] private ExposedReference<CanvasGroup> _target; [SerializeField] private float _startValue; [SerializeField] private float _endValue; public override Playable CreatePlayable(PlayableGraph graph, GameObject go) { var playable = ScriptPlayable<CanvasGroupBehaviour>.Create(graph); var canvasGroup = _target.Resolve(graph.GetResolver()); playable.GetBehaviour().Init(canvasGroup, _startValue, _endValue); return playable; } }
2) 轨道Clip逻辑
using UnityEngine; using UnityEngine.Playables; [System.Serializable] public class CanvasGroupBehaviour : PlayableBehaviour { public CanvasGroup _canvasGroup; public float _startValue; public float _endValue; public void Init(CanvasGroup canvasGroup, float startValue, float endValue) { _canvasGroup = canvasGroup; _startValue = startValue; _endValue = endValue; } public override void ProcessFrame(Playable playable, FrameData info, object playerData) { if (null == _canvasGroup) return; float progress = (float)(playable.GetTime() / playable.GetDuration()); float alpha = Mathf.Lerp(_startValue, _endValue, progress); _canvasGroup.alpha = alpha; Debug.Log($"CanvasGroupBehaviour: alpha: {alpha}"); } }
创建一个Playable轨道
PlayableGraph的可视化图形:
更加优雅的写法
上面的代码_startValue, _endValue需要在两个类中都写一遍,还得给他们赋值,下面的代码写法只需要在Behaviour中写一遍
using UnityEngine; using UnityEngine.Playables; [System.Serializable] public class CanvasGroupClip : PlayableAsset { public CanvasGroupBehaviour template = new CanvasGroupBehaviour(); public override Playable CreatePlayable(PlayableGraph graph, GameObject go) { var playable = ScriptPlayable<CanvasGroupBehaviour>.Create(graph, template); return playable; } }
#
using UnityEngine; using UnityEngine.Playables; [System.Serializable] public class CanvasGroupBehaviour : PlayableBehaviour { [SerializeField] private ExposedReference<CanvasGroup> _target; [SerializeField] public float _startValue; [SerializeField] public float _endValue; private CanvasGroup _canvasGroup; public override void OnGraphStart(Playable playable) { _canvasGroup = _target.Resolve(playable.GetGraph().GetResolver()); } public override void ProcessFrame(Playable playable, FrameData info, object playerData) { if (null == _canvasGroup) return; float progress = (float)(playable.GetTime() / playable.GetDuration()); float alpha = Mathf.Lerp(_startValue, _endValue, progress); _canvasGroup.alpha = alpha; Debug.Log($"CanvasGroupBehaviour: alpha: {alpha}"); } }
#
关于为什么对象绑定需要用到ExposedReference
一份timeline资源,可以用于多个不同的地方,只要绑定不同的对象就行了,而直接使用public CanvasGroup _target;是无法做到这样的功能的,
所以就引入了ExposedReference,他需要根据使用的地方解析出绑定对象
timeline资源的对象绑定关系没有直接保存在.playable资源中,而是保存在场景或预制体的PlayableDirector的Bindings下的。所以能做到:一份timeline资源,可以用于多个不同的地方
从ExposedReference解析绑定对象的方法
方法1
var bindingObj = _exposedRef.Resolve(playableGraph.GetResolver());
方法2:
var director = (PlayableDirector)playableGraph.GetResolver(); var obj = director.GetReferenceValue(_exposedRef.exposedName, out var isValid); if (isValid && null != obj) { var bindingObj = (Xxx)obj; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2021-12-27 shader Keyword无法关闭问题