Entity Lifecycle¶
Scripts override the protected virtual methods on Entity to
hook into the simulation. Override only the methods you need. The base implementations are
empty.
In short
OnCreate runs once when the script starts and OnDestroy once when the entity is
destroyed. In between, the per-step callbacks run on fixed simulation steps, not once per
rendered frame. Only OnUpdate and OnLateUpdate are enabled in new scenes; turn the
others on in Settings → Scene → Scripts.
graph LR
Create([OnCreate]) --> Step
subgraph Step["Each simulation step, repeated"]
direction LR
Pre[OnPreUpdate]:::off --> Up[OnUpdate]:::on --> Phys[OnPhysicsUpdate]:::off --> Late[OnLateUpdate]:::on --> Post[OnPostUpdate]:::off
end
Step --> Destroy([OnDestroy])
classDef on fill:#f5503d,stroke:#f5503d,color:#ffffff;
classDef off fill:transparent,stroke:#777777,color:#999999,stroke-dasharray:4 3;
OnCreate runs once, the per-step callbacks repeat every simulation step, and OnDestroy
runs once at the end. Solid nodes are enabled by default. Dashed nodes are disabled until
you turn them on in the scene's settings.
Creation and destruction¶
| Callback | When |
|---|---|
OnCreate() |
Runs once when the entity's script starts. Intended for caching components and initialising state. |
OnDestroy() |
Runs once when the entity is destroyed. Intended for releasing allocated resources. |
Events¶
Entity exposes events that can be subscribed to, typically in OnCreate:
protected override void OnCreate()
{
CollisionBeginEvent += other => Log.Info($"Hit {other.Tag}");
}
| Event | Fires when |
|---|---|
CollisionBeginEvent / CollisionEndEvent |
a Jolt rigid body or character controller starts or stops touching another Jolt body |
TriggerBeginEvent / TriggerEndEvent |
a Jolt rigid body or character controller enters or leaves a trigger (a Jolt RigidBody with Is Trigger set) |
Collision2DBeginEvent / Collision2DEndEvent |
a Box2D collision starts or ends |
DestroyedEvent |
the entity is destroyed |
Each collision and trigger event passes the other entity involved. The
Entity reference lists every event.
MuJoCo contacts do not raise these events
The 3D collision and trigger events come from Jolt physics only. Contacts between
MuJoCo bodies, such as a robot's gripper closing on an object, do not raise them. To
test a MuJoCo contact, look up the geom with GetGeomID and call IsGeomInContact on
the robot's MujocoSceneComponent.
The per-step callbacks¶
Lucky Engine does not run scripts once per frame. The simulation advances in fixed time steps, and each step walks through an ordered set of phases. Each callback is bound to a phase, so the order it fires in comes from its phase rather than its position in the class. Whether it fires at all comes from the scene's settings.
| Callback | Phase | Enabled By Default | Default TimeRunner |
|---|---|---|---|
OnPreUpdate(float ts) |
Acquisition | Robot (Runner 0), 50 Hz | |
OnUpdate(float ts) |
Control | Robot (Runner 0), 50 Hz | |
OnPhysicsUpdate(float ts) |
Physics | Robot (Runner 0), 50 Hz | |
OnLateUpdate(float ts) |
Validation | Robot (Runner 0), 50 Hz | |
OnPostUpdate(float ts) |
Export | Robot (Runner 0), 50 Hz |
Most game logic belongs in OnUpdate. OnLateUpdate runs later in the same step and
suits logic that depends on the rest of the step completing first, such as camera follow.
Only OnUpdate and OnLateUpdate run by default
OnPreUpdate, OnPhysicsUpdate and OnPostUpdate are disabled in new scenes. Turn
them on per scene in Settings → Scene → Scripts with Enable OnPreUpdate
Scripts, Enable OnPhysicsUpdate Scripts or Enable OnPostUpdate Scripts. An
overridden callback that never fires is usually a disabled one.
Open the Settings panel from Edit → Settings; the Settings page describes the panel. On the same Scripts page, each enabled callback also has a TimeRunner dropdown (for example OnUpdate Scripts TimeRunner), an Execution Phase dropdown, and an Internal Phase Priority that orders it among the other systems in its phase, lowest first.
The Phase column sets the order each callback runs in within a step. The Default TimeRunner column sets how often it runs. Every callback uses the Robot runner at 50 Hz by default, so the enabled callbacks step at the same rate. A callback can be reassigned to a runner that steps at a different frequency. The phases, the order they run in, and the runner model are explained in Time Runners.
About ts¶
ts is the length of one simulation step, in seconds. It is a fixed value. A 50 Hz
step gives a ts of 0.02. It is not the wall-clock time since the last rendered frame.
Because the step is fixed, ts is not required for consistent motion, but scaling rates by
it keeps values in real-world units.
Free-running callbacks¶
OnFreePreUpdate and OnFreePostUpdate run once per rendered frame instead of on the
fixed step. They are disabled unless Enable Free Step Update Scripts is turned on in
Settings → Scene → Scripts, and most scripts do not need them.
How free-running callbacks behave
OnFreePreUpdate runs before the frame's
fixed phases, and OnFreePostUpdate runs
after them. A single frame can drive zero, one, or several fixed steps, so these
callbacks are not synchronised with the per-step callbacks.
Their ts is the time since the last rendered frame, in seconds. It is tied to the
refresh rate and varies with frame time, unlike the fixed ts of the per-step
callbacks. They exist for work that must run at the frame rate instead of the fixed
step.
Where to go next¶
- Time Runners: runners, phases and the scene's time mode.
- Working with Components: reading and changing the components on an entity.
- Input & Controls: reading the keyboard reliably from fixed-step callbacks.