最近下载了Unity2017,有一个Timeline的新功能,编辑起来还是比较好上手的,不过如果是要进行动态绑定,就必须使用API,而API用起来步骤有点多,所以自己封装了一下
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Timeline;
using UnityEngine.Playables;
public class TimelineUnit
{
public string name;
public PlayableDirector director;
public PlayableAsset asset;
public Dictionary bindings;
public Dictionary> clips;
public void Init(string name, PlayableDirector director, PlayableAsset asset)
{
director.playableAsset = asset;
this.name = name;
this.director = director;
this.asset = asset;
bindings = new Dictionary();
clips = new Dictionary>();
foreach (var o in asset.outputs)
{
var trackName = o.streamName;
bindings.Add(trackName, o);
var track = o.sourceObject as TrackAsset;
var clipList = track.GetClips();
foreach (var c in clipList)
{
if (!clips.ContainsKey(trackName))
{
clips[trackName] = new Dictionary();
}
var name2Clips = clips[trackName];
if (!name2Clips.ContainsKey(c.displayName))
{
name2Clips.Add(c.displayName, c.asset as PlayableAsset);
}
}
}
}
public void SetBinding(string trackName, Object o)
{
director.SetGenericBinding(bindings[trackName].sourceObject, o);
}
public T GetTrack(string trackName) where T : TrackAsset
{
return bindings[trackName].sourceObject as T;
}
public T GetClip(string trackName, string clipName) where T : PlayableAsset
{
if (clips.ContainsKey(trackName))
{
var track = clips[trackName];
if (track.ContainsKey(clipName))
{
return track[clipName] as T;
}
else
{
Debug.LogError("GetClip Error, Track does not contain clip, trackName: " + trackName + ", clipName: " + clipName);
}
}
else
{
Debug.LogError("GetClip Error, Track does not contain clip, trackName: " + trackName + ", clipName: " + clipName);
}
return null;
}
public void Play()
{
director.Play();
}
}
using UnityEngine;
using UnityEngine.Playables;
public class TimelineHelper
{
public static TimelineUnit AddTimeline(GameObject go, string timelineName)
{
var unit = new TimelineUnit();
var director = go.GetComponent();
if (null == director)
director = go.AddComponent();
var asset = Resources.Load("TimelineRes/" + timelineName);
unit.Init(timelineName, director, asset);
return unit;
}
}
一个AnimationTrack,一个PlayableTrack,动画轨道不多讲,难点是PlayableTrack,这个是可以自定义逻辑的轨道
需要写两个类,一个继承PlayableAsset,一个继承PlayableBehaviour
using UnityEngine;
using UnityEngine.Playables;
public class MoveObjPlayableAsset : PlayableAsset
{
public GameObject go;
public Vector3 pos;
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
var bhv = new MoveObjPlayableBehaviour();
bhv.go = go;
bhv.pos = pos;
return ScriptPlayable.Create(graph, bhv);
}
}
using UnityEngine;
using UnityEngine.Playables;
public class MoveObjPlayableBehaviour : PlayableBehaviour
{
public GameObject go;
public Vector3 pos;
public override void OnGraphStart(Playable playable)
{
base.OnGraphStart(playable);
Debug.Log("OnGraphStart=======================");
}
public override void OnGraphStop(Playable playable)
{
base.OnGraphStop(playable);
Debug.Log("OnGraphStop=======================");
}
public override void OnBehaviourPlay(Playable playable, FrameData info)
{
base.OnBehaviourPlay(playable, info);
Debug.Log("OnBehaviourPlay=======================");
if (null != go)
{
go.transform.position = pos;
}
}
public override void OnBehaviourPause(Playable playable, FrameData info)
{
base.OnBehaviourPause(playable, info);
Debug.Log("OnBehaviourPause=======================");
if (null != go)
{
go.transform.position = Vector3.zero;
}
}
public override void OnBehaviourDelay(Playable playable, FrameData info)
{
base.OnBehaviourDelay(playable, info);
Debug.Log("OnBehaviourDelay=======================");
}
}
程序入口我放在一个runner的脚本里,挂在场景中的一个物体上
using UnityEngine;
public class Runner : MonoBehaviour
{
void Start()
{
var go = new GameObject("TimelineGo");
var unit = TimelineHelper.AddTimeline(go, "myTimeline");
unit.director.extrapolationMode = UnityEngine.Playables.DirectorWrapMode.Loop;
unit.SetBinding("at", go);
var p = unit.GetClip("myPlayable", "b");
p.go = gameObject;
unit.Play();
}
}
运行就可以看到有一个TimelineGo物体挂了Timeline运行了