Tutorial - Linear Replay
Prepare a Particle System
Add the GameObjectTimeMachine to a GameObject in the Scene
Add ParticleSystem into the Scene
Add a Remember Component to the GameObject with the ParticleSystem
Add a Remember Particle System
Check Enable Time Machine Recording
Create a new script
using UnityEngine;
using UnityEngine.UI;
using Arawn.CrystalSave.Runtime.TimeMachine;
namespace Arawn.CrystalSave.Demo
{
/// <summary>
/// Demo script to control GameObjectTimeMachine with 4 buttons for global timeline playback:
/// - Play Forward: Start timeline playback in forward direction
/// - Play Backward: Start timeline playback in reverse direction (negative speed)
/// - Record: Resume/start recording
/// - Pause: Pause current recording or playback
///
/// Features:
/// - Smooth interpolation between snapshots during playback (configurable)
/// - Continues playback from current timeline position
/// - Adjustable playback speed
/// </summary>
public class TimeMachineControllerDemo : MonoBehaviour
{
[Header("Time Machine Reference")]
[Tooltip("Reference to the GameObjectTimeMachine component")]
[SerializeField] private GameObjectTimeMachine timeMachine;
[Header("Button References")]
[Tooltip("Button to play timeline forward")]
[SerializeField] private Button playForwardButton;
[Tooltip("Button to play timeline backward")]
[SerializeField] private Button playBackwardButton;
[Tooltip("Button to start/resume recording")]
[SerializeField] private Button recordButton;
[Tooltip("Button to pause recording or playback")]
[SerializeField] private Button pauseButton;
[Header("Playback Settings")]
[Tooltip("Playback speed multiplier (1.0 = normal speed)")]
[SerializeField] private float playbackSpeed = 1f;
[Tooltip("Enable smooth interpolation between snapshots during playback")]
[SerializeField] private bool enableInterpolation = true;
private void Start()
{
// Validate references
if (timeMachine == null)
{
Debug.LogError("[TimeMachineControllerDemo] GameObjectTimeMachine reference is not set!");
enabled = false;
return;
}
// Set interpolation state
timeMachine.SetGlobalInterpolation(enableInterpolation); // Setup button listeners
if (playForwardButton != null)
{
playForwardButton.onClick.AddListener(OnPlayForward);
}
else
{
Debug.LogWarning("[TimeMachineControllerDemo] Play Forward button is not assigned!");
}
if (playBackwardButton != null)
{
playBackwardButton.onClick.AddListener(OnPlayBackward);
}
else
{
Debug.LogWarning("[TimeMachineControllerDemo] Play Backward button is not assigned!");
}
if (recordButton != null)
{
recordButton.onClick.AddListener(OnRecord);
}
else
{
Debug.LogWarning("[TimeMachineControllerDemo] Record button is not assigned!");
}
if (pauseButton != null)
{
pauseButton.onClick.AddListener(OnPause);
}
else
{
Debug.LogWarning("[TimeMachineControllerDemo] Pause button is not assigned!");
}
}
private void OnDestroy()
{
// Clean up button listeners
if (playForwardButton != null)
{
playForwardButton.onClick.RemoveListener(OnPlayForward);
}
if (playBackwardButton != null)
{
playBackwardButton.onClick.RemoveListener(OnPlayBackward);
}
if (recordButton != null)
{
recordButton.onClick.RemoveListener(OnRecord);
}
if (pauseButton != null)
{
pauseButton.onClick.RemoveListener(OnPause);
}
}
/// <summary>
/// Play timeline forward (normal playback)
/// </summary>
private void OnPlayForward()
{
// Ensure interpolation is set before starting playback
timeMachine.SetGlobalInterpolation(enableInterpolation);
// Set direction to forward (not reverse)
timeMachine.SetGlobalReversePlayback(false);
// Use current timeline position to continue from where we are
float startTime = timeMachine.CurrentTimelinePosition;
timeMachine.StartTimelinePlayback(startTime: startTime, playbackSpeed: playbackSpeed);
Debug.Log($"[TimeMachineControllerDemo] Playing timeline forward from {startTime:F2}s at {playbackSpeed}x speed (Interpolation: {(enableInterpolation ? "ON" : "OFF")})");
}
/// <summary>
/// Play timeline backward (reverse playback using negative speed)
/// </summary>
private void OnPlayBackward()
{
// Ensure interpolation is set before starting playback
timeMachine.SetGlobalInterpolation(enableInterpolation);
// Set direction to reverse
timeMachine.SetGlobalReversePlayback(true);
// Use current timeline position to continue from where we are
float startTime = timeMachine.CurrentTimelinePosition;
// Use absolute value of playbackSpeed since direction is controlled by SetGlobalReversePlayback
timeMachine.StartTimelinePlayback(startTime: startTime, playbackSpeed: playbackSpeed);
Debug.Log($"[TimeMachineControllerDemo] Playing timeline backward from {startTime:F2}s at {playbackSpeed}x speed (Interpolation: {(enableInterpolation ? "ON" : "OFF")})");
}
/// <summary>
/// Start or resume recording
/// </summary>
private void OnRecord()
{
timeMachine.ResumeRecording();
Debug.Log("[TimeMachineControllerDemo] Recording resumed");
}
/// <summary>
/// Pause current recording or playback
/// </summary>
private void OnPause()
{
// Pause timeline playback if active
timeMachine.PauseTimelinePlayback();
// Also pause recording if active
timeMachine.PauseRecording();
Debug.Log("[TimeMachineControllerDemo] Playback and recording paused");
}
/// <summary>
/// Public method to change playback speed at runtime
/// </summary>
public void SetPlaybackSpeed(float speed)
{
playbackSpeed = Mathf.Max(0.1f, speed);
Debug.Log($"[TimeMachineControllerDemo] Playback speed set to {playbackSpeed}x");
}
/// <summary>
/// Public method to enable or disable interpolation at runtime
/// </summary>
public void SetInterpolation(bool enabled)
{
enableInterpolation = enabled;
timeMachine.SetGlobalInterpolation(enabled);
Debug.Log($"[TimeMachineControllerDemo] Interpolation: {(enabled ? "ON" : "OFF")}");
}
/// <summary>
/// Public method to toggle interpolation at runtime
/// </summary>
public void ToggleInterpolation()
{
SetInterpolation(!enableInterpolation);
}
}
}
Attach the script to Scene GameObject
Create UI buttons and name and reference the buttons in our TimeMachineControllerDemo
Run the game
Let it run for at least 3 seconds
Click on the Play Backward button
Last updated