.vs
Assets
Library
APIUpdater
Artifacts
Bee
BuildPlayerData
PackageCache
com.unity.collab-proxy@2.5.2
com.unity.editorcoroutines@1.0.0
com.unity.ext.nunit@1.0.6
com.unity.feature.development@1.0.1
com.unity.ide.rider@3.0.31
com.unity.ide.visualstudio@2.0.22
com.unity.ide.vscode@1.2.5
com.unity.modules.ai@1.0.0
com.unity.modules.androidjni@1.0.0
com.unity.modules.animation@1.0.0
com.unity.modules.assetbundle@1.0.0
com.unity.modules.audio@1.0.0
com.unity.modules.cloth@1.0.0
com.unity.modules.director@1.0.0
com.unity.modules.imageconversion@1.0.0
com.unity.modules.imgui@1.0.0
com.unity.modules.jsonserialize@1.0.0
com.unity.modules.particlesystem@1.0.0
com.unity.modules.physics2d@1.0.0
com.unity.modules.physics@1.0.0
com.unity.modules.screencapture@1.0.0
com.unity.modules.subsystems@1.0.0
com.unity.modules.terrain@1.0.0
com.unity.modules.terrainphysics@1.0.0
com.unity.modules.tilemap@1.0.0
com.unity.modules.ui@1.0.0
com.unity.modules.uielements@1.0.0
com.unity.modules.umbra@1.0.0
com.unity.modules.unityanalytics@1.0.0
com.unity.modules.unitywebrequest@1.0.0
com.unity.modules.unitywebrequestassetbundle@1.0.0
com.unity.modules.unitywebrequestaudio@1.0.0
com.unity.modules.unitywebrequesttexture@1.0.0
com.unity.modules.unitywebrequestwww@1.0.0
com.unity.modules.vehicles@1.0.0
com.unity.modules.video@1.0.0
com.unity.modules.vr@1.0.0
com.unity.modules.wind@1.0.0
com.unity.modules.xr@1.0.0
com.unity.performance.profile-analyzer@1.2.2
com.unity.settings-manager@2.0.1
com.unity.test-framework@1.1.33
com.unity.testtools.codecoverage@1.2.6
com.unity.textmeshpro@3.0.6
com.unity.timeline@1.7.6
DocCodeExamples
Documentation~
Editor
Runtime
Activation
Animation
AssetUpgrade
Attributes
Audio
Control
Evaluation
Events
Extensions
Playables
ActivationControlPlayable.cs
ActivationControlPlayable.cs.meta
BasicScriptPlayable.cs
BasicScriptPlayable.cs.meta
DirectorControlPlayable.cs
DirectorControlPlayable.cs.meta
ITimeControl.cs
ITimeControl.cs.meta
NotificationFlags.cs
NotificationFlags.cs.meta
ParticleControlPlayable.cs
ParticleControlPlayable.cs.meta
PrefabControlPlayable.cs
PrefabControlPlayable.cs.meta
TimeControlPlayable.cs
TimeControlPlayable.cs.meta
TimeNotificationBehaviour.cs
TimeNotificationBehaviour.cs.meta
Properties
Scripting
Utilities
Activation.meta
Animation.meta
AssetUpgrade.meta
Attributes.meta
Audio.meta
ClipCaps.cs
ClipCaps.cs.meta
Control.meta
DiscreteTime.cs
DiscreteTime.cs.meta
Evaluation.meta
Events.meta
Extensions.meta
GroupTrack.cs
GroupTrack.cs.meta
ILayerable.cs
ILayerable.cs.meta
Playables.meta
Properties.meta
Scripting.meta
Timeline.deprecated.cs
Timeline.deprecated.cs.meta
TimelineAsset.cs
TimelineAsset.cs.meta
TimelineAsset_CreateRemove.cs
TimelineAsset_CreateRemove.cs.meta
TimelineAttributes.cs
TimelineAttributes.cs.meta
TimelineClip.cs
TimelineClip.cs.meta
TimelinePlayable.cs
TimelinePlayable.cs.meta
TrackAsset.cs
TrackAsset.cs.meta
Unity.Timeline.asmdef
Unity.Timeline.asmdef.meta
Utilities.meta
Samples~
.signature
CHANGELOG.md
CHANGELOG.md.meta
DocCodeExamples.meta
Editor.meta
LICENSE.md
LICENSE.md.meta
README.md
README.md.meta
Runtime.meta
ValidationExceptions.json
ValidationExceptions.json.meta
package.json
package.json.meta
com.unity.ugui@1.0.0
com.unity.visualscripting@1.9.4
PackageManager
PlayModeViewStates
PlayerDataCache
ScriptAssemblies
Search
ShaderCache
SplashScreenCache
StateCache
UIElements
AnnotationManager
ArtifactDB
ArtifactDB-lock
BuildPlayer.prefs
BuildSettings.asset
EditorOnlyScriptingSettings.json
EditorOnlyVirtualTextureState.json
EditorSnapSettings.asset
EditorUserBuildSettings.asset
InspectorExpandedItems.asset
LastBuild.buildreport
LastSceneManagerSetup.txt
LibraryFormatVersion.txt
MonoManager.asset
SceneVisibilityState.asset
ScriptMapper
ShaderCache.db
SourceAssetDB
SourceAssetDB-lock
SpriteAtlasDatabase.asset
Style.catalog
expandedItems
ilpp.pid
Logs
Packages
ProjectSettings
UserSettings
obj
.vsconfig
Assembly-CSharp.Player.csproj
Assembly-CSharp.csproj
TM1.sln
Unity.CollabProxy.Editor.csproj
Unity.EditorCoroutines.Editor.csproj
Unity.Performance.Profile-Analyzer.Editor.csproj
Unity.PlasticSCM.Editor.csproj
Unity.Rider.Editor.csproj
Unity.Settings.Editor.csproj
Unity.TestTools.CodeCoverage.Editor.OpenCover.Model.csproj
Unity.TestTools.CodeCoverage.Editor.OpenCover.Mono.Reflection.csproj
Unity.TestTools.CodeCoverage.Editor.csproj
Unity.TextMeshPro.Editor.csproj
Unity.TextMeshPro.Player.csproj
Unity.TextMeshPro.csproj
Unity.Timeline.Editor.csproj
Unity.Timeline.Player.csproj
Unity.Timeline.csproj
Unity.VSCode.Editor.csproj
Unity.VisualScripting.Core.Editor.csproj
Unity.VisualScripting.Core.Player.csproj
Unity.VisualScripting.Core.csproj
Unity.VisualScripting.Flow.Editor.csproj
Unity.VisualScripting.Flow.Player.csproj
Unity.VisualScripting.Flow.csproj
Unity.VisualScripting.SettingsProvider.Editor.csproj
Unity.VisualScripting.Shared.Editor.csproj
Unity.VisualScripting.State.Editor.csproj
Unity.VisualScripting.State.Player.csproj
Unity.VisualScripting.State.csproj
Unity.VisualStudio.Editor.csproj
UnityEditor.TestRunner.csproj
UnityEditor.UI.csproj
UnityEngine.TestRunner.Player.csproj
UnityEngine.TestRunner.csproj
UnityEngine.UI.Player.csproj
UnityEngine.UI.csproj
252 lines
9.8 KiB
C#
252 lines
9.8 KiB
C#
![]() |
using System;
|
||
|
using UnityEngine;
|
||
|
using UnityEngine.Playables;
|
||
|
|
||
|
namespace UnityEngine.Timeline
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Playable Behaviour used to control a PlayableDirector.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// This playable is used to control other PlayableDirector components from a Timeline sequence.
|
||
|
/// </remarks>
|
||
|
public class DirectorControlPlayable : PlayableBehaviour
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// The PlayableDirector being controlled by this PlayableBehaviour
|
||
|
/// </summary>
|
||
|
public PlayableDirector director;
|
||
|
|
||
|
bool m_SyncTime = false;
|
||
|
double m_AssetDuration = double.MaxValue;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a Playable with a DirectorControlPlayable attached
|
||
|
/// </summary>
|
||
|
/// <param name="graph">The graph to inject the playable into</param>
|
||
|
/// <param name="director">The director to control</param>
|
||
|
/// <returns>Returns a Playable with a DirectorControlPlayable attached</returns>
|
||
|
public static ScriptPlayable<DirectorControlPlayable> Create(PlayableGraph graph, PlayableDirector director)
|
||
|
{
|
||
|
if (director == null)
|
||
|
return ScriptPlayable<DirectorControlPlayable>.Null;
|
||
|
|
||
|
var handle = ScriptPlayable<DirectorControlPlayable>.Create(graph);
|
||
|
handle.GetBehaviour().director = director;
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(director))
|
||
|
UnityEditor.PrefabUtility.prefabInstanceUpdated += handle.GetBehaviour().OnPrefabUpdated;
|
||
|
#endif
|
||
|
|
||
|
return handle;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This function is called when this PlayableBehaviour is destroyed.
|
||
|
/// </summary>
|
||
|
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||
|
public override void OnPlayableDestroy(Playable playable)
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
if (!Application.isPlaying)
|
||
|
UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated;
|
||
|
#endif
|
||
|
if (director != null && director.playableAsset != null)
|
||
|
director.Stop();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This function is called during the PrepareFrame phase of the PlayableGraph.
|
||
|
/// </summary>
|
||
|
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||
|
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
|
||
|
public override void PrepareFrame(Playable playable, FrameData info)
|
||
|
{
|
||
|
if (director == null || !director.isActiveAndEnabled || director.playableAsset == null)
|
||
|
return;
|
||
|
|
||
|
// resync the time on an evaluate or a time jump (caused by loops, or some setTime calls)
|
||
|
m_SyncTime |= (info.evaluationType == FrameData.EvaluationType.Evaluate) ||
|
||
|
DetectDiscontinuity(playable, info);
|
||
|
|
||
|
SyncSpeed(info.effectiveSpeed);
|
||
|
SyncStart(playable.GetGraph(), playable.GetTime());
|
||
|
#if !UNITY_2021_2_OR_NEWER
|
||
|
SyncStop(playable.GetGraph(), playable.GetTime());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This function is called when the Playable play state is changed to Playables.PlayState.Playing.
|
||
|
/// </summary>
|
||
|
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||
|
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
|
||
|
public override void OnBehaviourPlay(Playable playable, FrameData info)
|
||
|
{
|
||
|
m_SyncTime = true;
|
||
|
|
||
|
if (director != null && director.playableAsset != null)
|
||
|
m_AssetDuration = director.playableAsset.duration;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This function is called when the Playable play state is changed to PlayState.Paused.
|
||
|
/// </summary>
|
||
|
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||
|
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
|
||
|
public override void OnBehaviourPause(Playable playable, FrameData info)
|
||
|
{
|
||
|
if (director != null && director.playableAsset != null)
|
||
|
{
|
||
|
if (info.effectivePlayState == PlayState.Playing) // graph was paused
|
||
|
director.Pause();
|
||
|
else
|
||
|
director.Stop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This function is called during the ProcessFrame phase of the PlayableGraph.
|
||
|
/// </summary>
|
||
|
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||
|
/// <param name="info">A FrameData structure that contains information about the current frame context.</param>
|
||
|
/// <param name="playerData">unused</param>
|
||
|
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
|
||
|
{
|
||
|
if (director == null || !director.isActiveAndEnabled || director.playableAsset == null)
|
||
|
return;
|
||
|
|
||
|
if (m_SyncTime || DetectOutOfSync(playable))
|
||
|
{
|
||
|
UpdateTime(playable);
|
||
|
if (director.playableGraph.IsValid())
|
||
|
{
|
||
|
director.playableGraph.Evaluate();
|
||
|
#if TIMELINE_FRAMEACCURATE
|
||
|
director.playableGraph.SynchronizeEvaluation(playable.GetGraph());
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
director.Evaluate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_SyncTime = false;
|
||
|
#if UNITY_2021_2_OR_NEWER
|
||
|
SyncStop(playable.GetGraph(), playable.GetTime());
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#if UNITY_EDITOR
|
||
|
void OnPrefabUpdated(GameObject go)
|
||
|
{
|
||
|
// When the prefab asset is updated, we rebuild the graph to reflect the changes in editor
|
||
|
if (UnityEditor.PrefabUtility.GetRootGameObject(director) == go)
|
||
|
director.RebuildGraph();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void SyncSpeed(double speed)
|
||
|
{
|
||
|
if (director.playableGraph.IsValid())
|
||
|
{
|
||
|
int roots = director.playableGraph.GetRootPlayableCount();
|
||
|
for (int i = 0; i < roots; i++)
|
||
|
{
|
||
|
var rootPlayable = director.playableGraph.GetRootPlayable(i);
|
||
|
if (rootPlayable.IsValid())
|
||
|
{
|
||
|
rootPlayable.SetSpeed(speed);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SyncStart(PlayableGraph graph, double time)
|
||
|
{
|
||
|
if (director.state == PlayState.Playing
|
||
|
|| !graph.IsPlaying()
|
||
|
|| (director.extrapolationMode == DirectorWrapMode.None && time > m_AssetDuration))
|
||
|
return;
|
||
|
#if TIMELINE_FRAMEACCURATE
|
||
|
if (graph.IsMatchFrameRateEnabled())
|
||
|
director.Play(graph.GetFrameRate());
|
||
|
else
|
||
|
director.Play();
|
||
|
#else
|
||
|
director.Play();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void SyncStop(PlayableGraph graph, double time)
|
||
|
{
|
||
|
if (director.state == PlayState.Paused
|
||
|
|| (graph.IsPlaying() && (director.extrapolationMode != DirectorWrapMode.None || time < m_AssetDuration)))
|
||
|
return;
|
||
|
if (director.state == PlayState.Paused)
|
||
|
return;
|
||
|
|
||
|
bool expectedFinished = director.extrapolationMode == DirectorWrapMode.None && time > m_AssetDuration;
|
||
|
if (expectedFinished || !graph.IsPlaying())
|
||
|
director.Pause();
|
||
|
}
|
||
|
|
||
|
bool DetectDiscontinuity(Playable playable, FrameData info)
|
||
|
{
|
||
|
return Math.Abs(playable.GetTime() - playable.GetPreviousTime() - info.m_DeltaTime * info.m_EffectiveSpeed) > DiscreteTime.tickValue;
|
||
|
}
|
||
|
|
||
|
bool DetectOutOfSync(Playable playable)
|
||
|
{
|
||
|
double expectedTime = playable.GetTime();
|
||
|
if (playable.GetTime() >= m_AssetDuration)
|
||
|
{
|
||
|
switch (director.extrapolationMode)
|
||
|
{
|
||
|
case DirectorWrapMode.None:
|
||
|
expectedTime = m_AssetDuration;
|
||
|
break;
|
||
|
case DirectorWrapMode.Hold:
|
||
|
expectedTime = m_AssetDuration;
|
||
|
break;
|
||
|
case DirectorWrapMode.Loop:
|
||
|
expectedTime %= m_AssetDuration;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!Mathf.Approximately((float)expectedTime, (float)director.time))
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
double lastDelta = playable.GetTime() - playable.GetPreviousTime();
|
||
|
if (UnityEditor.Unsupported.IsDeveloperBuild())
|
||
|
Debug.LogWarningFormat("Internal Warning - Control track desync detected on {2} ({0:F10} vs {1:F10} with delta {3:F10}). Time will be resynchronized. Known to happen with nested control tracks", playable.GetTime(), director.time, director.name, lastDelta);
|
||
|
#endif
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// We need to handle loop modes explicitly since we are setting the time directly
|
||
|
void UpdateTime(Playable playable)
|
||
|
{
|
||
|
double duration = Math.Max(0.1, director.playableAsset.duration);
|
||
|
switch (director.extrapolationMode)
|
||
|
{
|
||
|
case DirectorWrapMode.Hold:
|
||
|
director.time = Math.Min(duration, Math.Max(0, playable.GetTime()));
|
||
|
break;
|
||
|
case DirectorWrapMode.Loop:
|
||
|
director.time = Math.Max(0, playable.GetTime() % duration);
|
||
|
break;
|
||
|
case DirectorWrapMode.None:
|
||
|
director.time = Math.Min(duration, Math.Max(0, playable.GetTime()));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|