Scene and Node Lifecycle
The samples all follow the same structural conventions; this page states them outright.
Scene flow: the director owns it
CCDirector.SharedDirector.RunWithScene(new MainMenuScene()); // first scene only
CCDirector.SharedDirector.ReplaceScene(new GameScene()); // normal navigation
CCDirector.SharedDirector.PushScene(new PauseScene()); // overlay, keep the old scene
CCDirector.SharedDirector.PopScene(); // return to it
RunWithScenestarts the very first scene only; from then on,ReplaceSceneis the normal navigation between scenes.PushScene/PopSceneis the exception to that: temporary overlays (pause, settings) where the underlying scene should survive untouched — cheaper than rebuilding, and it keeps gameplay state alive by construction.- Transitions wrap the incoming scene:
ReplaceScene(new CCTransitionFade(0.5f, next)).
Node lifecycle: build → enter → exit
A node's life has three phases, and each kind of work belongs in exactly one of them:
public class GameLayer : CCLayer
{
public GameLayer()
{
// 1. BUILD - construct the hierarchy: create children, set positions.
// The node is NOT in a running scene yet: no scheduling, no input.
AddChild(new CCSprite("player"));
}
public override void OnEnter()
{
base.OnEnter(); // ALWAYS first - wires children, scheduler, and touch registration
// 2. ACTIVATE - the node just joined the running scene:
// schedule updates, subscribe to input, start ambient actions/audio.
ScheduleUpdate();
}
public override void OnExit()
{
// 3. DEACTIVATE - mirror OnEnter: unschedule, unsubscribe, stop what you started.
UnscheduleUpdate();
base.OnExit(); // ALWAYS last
}
}
The rules the engine assumes:
- Always call
base.OnEnter()/base.OnExit()— they propagate the lifecycle to children and manage scheduler/touch registration. Skipping them is the classic source of "my child never updates" and "touches leak into dead scenes." OnEnterandOnExitare symmetric. Everything you start in one, stop in the other — a node can enter and exit multiple times (push/pop flows re-enter the underlying scene).OnEnterTransitionDidFinishfires after an incoming transition completes — use it to defer gameplay start (input enabling, music) until the scene is fully visible.- For heavyweight teardown, remove children with
RemoveChild(child, cleanup: true)so running actions and schedules are stopped, not orphaned.
The test app's scenes (see the Tests README) are living examples of these conventions across every engine subsystem.