Tutorial - Linear Replay

Prepare a Particle System

  1. Add the GameObjectTimeMachine to a GameObject in the Scene

  2. Add ParticleSystem into the Scene

  3. Add a Remember Component to the GameObject with the ParticleSystem

  4. Add a Remember Particle System

  5. 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);
	}
}
}
  1. Attach the script to Scene GameObject

  2. Create UI buttons and name and reference the buttons in our TimeMachineControllerDemo

Run the game

  1. Let it run for at least 3 seconds

  2. Click on the Play Backward button

Last updated