Warning
Warning: Unity Simulation is deprecated as of December 2023, and is no longer available.
Pause and resume a simulation
Simulations encapsulate a wide range of real world scenarios, which often involve unexpected situations. While the real world can't be paused in case a robot crashes into an object, or behaves unexpectedly, the Pause
and Resume
functionalities in Distributed Rendering allow users to pause the simulation at certain points in time.
Usage
FrameManager
exposes Pause and Resume methods and properties via the singleton FrameManager.Instance
.
Pause(): Sets the simulation Timescale and related properties to zero, effectively disabling the simulation. While paused, Distributed Rendering will not generate any new metaframes. Any pending metaframes will be dispatched.
Resume(): Un-pauses the simulation.
ClearQueues(): Removes any pending metaframes from all camera queues. This effectively fast-forwards the Clients to the current state of the scene as managed by the Server.
PauseUntil(Func
) : Pauses the simulation until the specified condition is satisfied.SynchronizedRunStart(): Forces Clients to stay in sync with the Server. The Server will wait for each render node to complete the current frame before generating any new metaframes.
SynchronizedRunStop() Ends the synchronous run. The Server may run at full speed without waiting on Clients.
The following code sample demonstrates these methods by adding various buttons that execute these methods. Attach this code to any game object in the scene before building.
using UnityEngine;
using UnityEngine.UI;
using Unity.Simulation.DistributedRendering.Core;
using UnityEngine.Events;
public class SimulationControls : MonoBehaviour
{
#region UI Buttons
public Button btnClearQueues;
public Button btnPause;
public Button btnNext;
public Button btnPauseUntil;
public Button btnRunSynchronous;
#endregion
// Start is called before the first frame update
void Start()
{
Debug.Log($"Initializing {nameof(SceneControls)}");
tryAddClick(btnPause, PauseResume);
tryAddClick(btnNext, SingleStep);
tryAddClick(btnClearQueues, FrameManager.Instance.ClearQueues);
tryAddClick(btnRunSynchronous, RunSynchronous);
}
private void tryAddClick(Button button, UnityAction handler)
{
if (null != button)
button.onClick.AddListener(handler);
}
/// <summary>
/// Remove any pending metaframes from all camera queues.
/// </summary>
void ClearQueues() => FrameManager.Instance.ClearQueues();
/// <summary>
/// Pause or resume the simulation
/// </summary>
public void PauseResume()
{
if (FrameManager.Instance.IsPaused)
FrameManager.Instance.Resume();
else
FrameManager.Instance.Pause();
/// uncomment this line to fast-forward render nodes to the current frame on the next iteration
//_drSystem.ClearQueues();
Debug.Log($"{nameof(SceneControls)}.Pause {FrameManager.Instance.IsPaused}");
}
/// <summary>
/// Dispatch the next pending metaframe to all clients. Pause immediately after.
/// </summary>
public void SingleStep()
{
FrameManager.Instance.RunOneFrame();
/// See also:
/// _drSystem.PauseUntil(Func<bool>...)
/// unpause the system for one frame.
}
private bool _isRunningSynchronous;
public void RunSynchronous()
{
_isRunningSynchronous = !_isRunningSynchronous;
if (_isRunningSynchronous)
{
SetButtonText("btnRunSynchronous", "Synchronized: Running");
FrameManager.Instance.SynchronizedRunStart();
}
else
{
SetButtonText("btnRunSynchronous", "Run Synchronous");
FrameManager.Instance.SynchronizedRunStop();
}
}
private void SetButtonText(string buttonName, string newText)
{
var t = GameObject.Find(buttonName).GetComponentInChildren<Text>(true);
t.text = newText;
}
}