menu_bookDocumentation
Scene Tick Order: Full Frame Pipeline — FixedUpdate, Update, PreRender, ProcessDeletes, and Stage Hooks
Scene Tick Order: The Full Frame Pipeline
Understanding the exact order of operations in a scene tick is critical for writing correct game logic.
Game Tick Order (Scene.GameTick)
- UpdateTime( timeDelta ) — advances TimeNow and TimeDelta (scaled by TimeScale)
- SyncContext.FrameStage.Update.Trigger() — async frame stage
- Fixed Update loop (if ProjectSettings.Physics.UseFixedUpdate):
- ProcessDeletes() — destroy queued objects
- Signal( Stage.StartUpdate )
- InternalUpdate():
- Signal( Stage.UpdateBones )
- PreRender() — OnPreRender() on all pre-render components (skipped if headless)
- ProcessDeletes()
- Signal( Stage.FinishUpdate )
- SoundHandle.FlushCreatedSounds()
- SyncContext.FrameStage.PreRender.Trigger()
Key Insights
- ProcessDeletes() is called multiple times per frame — after fixed update and after update. Objects destroyed with Destroy() are queued and removed at these points.
- OnStart() is called lazily from RunPendingStarts(), which runs at the start of both fixed update and regular update. A component enabled mid-frame will have OnStart called before its first OnUpdate.
- Signal( Stage.Interpolation ) runs before OnUpdate, so transform interpolation is already applied when your update code runs.
- OnPreRender() is skipped entirely on dedicated servers (Application.IsHeadless).
- The TimeScale property on Scene scales TimeDelta but not RealTime.
- Network updates (SceneNetworkUpdate()) run at the start of SharedTick, before fixed update.
GameObjectSystem Stage Hooks
GameObjectSystem can hook into any stage:CSHARP
public class MySystem : GameObjectSystem<MySystem>
{
public MySystem( Scene scene ) : base( scene )
{
Listen( Stage.StartUpdate, 0, OnStartUpdate, "MySystem.OnStartUpdate" );
Listen( Stage.PhysicsStep, 0, OnPhysicsStep, "MySystem.OnPhysicsStep" );
Listen( Stage.FinishUpdate, 0, OnFinishUpdate, "MySystem.OnFinishUpdate" );
}
void OnStartUpdate() { /* runs before OnUpdate on all components */ }
void OnPhysicsStep() { /* runs during fixed update, after component FixedUpdate */ }
void OnFinishUpdate() { /* runs after all OnUpdate calls */ }
}The order parameter controls priority within a stage (negative = before default, positive = after).
Was this helpful?