Last active
February 7, 2021 09:49
-
-
Save dimmduh/033acb2dad9f9b4a6532534a2fe0a189 to your computer and use it in GitHub Desktop.
Timeline custom tracks - base classes. Still work in progress.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using UnityEngine; | |
using UnityEngine.Playables; | |
public abstract class BaseClip : PlayableAsset | |
{ | |
[HideInInspector, SerializeField] | |
[Bind(nameof(BasePlayableBehaviour.clipStartTime))] | |
public float startTime; | |
[HideInInspector, SerializeField] | |
[Bind(nameof(BasePlayableBehaviour.clipEndTime))] | |
public float endTime; | |
public ScriptPlayable<T> CreatePlayable<T>(PlayableGraph graph, params string[] bindFields) where T : BasePlayableBehaviour, new() | |
{ | |
return CreatePlayable<T>(graph, bindFields.ToDictionary(s => s, s => s)); | |
} | |
public ScriptPlayable<T> CreatePlayable<T>(PlayableGraph graph, Dictionary<string, string> bindFields = null) where T : BasePlayableBehaviour, new() | |
{ | |
var playable = ScriptPlayable<T>.Create(graph); | |
var behaviour = playable.GetBehaviour(); | |
if (bindFields == null) | |
bindFields = new Dictionary<string, string>(); | |
//read from attributes | |
var bindFieldsWithAttribute = GetType().GetFieldsWithAttribute<BindAttribute>(); | |
foreach (var fieldInfo in bindFieldsWithAttribute) | |
{ | |
var targetName = fieldInfo.GetCustomAttribute<BindAttribute>().targetFieldName.NullIfEmpty() ?? fieldInfo.Name; | |
bindFields.Add(fieldInfo.Name, targetName); | |
} | |
//fill values | |
foreach (var bindField in bindFields) | |
{ | |
var value = z_Utils.GetFieldValue(this, bindField.Key); | |
//resolve complex value | |
var valueType = value.GetType(); | |
if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(ExposedReference<>)) | |
{ | |
var method = value.GetType().GetMethod("Resolve"); | |
value = method.Invoke(value, new []{graph.GetResolver()}); | |
} | |
z_Utils.SetFieldValue(behaviour, bindField.Value, value); | |
} | |
return playable; | |
} | |
public virtual string GetDisplayName() | |
{ | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEditor.Timeline; | |
using UnityEngine.Timeline; | |
[CustomTimelineEditor(typeof(BaseClip))] | |
public class BaseClipEditor : ClipEditor | |
{ | |
public override void OnClipChanged(TimelineClip clip) | |
{ | |
base.OnClipChanged(clip); | |
var newDisplayName = ((BaseClip) clip.asset).GetDisplayName(); | |
if (newDisplayName != null) | |
clip.displayName = newDisplayName; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Playables; | |
public class BasePlayableBehaviour : PlayableBehaviour | |
{ | |
public float clipStartTime; | |
public float clipEndTime; | |
private static double timelineStopTime; | |
protected PlayableDirector GetDirector(Playable playable) | |
{ | |
return (PlayableDirector) playable.GetGraph().GetResolver(); | |
} | |
protected void SetDirectorSpeed(Playable playable, float value) | |
{ | |
GetDirector(playable).playableGraph.GetRootPlayable(0).SetSpeed(value); | |
} | |
public override void OnPlayableCreate(Playable playable) | |
{ | |
Debug.Log("OnPlayableCreate"); | |
} | |
public override void OnGraphStop(Playable playable) | |
{ | |
var director = GetDirector(playable); | |
if (director && director.state == PlayState.Paused) | |
{ | |
timelineStopTime = director.time; | |
OnTimelinePause(playable); | |
} | |
} | |
public override void OnGraphStart(Playable playable) | |
{ | |
var director = GetDirector(playable); | |
if (director && director.state == PlayState.Playing) | |
{ | |
if (director.time + 0.001 < timelineStopTime) | |
OnTimelineRestart(playable); | |
else | |
OnTimelineResume(playable); | |
} | |
} | |
public override void OnBehaviourPlay(Playable playable, FrameData info) | |
{ | |
var duration = playable.GetDuration(); | |
var time = playable.GetTime(); | |
var prevTime = time - info.deltaTime; | |
if (info.effectivePlayState == PlayState.Playing) | |
{ | |
if (prevTime <= 0) | |
OnClipStart(playable); | |
else if (time >= 0 && time < duration) | |
{ | |
OnClipResume(playable); | |
} | |
} | |
} | |
public override void OnBehaviourPause(Playable playable, FrameData info) | |
{ | |
var duration = playable.GetDuration(); | |
var count = playable.GetTime() + info.deltaTime; | |
if ((info.effectivePlayState == PlayState.Paused && count > duration) || playable.GetGraph().GetRootPlayable(0).IsDone()) | |
{ | |
OnClipFinish(playable); | |
} | |
var director = (PlayableDirector) playable.GetGraph().GetResolver(); | |
if (director && director.state == PlayState.Paused && info.effectivePlayState == PlayState.Playing && count < duration) | |
{ | |
OnClipPause(playable); | |
} | |
} | |
protected virtual void OnTimelinePause(Playable playable) | |
{ | |
Debug.Log("OnTimelinePause"); | |
} | |
protected virtual void OnTimelineResume(Playable playable) | |
{ | |
Debug.Log("OnTimelineResume"); | |
} | |
protected virtual void OnTimelineRestart(Playable playable) | |
{ | |
Debug.Log("OnTimelineRestart"); | |
} | |
protected virtual void OnClipResume(Playable playable) | |
{ | |
} | |
protected virtual void OnClipPause(Playable playable) | |
{ | |
} | |
protected virtual void OnClipStart(Playable playable) | |
{ | |
} | |
protected virtual void OnClipFinish(Playable playable) | |
{ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.Playables; | |
using UnityEngine.Timeline; | |
public class BaseTrackAsset : TrackAsset | |
{ | |
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) | |
{ | |
SetStartEndTimeToClips(); | |
return ScriptPlayable<TimeControlMixerBehaviour>.Create(graph, inputCount); | |
} | |
protected void SetStartEndTimeToClips() | |
{ | |
foreach (var clip in GetClips()) | |
{ | |
if (clip.asset is BaseClip customClip) | |
{ | |
//todo is it ok to cast to float? | |
customClip.startTime = (float) clip.start; | |
customClip.endTime = (float) clip.end; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace UnityEngine.Playables | |
{ | |
public class BindAttribute : Attribute | |
{ | |
public string targetFieldName; | |
public BindAttribute() | |
{ | |
} | |
public BindAttribute(string targetFieldName) | |
{ | |
this.targetFieldName = targetFieldName; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment