mirror of
https://github.com/Project-Redacted/Highscores-Server.git
synced 2025-05-20 10:24:59 +00:00
Add example Unity Project
This commit is contained in:
parent
fda7ff28dd
commit
e3acdb9d6b
7122 changed files with 505543 additions and 2 deletions
|
@ -0,0 +1,140 @@
|
|||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Playable that controls the active state of a GameObject.
|
||||
/// </summary>
|
||||
public class ActivationControlPlayable : PlayableBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The state of a GameObject's activeness when a PlayableGraph stops.
|
||||
/// </summary>
|
||||
public enum PostPlaybackState
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the GameObject to active when the PlayableGraph stops.
|
||||
/// </summary>
|
||||
Active,
|
||||
|
||||
/// <summary>
|
||||
/// Set the GameObject to inactive when the [[PlayableGraph]] stops.
|
||||
/// </summary>
|
||||
Inactive,
|
||||
|
||||
/// <summary>
|
||||
/// Revert the GameObject to the active state it was before the [[PlayableGraph]] started.
|
||||
/// </summary>
|
||||
Revert
|
||||
}
|
||||
|
||||
enum InitialState
|
||||
{
|
||||
Unset,
|
||||
Active,
|
||||
Inactive
|
||||
}
|
||||
|
||||
public GameObject gameObject = null;
|
||||
public PostPlaybackState postPlayback = PostPlaybackState.Revert;
|
||||
InitialState m_InitialState;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a ScriptPlayable with an ActivationControlPlayable behaviour attached
|
||||
/// </summary>
|
||||
/// <param name="graph">PlayableGraph that will own the playable</param>
|
||||
/// <param name="gameObject">The GameObject that triggered the graph build</param>
|
||||
/// <param name="postPlaybackState">The state to leave the gameObject after the graph is stopped</param>
|
||||
/// <returns>Returns a playable that controls activation of a game object</returns>
|
||||
public static ScriptPlayable<ActivationControlPlayable> Create(PlayableGraph graph, GameObject gameObject, ActivationControlPlayable.PostPlaybackState postPlaybackState)
|
||||
{
|
||||
if (gameObject == null)
|
||||
return ScriptPlayable<ActivationControlPlayable>.Null;
|
||||
|
||||
var handle = ScriptPlayable<ActivationControlPlayable>.Create(graph);
|
||||
var playable = handle.GetBehaviour();
|
||||
playable.gameObject = gameObject;
|
||||
playable.postPlayback = postPlaybackState;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the Playable play state is changed to Playables.PlayState.Playing.
|
||||
/// </summary>
|
||||
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||||
/// <param name="info">The information about this frame</param>
|
||||
public override void OnBehaviourPlay(Playable playable, FrameData info)
|
||||
{
|
||||
if (gameObject == null)
|
||||
return;
|
||||
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
/// <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">The information about this frame</param>
|
||||
public override void OnBehaviourPause(Playable playable, FrameData info)
|
||||
{
|
||||
// OnBehaviourPause can be called if the graph is stopped for a variety of reasons
|
||||
// the effectivePlayState will test if the pause is due to the clip being out of bounds
|
||||
if (gameObject != null && info.effectivePlayState == PlayState.Paused)
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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="userData">unused</param>
|
||||
public override void ProcessFrame(Playable playable, FrameData info, object userData)
|
||||
{
|
||||
if (gameObject != null)// && !gameObject.activeSelf)
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the PlayableGraph that owns this PlayableBehaviour starts.
|
||||
/// </summary>
|
||||
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||||
public override void OnGraphStart(Playable playable)
|
||||
{
|
||||
if (gameObject != null)
|
||||
{
|
||||
if (m_InitialState == InitialState.Unset)
|
||||
m_InitialState = gameObject.activeSelf ? InitialState.Active : InitialState.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the Playable that owns the PlayableBehaviour is destroyed.
|
||||
/// </summary>
|
||||
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||||
public override void OnPlayableDestroy(Playable playable)
|
||||
{
|
||||
if (gameObject == null || m_InitialState == InitialState.Unset)
|
||||
return;
|
||||
|
||||
switch (postPlayback)
|
||||
{
|
||||
case PostPlaybackState.Active:
|
||||
gameObject.SetActive(true);
|
||||
break;
|
||||
|
||||
case PostPlaybackState.Inactive:
|
||||
gameObject.SetActive(false);
|
||||
break;
|
||||
|
||||
case PostPlaybackState.Revert:
|
||||
gameObject.SetActive(m_InitialState == InitialState.Active);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d20e4e177b86a2843805dd3894f41b42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is deprecated. It is recommended to use Playable Asset and Playable Behaviour derived classes instead.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[Obsolete("For best performance use PlayableAsset and PlayableBehaviour.")]
|
||||
public class BasicPlayableBehaviour : ScriptableObject, IPlayableAsset, IPlayableBehaviour
|
||||
{
|
||||
public BasicPlayableBehaviour() {}
|
||||
|
||||
/// <summary>
|
||||
/// The playback duration in seconds of the instantiated Playable.
|
||||
/// </summary>
|
||||
public virtual double duration { get { return PlayableBinding.DefaultDuration; } }
|
||||
|
||||
/// <summary>
|
||||
///A description of the outputs of the instantiated Playable.
|
||||
/// </summary>
|
||||
public virtual IEnumerable<PlayableBinding> outputs { get { return PlayableBinding.None; } }
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the PlayableGraph that owns this PlayableBehaviour starts.</para>
|
||||
/// </summary>
|
||||
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||||
public virtual void OnGraphStart(Playable playable) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the PlayableGraph that owns this PlayableBehaviour stops.</para>
|
||||
/// </summary>
|
||||
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||||
public virtual void OnGraphStop(Playable playable) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the Playable that owns the PlayableBehaviour is created.</para>
|
||||
/// </summary>
|
||||
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||||
public virtual void OnPlayableCreate(Playable playable) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the Playable that owns the PlayableBehaviour is destroyed.</para>
|
||||
/// </summary>
|
||||
/// <param name="playable">The Playable that owns the current PlayableBehaviour.</param>
|
||||
public virtual void OnPlayableDestroy(Playable playable) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the Playable play state is changed to Playables.PlayState.Playing.</para>
|
||||
/// </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 virtual void OnBehaviourPlay(Playable playable, FrameData info) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called when the Playable play state is changed to Playables.PlayState.Paused.</para>
|
||||
/// </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 virtual void OnBehaviourPause(Playable playable, FrameData info) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called during the PrepareFrame phase of the PlayableGraph.</para>
|
||||
/// </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 virtual void PrepareFrame(Playable playable, FrameData info) {}
|
||||
|
||||
/// <summary>
|
||||
/// <para>This function is called during the ProcessFrame phase of the PlayableGraph.</para>
|
||||
/// </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>
|
||||
/// <param name="playerData">The user data of the ScriptPlayableOutput that initiated the process pass.</param>
|
||||
public virtual void ProcessFrame(Playable playable, FrameData info, object playerData) {}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this method to have your asset inject playables into the given graph.
|
||||
/// </summary>
|
||||
/// <param name="graph">The graph to inject playables into.</param>
|
||||
/// <param name="owner">The game object which initiated the build.</param>
|
||||
/// <returns>The playable injected into the graph, or the root playable if multiple playables are injected.</returns>
|
||||
public virtual Playable CreatePlayable(PlayableGraph graph, GameObject owner)
|
||||
{
|
||||
return ScriptPlayable<BasicPlayableBehaviour>.Create(graph, this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe03a7b0ba57a4d488b6c327ae16c335
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,206 @@
|
|||
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;
|
||||
|
||||
private bool m_SyncTime = false;
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
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);
|
||||
SyncPlayState(playable.GetGraph(), playable.GetTime());
|
||||
}
|
||||
|
||||
/// <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);
|
||||
director.Evaluate();
|
||||
}
|
||||
|
||||
m_SyncTime = false;
|
||||
}
|
||||
|
||||
#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 SyncPlayState(PlayableGraph graph, double playableTime)
|
||||
{
|
||||
bool expectedFinished = (playableTime >= m_AssetDuration) && director.extrapolationMode == DirectorWrapMode.None;
|
||||
if (graph.IsPlaying() && !expectedFinished)
|
||||
director.Play();
|
||||
else
|
||||
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)
|
||||
{
|
||||
if (director.extrapolationMode == DirectorWrapMode.None)
|
||||
return false;
|
||||
else if (director.extrapolationMode == DirectorWrapMode.Hold)
|
||||
expectedTime = m_AssetDuration;
|
||||
else if (m_AssetDuration > float.Epsilon) // loop
|
||||
expectedTime = expectedTime % m_AssetDuration;
|
||||
}
|
||||
|
||||
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 = playable.GetTime();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: be156cc527d606b4aaac403e9843186e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,27 @@
|
|||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface that can be implemented by MonoBehaviours indicating that they receive time-related control calls from a PlayableGraph.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementing this interface on MonoBehaviours attached to GameObjects under control by control-tracks will cause them to be notified when associated Timeline clips are active.
|
||||
/// </remarks>
|
||||
public interface ITimeControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Called each frame the Timeline clip is active.
|
||||
/// </summary>
|
||||
/// <param name="time">The local time of the associated Timeline clip.</param>
|
||||
void SetTime(double time);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the associated Timeline clip becomes active.
|
||||
/// </summary>
|
||||
void OnControlTimeStart();
|
||||
|
||||
/// <summary>
|
||||
/// Called when the associated Timeline clip becomes deactivated.
|
||||
/// </summary>
|
||||
void OnControlTimeStop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5415c904c4fbc3e498253bc2866b37cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Use these flags to specify the notification behaviour.
|
||||
/// </summary>
|
||||
/// <see cref="UnityEngine.Playables.INotification"/>
|
||||
[Flags]
|
||||
[Serializable]
|
||||
public enum NotificationFlags : short
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this flag to send the notification in Edit Mode.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Sent on discontinuous jumps in time.
|
||||
/// </remarks>
|
||||
TriggerInEditMode = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Use this flag to send the notification if playback starts after the notification time.
|
||||
/// </summary>
|
||||
Retroactive = 1 << 1,
|
||||
|
||||
/// <summary>
|
||||
/// Use this flag to send the notification only once when looping.
|
||||
/// </summary>
|
||||
TriggerOnce = 1 << 2,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 983c76d87fb6f4f4597a526a4b2b5fd7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,177 @@
|
|||
using System;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Playable that synchronizes a particle system simulation.
|
||||
/// </summary>
|
||||
public class ParticleControlPlayable : PlayableBehaviour
|
||||
{
|
||||
const float kUnsetTime = -1;
|
||||
float m_LastTime = kUnsetTime;
|
||||
uint m_RandomSeed = 1;
|
||||
|
||||
// particleSystem.time can not be relied on for an accurate time. It does not advance until a delta threshold is reached(fixedUpdate) and until the start delay has elapsed.
|
||||
float m_SystemTime;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Playable with a ParticleControlPlayable behaviour attached
|
||||
/// </summary>
|
||||
/// <param name="graph">The PlayableGraph to inject the Playable into.</param>
|
||||
/// <param name="component">The particle systtem to control</param>
|
||||
/// <param name="randomSeed">A random seed to use for particle simulation</param>
|
||||
/// <returns>Returns the created Playable.</returns>
|
||||
public static ScriptPlayable<ParticleControlPlayable> Create(PlayableGraph graph, ParticleSystem component, uint randomSeed)
|
||||
{
|
||||
if (component == null)
|
||||
return ScriptPlayable<ParticleControlPlayable>.Null;
|
||||
|
||||
var handle = ScriptPlayable<ParticleControlPlayable>.Create(graph);
|
||||
handle.GetBehaviour().Initialize(component, randomSeed);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The particle system to control
|
||||
/// </summary>
|
||||
public ParticleSystem particleSystem { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the behaviour with a particle system and random seed.
|
||||
/// </summary>
|
||||
/// <param name="ps"></param>
|
||||
/// <param name="randomSeed"></param>
|
||||
public void Initialize(ParticleSystem ps, uint randomSeed)
|
||||
{
|
||||
m_RandomSeed = Math.Max(1, randomSeed);
|
||||
particleSystem = ps;
|
||||
m_SystemTime = 0;
|
||||
SetRandomSeed();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying && UnityEditor.PrefabUtility.IsPartOfPrefabInstance(ps))
|
||||
UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// This function is called when the Playable that owns the PlayableBehaviour is destroyed.
|
||||
/// </summary>
|
||||
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||||
public override void OnPlayableDestroy(Playable playable)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated;
|
||||
}
|
||||
|
||||
void OnPrefabUpdated(GameObject go)
|
||||
{
|
||||
// When the instance is updated from, this will cause the next evaluate to resimulate.
|
||||
if (UnityEditor.PrefabUtility.GetRootGameObject(particleSystem) == go)
|
||||
m_LastTime = kUnsetTime;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void SetRandomSeed()
|
||||
{
|
||||
particleSystem.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
||||
var systems = particleSystem.gameObject.GetComponentsInChildren<ParticleSystem>();
|
||||
uint seed = m_RandomSeed;
|
||||
foreach (var ps in systems)
|
||||
{
|
||||
// don't overwrite user set random seeds
|
||||
if (ps.useAutoRandomSeed)
|
||||
{
|
||||
ps.useAutoRandomSeed = false;
|
||||
ps.randomSeed = seed;
|
||||
seed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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="data">A FrameData structure that contains information about the current frame context.</param>
|
||||
public override void PrepareFrame(Playable playable, FrameData data)
|
||||
{
|
||||
if (particleSystem == null || !particleSystem.gameObject.activeInHierarchy)
|
||||
return;
|
||||
|
||||
float localTime = (float)playable.GetTime();
|
||||
bool shouldUpdate = Mathf.Approximately(m_LastTime, kUnsetTime) ||
|
||||
!Mathf.Approximately(m_LastTime, localTime);
|
||||
if (shouldUpdate)
|
||||
{
|
||||
float epsilon = Time.fixedDeltaTime * 0.5f;
|
||||
float simTime = localTime;
|
||||
float expectedDelta = simTime - m_LastTime;
|
||||
|
||||
// The first iteration includes the start delay. Evaluate(particleSystem.randomSeed) is how the particle system generates the random value internally.
|
||||
float startDelay = particleSystem.main.startDelay.Evaluate(particleSystem.randomSeed);
|
||||
float particleSystemDurationLoop0 = particleSystem.main.duration + startDelay;
|
||||
|
||||
// The particle system time does not include the start delay so we need to remove this for our own system time.
|
||||
float expectedSystemTime = simTime > particleSystemDurationLoop0 ? m_SystemTime : m_SystemTime - startDelay;
|
||||
|
||||
// if it's not looping, then the system time won't advance past the end of the duration
|
||||
if (!particleSystem.main.loop)
|
||||
expectedSystemTime = Math.Min(expectedSystemTime, particleSystem.main.duration);
|
||||
|
||||
|
||||
// conditions for restart
|
||||
bool restart = (simTime < m_LastTime) || // time went backwards
|
||||
(simTime < epsilon) || // time is set to 0
|
||||
Mathf.Approximately(m_LastTime, kUnsetTime) || // object disabled
|
||||
(expectedDelta > particleSystem.main.duration) || // large jump (bug workaround)
|
||||
!(Mathf.Abs(expectedSystemTime - particleSystem.time) < Time.maximumParticleDeltaTime); // particle system isn't where we left it
|
||||
if (restart)
|
||||
{
|
||||
// work around for a bug where simulate(simTime, true, true) doesn't work on loops
|
||||
particleSystem.Simulate(0, true, true);
|
||||
particleSystem.Simulate(simTime, true, false);
|
||||
m_SystemTime = simTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ps.time will wrap, so we need to account for that in computing delta time
|
||||
float particleSystemDuration = simTime > particleSystemDurationLoop0 ? particleSystem.main.duration : particleSystemDurationLoop0;
|
||||
float fracTime = simTime % particleSystemDuration;
|
||||
float deltaTime = fracTime - m_SystemTime;
|
||||
|
||||
if (deltaTime < -epsilon) // detect wrapping of ps.time
|
||||
deltaTime = fracTime + particleSystemDurationLoop0 - m_SystemTime;
|
||||
|
||||
particleSystem.Simulate(deltaTime, true, false);
|
||||
m_SystemTime += deltaTime;
|
||||
}
|
||||
|
||||
m_LastTime = localTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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_LastTime = kUnsetTime;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
m_LastTime = kUnsetTime;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f603edd7163537f44927ad2808147a25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Playable that controls and instantiates a Prefab.
|
||||
/// </summary>
|
||||
public class PrefabControlPlayable : PlayableBehaviour
|
||||
{
|
||||
GameObject m_Instance;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private bool m_IsActiveCached;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Playable with a PrefabControlPlayable behaviour attached
|
||||
/// </summary>
|
||||
/// <param name="graph">The PlayableGraph to inject the Playable into.</param>
|
||||
/// <param name="prefabGameObject">The prefab to instantiate from</param>
|
||||
/// <param name="parentTransform">Transform to parent instance to. Can be null.</param>
|
||||
/// <returns>Returns a Playabe with PrefabControlPlayable behaviour attached.</returns>
|
||||
public static ScriptPlayable<PrefabControlPlayable> Create(PlayableGraph graph, GameObject prefabGameObject, Transform parentTransform)
|
||||
{
|
||||
if (prefabGameObject == null)
|
||||
return ScriptPlayable<PrefabControlPlayable>.Null;
|
||||
|
||||
var handle = ScriptPlayable<PrefabControlPlayable>.Create(graph);
|
||||
handle.GetBehaviour().Initialize(prefabGameObject, parentTransform);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The instance of the prefab created by this behaviour
|
||||
/// </summary>
|
||||
public GameObject prefabInstance
|
||||
{
|
||||
get { return m_Instance; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the behaviour with a prefab and parent transform
|
||||
/// </summary>
|
||||
/// <param name="prefabGameObject">The prefab to instantiate from</param>
|
||||
/// <param name="parentTransform">Transform to parent instance to. Can be null.</param>
|
||||
/// <returns>The created instance</returns>
|
||||
public GameObject Initialize(GameObject prefabGameObject, Transform parentTransform)
|
||||
{
|
||||
if (prefabGameObject == null)
|
||||
throw new ArgumentNullException("Prefab cannot be null");
|
||||
|
||||
if (m_Instance != null)
|
||||
{
|
||||
Debug.LogWarningFormat("Prefab Control Playable ({0}) has already been initialized with a Prefab ({1}).", prefabGameObject.name, m_Instance.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
m_Instance = (GameObject)UnityEditor.PrefabUtility.InstantiatePrefab(prefabGameObject, parentTransform);
|
||||
UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_Instance = Object.Instantiate(prefabGameObject, parentTransform, false);
|
||||
}
|
||||
m_Instance.name = prefabGameObject.name + " [Timeline]";
|
||||
m_Instance.SetActive(false);
|
||||
SetHideFlagsRecursive(m_Instance);
|
||||
}
|
||||
return m_Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the Playable that owns the PlayableBehaviour is destroyed.
|
||||
/// </summary>
|
||||
/// <param name="playable">The playable this behaviour is attached to.</param>
|
||||
public override void OnPlayableDestroy(Playable playable)
|
||||
{
|
||||
if (m_Instance)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Object.Destroy(m_Instance);
|
||||
else
|
||||
Object.DestroyImmediate(m_Instance);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated;
|
||||
#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)
|
||||
{
|
||||
if (m_Instance == null)
|
||||
return;
|
||||
|
||||
m_Instance.SetActive(true);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
m_IsActiveCached = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// OnBehaviourPause can be called if the graph is stopped for a variety of reasons
|
||||
// the effectivePlayState will test if the pause is due to the clip being out of bounds
|
||||
if (m_Instance != null && info.effectivePlayState == PlayState.Paused)
|
||||
{
|
||||
m_Instance.SetActive(false);
|
||||
#if UNITY_EDITOR
|
||||
m_IsActiveCached = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnPrefabUpdated(GameObject go)
|
||||
{
|
||||
if (go == m_Instance)
|
||||
{
|
||||
SetHideFlagsRecursive(go);
|
||||
go.SetActive(m_IsActiveCached);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void SetHideFlagsRecursive(GameObject gameObject)
|
||||
{
|
||||
if (gameObject == null)
|
||||
return;
|
||||
|
||||
gameObject.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor;
|
||||
if (!Application.isPlaying)
|
||||
gameObject.hideFlags |= HideFlags.HideInHierarchy;
|
||||
foreach (Transform child in gameObject.transform)
|
||||
{
|
||||
SetHideFlagsRecursive(child.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 439c018cf4619e94d9a92110ce0aa188
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,85 @@
|
|||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// A PlayableBehaviour that manages a component that implements the ITimeControl interface
|
||||
/// </summary>
|
||||
public class TimeControlPlayable : PlayableBehaviour
|
||||
{
|
||||
ITimeControl m_timeControl;
|
||||
|
||||
bool m_started;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a Playable with a TimeControlPlayable behaviour attached
|
||||
/// </summary>
|
||||
/// <param name="graph">The PlayableGraph to inject the Playable into.</param>
|
||||
/// <param name="timeControl"></param>
|
||||
/// <returns></returns>
|
||||
public static ScriptPlayable<TimeControlPlayable> Create(PlayableGraph graph, ITimeControl timeControl)
|
||||
{
|
||||
if (timeControl == null)
|
||||
return ScriptPlayable<TimeControlPlayable>.Null;
|
||||
|
||||
var handle = ScriptPlayable<TimeControlPlayable>.Create(graph);
|
||||
handle.GetBehaviour().Initialize(timeControl);
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the behaviour
|
||||
/// </summary>
|
||||
/// <param name="timeControl">Component that implements the ITimeControl interface</param>
|
||||
public void Initialize(ITimeControl timeControl)
|
||||
{
|
||||
m_timeControl = timeControl;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
Debug.Assert(m_started, "PrepareFrame has been called without OnControlTimeStart being called first.");
|
||||
if (m_timeControl != null)
|
||||
m_timeControl.SetTime(playable.GetTime());
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if (m_timeControl == null)
|
||||
return;
|
||||
|
||||
if (!m_started)
|
||||
{
|
||||
m_timeControl.OnControlTimeStart();
|
||||
m_started = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 (m_timeControl == null)
|
||||
return;
|
||||
|
||||
if (m_started)
|
||||
{
|
||||
m_timeControl.OnControlTimeStop();
|
||||
m_started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1db879070d9a45f4c86cdf5e59616df5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,254 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace UnityEngine.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this PlayableBehaviour to send notifications at a given time.
|
||||
/// </summary>
|
||||
/// <seealso cref="UnityEngine.Timeline.NotificationFlags"/>
|
||||
public class TimeNotificationBehaviour : PlayableBehaviour
|
||||
{
|
||||
struct NotificationEntry
|
||||
{
|
||||
public double time;
|
||||
public INotification payload;
|
||||
public bool notificationFired;
|
||||
public NotificationFlags flags;
|
||||
|
||||
public bool triggerInEditor
|
||||
{
|
||||
get { return (flags & NotificationFlags.TriggerInEditMode) != 0; }
|
||||
}
|
||||
public bool prewarm
|
||||
{
|
||||
get { return (flags & NotificationFlags.Retroactive) != 0; }
|
||||
}
|
||||
public bool triggerOnce
|
||||
{
|
||||
get { return (flags & NotificationFlags.TriggerOnce) != 0; }
|
||||
}
|
||||
}
|
||||
|
||||
readonly List<NotificationEntry> m_Notifications = new List<NotificationEntry>();
|
||||
double m_PreviousTime;
|
||||
bool m_NeedSortNotifications;
|
||||
|
||||
Playable m_TimeSource;
|
||||
|
||||
/// <summary>
|
||||
/// Sets an optional Playable that provides duration and Wrap mode information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// timeSource is optional. By default, the duration and Wrap mode will come from the current Playable.
|
||||
/// </remarks>
|
||||
public Playable timeSource
|
||||
{
|
||||
set { m_TimeSource = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initializes a ScriptPlayable with a TimeNotificationBehaviour.
|
||||
/// </summary>
|
||||
/// <param name="graph">The playable graph.</param>
|
||||
/// <param name="duration">The duration of the playable.</param>
|
||||
/// <param name="loopMode">The loop mode of the playable.</param>
|
||||
/// <returns>A new TimeNotificationBehaviour linked to the PlayableGraph.</returns>
|
||||
public static ScriptPlayable<TimeNotificationBehaviour> Create(PlayableGraph graph, double duration, DirectorWrapMode loopMode)
|
||||
{
|
||||
var notificationsPlayable = ScriptPlayable<TimeNotificationBehaviour>.Create(graph);
|
||||
notificationsPlayable.SetDuration(duration);
|
||||
notificationsPlayable.SetTimeWrapMode(loopMode);
|
||||
notificationsPlayable.SetPropagateSetTime(true);
|
||||
return notificationsPlayable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a notification to be sent with flags, at a specific time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to send the notification.</param>
|
||||
/// <param name="payload">The notification.</param>
|
||||
/// <param name="flags">The notification flags that determine the notification behaviour. This parameter is set to Retroactive by default.</param>
|
||||
/// <seealso cref="UnityEngine.Timeline.NotificationFlags"/>
|
||||
public void AddNotification(double time, INotification payload, NotificationFlags flags = NotificationFlags.Retroactive)
|
||||
{
|
||||
m_Notifications.Add(new NotificationEntry
|
||||
{
|
||||
time = time,
|
||||
payload = payload,
|
||||
flags = flags
|
||||
});
|
||||
m_NeedSortNotifications = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called when the PlayableGraph that owns this PlayableBehaviour starts.
|
||||
/// </summary>
|
||||
/// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param>
|
||||
public override void OnGraphStart(Playable playable)
|
||||
{
|
||||
SortNotifications();
|
||||
for (var i = 0; i < m_Notifications.Count; i++)
|
||||
{
|
||||
var notification = m_Notifications[i];
|
||||
notification.notificationFired = false;
|
||||
m_Notifications[i] = notification;
|
||||
}
|
||||
|
||||
m_PreviousTime = playable.GetTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called when the Playable play state is changed to PlayState.Paused
|
||||
/// </summary>
|
||||
/// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param>
|
||||
/// <param name="info">Playable context information such as weight, evaluationType, and so on.</param>
|
||||
public override void OnBehaviourPause(Playable playable, FrameData info)
|
||||
{
|
||||
if (playable.IsDone())
|
||||
{
|
||||
SortNotifications();
|
||||
for (var i = 0; i < m_Notifications.Count; i++)
|
||||
{
|
||||
var e = m_Notifications[i];
|
||||
if (!e.notificationFired)
|
||||
{
|
||||
var duration = playable.GetDuration();
|
||||
var canTrigger = m_PreviousTime <= e.time && e.time <= duration;
|
||||
if (canTrigger)
|
||||
{
|
||||
Trigger_internal(playable, info.output, ref e);
|
||||
m_Notifications[i] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called during the PrepareFrame phase of the PlayableGraph.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Called once before processing starts.
|
||||
/// </remarks>
|
||||
/// <param name="playable">The reference to the playable associated with this PlayableBehaviour.</param>
|
||||
/// <param name="info">Playable context information such as weight, evaluationType, and so on.</param>
|
||||
public override void PrepareFrame(Playable playable, FrameData info)
|
||||
{
|
||||
// Never trigger on scrub
|
||||
if (info.evaluationType == FrameData.EvaluationType.Evaluate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SyncDurationWithExternalSource(playable);
|
||||
SortNotifications();
|
||||
var currentTime = playable.GetTime();
|
||||
|
||||
// Fire notifications from previousTime till the end
|
||||
if (info.timeLooped)
|
||||
{
|
||||
var duration = playable.GetDuration();
|
||||
TriggerNotificationsInRange(m_PreviousTime, duration, info, playable, true);
|
||||
var dx = playable.GetDuration() - m_PreviousTime;
|
||||
var nFullTimelines = (int)((info.deltaTime * info.effectiveSpeed - dx) / playable.GetDuration());
|
||||
for (var i = 0; i < nFullTimelines; i++)
|
||||
{
|
||||
TriggerNotificationsInRange(0, duration, info, playable, false);
|
||||
}
|
||||
TriggerNotificationsInRange(0, currentTime, info, playable, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pt = playable.GetTime();
|
||||
TriggerNotificationsInRange(m_PreviousTime, pt, info,
|
||||
playable, true);
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Notifications.Count; ++i)
|
||||
{
|
||||
var e = m_Notifications[i];
|
||||
if (e.notificationFired && CanRestoreNotification(e, info, currentTime, m_PreviousTime))
|
||||
{
|
||||
Restore_internal(ref e);
|
||||
m_Notifications[i] = e;
|
||||
}
|
||||
}
|
||||
|
||||
m_PreviousTime = playable.GetTime();
|
||||
}
|
||||
|
||||
void SortNotifications()
|
||||
{
|
||||
if (m_NeedSortNotifications)
|
||||
{
|
||||
m_Notifications.Sort((x, y) => x.time.CompareTo(y.time));
|
||||
m_NeedSortNotifications = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CanRestoreNotification(NotificationEntry e, FrameData info, double currentTime, double previousTime)
|
||||
{
|
||||
if (e.triggerOnce)
|
||||
return false;
|
||||
if (info.timeLooped)
|
||||
return true;
|
||||
|
||||
//case 1111595: restore the notification if the time is manually set before it
|
||||
return previousTime > currentTime && currentTime <= e.time;
|
||||
}
|
||||
|
||||
void TriggerNotificationsInRange(double start, double end, FrameData info, Playable playable, bool checkState)
|
||||
{
|
||||
if (start <= end)
|
||||
{
|
||||
var playMode = Application.isPlaying;
|
||||
for (var i = 0; i < m_Notifications.Count; i++)
|
||||
{
|
||||
var e = m_Notifications[i];
|
||||
if (e.notificationFired && (checkState || e.triggerOnce))
|
||||
continue;
|
||||
|
||||
var notificationTime = e.time;
|
||||
if (e.prewarm && notificationTime < end && (e.triggerInEditor || playMode))
|
||||
{
|
||||
Trigger_internal(playable, info.output, ref e);
|
||||
m_Notifications[i] = e;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (notificationTime < start || notificationTime > end)
|
||||
continue;
|
||||
|
||||
if (e.triggerInEditor || playMode)
|
||||
{
|
||||
Trigger_internal(playable, info.output, ref e);
|
||||
m_Notifications[i] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SyncDurationWithExternalSource(Playable playable)
|
||||
{
|
||||
if (m_TimeSource.IsValid())
|
||||
{
|
||||
playable.SetDuration(m_TimeSource.GetDuration());
|
||||
playable.SetTimeWrapMode(m_TimeSource.GetTimeWrapMode());
|
||||
}
|
||||
}
|
||||
|
||||
static void Trigger_internal(Playable playable, PlayableOutput output, ref NotificationEntry e)
|
||||
{
|
||||
output.PushNotification(playable, e.payload);
|
||||
e.notificationFired = true;
|
||||
}
|
||||
|
||||
static void Restore_internal(ref NotificationEntry e)
|
||||
{
|
||||
e.notificationFired = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: afeb55855d7a63b45ba6f8bd97599202
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue