Behavior owns logic
Attach a Python class to an Entity, override the callbacks you need, and keep state close to the thing it controls.
Learn the scripting lifecycle and turn an idea into playable behavior with practical examples and a complete reference.
THE MODEL
Attach a Python class to an Entity, override the callbacks you need, and keep state close to the thing it controls.
Compose transforms, renderers, colliders, audio, UI, and your own data through Modules.
Query Entities, manage hierarchy, transition Stages, and use named project definitions such as tags and layers.
LEARN BY DOING
Frame-rate independent movement with named axes.
from IronGrid import Behavior, Input, Vector3
class PlayerMover(Behavior):
speed = 5.0
def update(self, dt):
move = Vector3(Input.get_axis("Horizontal"), 0,
Input.get_axis("Vertical"))
self.transform.position += move * self.speed * dtInstantiate an Archetype and keep its root Entity.
from IronGrid import Behavior, Archetypes
class Spawner(Behavior):
def start(self):
made = Archetypes.instantiate(self,
"Assets/Archetypes/Crate.archetype",
position=(0, 2, 0))
self.crate = made[0] if made else NoneUse callbacks instead of polling every frame.
from IronGrid import Behavior, Tags
class Pickup(Behavior):
def on_trigger_3d(self, event):
if Tags.has(self, event.other_entity, "Player"):
print("Collected")REFERENCE
Core
The base class for scripts attached through a Script Binding. Override only the lifecycle and event callbacks your script needs.
Use case
Player controllers, interactables, game rules, UI presenters, and any stateful logic owned by an Entity.from IronGrid import Behavior, Input, KeyCode
class DoorController(Behavior):
speed = 2.0
def update(self, dt):
if Input.get_key_down(KeyCode.E):
self.transform.position.y += self.speed * dtclass Behavior(entity=None, engine=None, _data=None)Base type for an attached gameplay script; the runtime supplies its Entity, Stage, and exposed field values.
soft_show(default=None) · soft_hide(default=None)Controls whether a field appears in Properties while retaining its Python default.
awake()Called once when the script instance is created, before start().
start()Called once before the first gameplay update.
update(dt: float)Called every rendered frame; dt is elapsed time in seconds.
fixed_update(dt: float)Called on the fixed simulation step; use for physics-affecting logic.
late_update(dt: float)Called after normal updates; useful for cameras and dependent transforms.
on_enable() · on_disable()Called when the Script Binding enters or leaves the enabled state.
on_destroy()Called before the script instance is removed.
on_collision_2d/3d(event) · on_trigger_2d/3d(event)Event-driven collision and trigger delivery for the attached Entity.
on_key_down/up(event) · on_button_down/up(event) · on_mouse_down/up(event)Edge-triggered keyboard, action, and mouse events.
on_ui_click(event) · on_ui_value_changed(event) · on_ui_text_changed(event) · on_ui_focus_changed(event)Events from interactive UI modules.
on_animator_state_changed(event)Called when an Animator changes state.
self.transform -> Transform | None · self.entity_ref -> Entity | NoneCurated wrappers bound to the attached Entity.
find_entity(name: str) -> Entity | NoneFinds the first exact-name match in the active Stage.
get_module(type) · add_module(value) · remove_module(type)Convenient module access scoped to the attached Entity.
Core
Read the active Stage, resolve its camera, change hierarchy, or request a Stage transition.
Use case
Level flow, camera-aware systems, and hierarchy changes that span multiple entities.from IronGrid import Behavior, Stage
class ExitPortal(Behavior):
next_stage = "Stages/Level02.stage"
def on_trigger_3d(self, event):
Stage.load_stage(self, self.next_stage)Stage.current(context)Returns the active Stage for a Behavior, Entity, or Stage context.
Stage.name(context) -> strReturns the active Stage name.
Stage.active_camera(context) -> int | NoneReturns the active camera Entity id.
Stage.load(context, name_or_path) -> bool · Stage.load_stage(...) -> boolRequests a transition to another Stage.
Stage.set_parent(context, child, parent=None, *, keep_world=True) -> boolReparents an Entity and optionally preserves world placement.
World
Create, query, rename, enable, destroy, and traverse Entities.
Use case
Spawning projectiles, locating named anchors, querying populations, and organizing runtime hierarchies.from IronGrid import Behavior, Entities
class Spawner(Behavior):
def start(self):
self.light = Entities.create(self, name="Warning Light",
parent=self.entity, position=(0, 2.5, 0))Entities.get(context, entity=None) -> Entity | NoneWraps an Entity id or Entity-like value.
Entities.create(context, *, name='Entity', parent=None, position=None, rotation=None, scale=None, enabled=True) -> Entity | NoneCreates one Entity with optional hierarchy and local transform values.
Entities.create_many(context, specs) -> list[Entity]Creates Entities from specification dictionaries.
Entities.destroy(context, entity=None) -> bool · destroy_many(context, entities) -> intDestroys one or many Entities.
Entities.all(context) -> list[Entity] · Entities.ids(context) -> list[int]Enumerates the active Stage.
Entities.with_module(context, *types) -> list[Entity]Returns Entities that contain every requested module type.
Entities.ids_with_module(context, *types) -> list[int]Id-only module query.
find_by_name(context, name) · find_all_by_name(context, name) · find_by_prefix(context, prefix)Exact-name and prefix lookup.
Entities.name(context, entity=None) -> str · set_name(..., value='Entity') -> boolReads or changes an Entity name.
Entities.enabled(context, entity=None) -> bool · set_enabled(..., value=True) -> boolReads or changes enabled state.
Entities.children(context, entity=None) -> list[Entity] · parent(...) -> Entity | NoneTraverses immediate hierarchy relationships.
Entities.set_parent(context, child, parent=None, *, keep_world=True) -> boolReparents an Entity.
Entity.eid · Entity.transform · get_module · add_module · remove_module · get_child · get_childrenObject-oriented wrapper for one Entity.
World
Read and write local transforms, including efficient batch operations.
Use case
Single-Entity movement, crowds, pickups, procedural layouts, and synchronized motion.from IronGrid import Behavior, Transforms
class Bob(Behavior):
def update(self, dt):
Transforms.translate(self, delta=(0, 0.15 * dt, 0))Transforms.get(context, entity=None) -> Transform | NoneReturns one bound Transform.
position(...) -> Vector3 · set_position(..., value=(0,0,0)) -> boolReads or writes local position.
positions(context, entities=None) -> dict[int, Vector3] · set_positions(context, values) -> intBatch local position access.
translate(..., delta=(0,0,0)) -> bool · translate_many(context, values) -> intOffsets one or many local positions.
rotation(...) -> Vector3 · set_rotation(..., value=(0,0,0)) -> boolReads or writes local Euler rotation in degrees.
rotations(context, entities=None) -> dict[int, Vector3] · set_rotations(context, values) -> intBatch local rotation access.
scale(...) -> Vector3 · set_scale(..., value=(1,1,1)) -> boolReads or writes local scale.
scales(context, entities=None) -> dict[int, Vector3] · set_scales(context, values) -> intBatch local scale access.
world_position(context, entity=None) -> Vector3 · world_matrix(...) -> list[float]Resolved world-space position and matrix.
name · enabled · position · local_position · rotation · scaleMutable properties on one bound Transform.
set_rotation_deg(x,y,z) · set_rotation_quat(x,y,z,w)Explicit Euler-degree and quaternion setters.
World
Read, add, remove, test, and patch gameplay-facing modules.
Use case
Changing rendering, physics, UI, camera, light, or gameplay data.from IronGrid import Behavior, Modules
from IronGrid.modules import LightModule
class Pulse(Behavior):
def start(self):
Modules.patch(self, LightModule, {"intensity": 4.0})Modules.get(context, type, entity=None) · get_many(context, type, entities=None)Reads one module or a dictionary keyed by Entity id.
Modules.add(context, module, entity=None) · remove(context, type, entity=None) -> boolAdds or removes a module.
Modules.has(context, type, entity=None) · has_many(context, type, entities=None)Tests module presence.
Modules.patch(context, type, data, entity=None) · patch_many(context, type, values) -> intUpdates selected fields on one or many modules.
Transform · CameraModule · LightModule · EnvironmentModule · TagsModuleSpatial, camera, lighting, environment, and classification data.
MeshFilter · MeshRenderer · MaterialMesh, renderer, and material state.
Canvas · RectTransform · UIImage · UIPanel · UIText · Text3DLayout and visual UI modules.
UIButton · UIInputField · UICheckbox · UISlider · UIProgressBarInteractive controls that emit Behavior UI callbacks.
RigidBody2D · BoxCollider2D · CircleCollider2DPublic 2D body and collider types.
RigidBody · BoxCollider · SphereCollider · CapsuleCollider · CylinderCollider · ColliderSurfacePublic 3D body, shape, and surface types.
Gameplay
Poll keyboard, mouse, named actions, axes, cursor state, and relative motion.
Use case
Named controls for players, raw keys for tools, and relative mouse mode for first-person camera look.from IronGrid import Behavior, Input, KeyCode
class PlayerLook(Behavior):
def start(self):
Input.set_mouse_capture(True)
def update(self, dt):
dx, dy = Input.get_mouse_delta()
if Input.get_key_down(KeyCode.ESCAPE):
Input.set_mouse_capture(False)get_key(key) · get_key_down(key) · get_key_up(key)Held, pressed-edge, and released-edge key state.
get_button(name) · get_button_down(name) · get_button_up(name)Held and edge state for named actions.
get_axis(name) -> float · set_axis(name, positive, negative)Reads or defines a named axis.
set_button(name, keys=None, mouse_buttons=None, gamepad_buttons=None)Defines a named cross-device action.
get_mouse_button(button) · get_mouse_button_down(button) · get_mouse_button_up(button)Held and edge states for MouseButton values.
get_mouse_position() · get_mouse_viewport_size() · get_mouse_delta()Viewport position, viewport dimensions, and per-frame relative motion.
set_mouse_capture(bool) · get_mouse_capture() · is_mouse_capture_requested()Requests and inspects gameplay mouse capture.
set_cursor_visible(bool) · get_cursor_visible() · set_cursor_locked(bool) · set_relative_mouse_mode(bool)Cursor visibility, locking, and relative input.
A-Z · digits · arrows · SPACE · ENTER · ESCAPE · modifiersPortable key constants.
LEFT · MIDDLE · RIGHT · X1 · X2Portable mouse button constants.
Gameplay
2D and 3D queries, body control, collision events, and trigger events.
Use case
Weapons, character clearance, areas of effect, impacts, and event-driven interactions.from IronGrid import Behavior, Physics
class Weapon(Behavior):
def fire(self, origin, direction):
hits = Physics.raycast_3d(self, origin, direction,
max_distance=120.0, include_triggers=False)
if hits:
Physics.add_impulse_3d(self, hits[0].entity, direction * 18)raycast_3d(context, origin, direction, max_distance=..., **filter) · raycast_3d_many(context, rays)Single or batch ray queries.
sphere_cast_3d(...) · box_cast_3d(...) · capsule_cast_3d(...)Sweeps a volume through space.
overlap_sphere_3d(...) · overlap_box_3d(...) · overlap_capsule_3d(...)Finds bodies inside a volume.
raycast_2d(context, origin, direction, max_distance=..., **filter) · raycast_2d_many(context, rays)Single or batch 2D ray queries.
overlap_circle_2d(...) · overlap_box_2d(...)Finds 2D bodies inside a shape.
collision_layer · collision_mask · include_triggers · all_hitsOptional named-layer and result controls accepted by query APIs.
set_linear_velocity_2d(..., velocity=(0,0)) · linear_velocity_2d(...)Writes or reads planar body velocity.
add_force_2d(..., force=(0,0)) · add_impulse_2d(..., impulse=(0,0))Continuous force and instantaneous impulse.
wake_body_2d(...) · teleport_body_2d(..., position, rotation_degrees=0, preserve_velocity=True)Wakes or explicitly teleports a 2D body.
add_force_3d(..., force=(0,0,0)) · add_impulse_3d(..., impulse=(0,0,0))Continuous force and instantaneous impulse.
wake_body_3d(context, entity=None) -> boolWakes a sleeping 3D body.
collisions_2d/3d(context) · triggers_2d/3d(context)Returns current physics event rows.
collisions_for(context, entity=None, dimension=3) · triggers_for(...)Filters current events to one Entity.
Gameplay
Tags classify gameplay meaning; layers define physics filtering.
Use case
Semantic queries such as Enemy or Pickup, plus precise collision rules.from IronGrid import Behavior, Tags, Layers
class Hazard(Behavior):
def start(self):
Layers.set_entity_layer(self, self.entity, "Hazards")
def on_trigger_3d(self, event):
if Tags.has(self, event.other_entity, "Player"):
print("Damage player")Tags.primary(...) · Tags.set_primary(..., value='Untagged')Reads or writes the single primary tag.
Tags.get(...) · Tags.set(..., values=()) · Tags.add(..., *values) · Tags.remove(..., *values)Reads or changes all tags.
Tags.has(..., value) · Tags.entities(context, value) · Tags.ids(context, value)Tests or queries by tag.
Tags.defined(context=None) · Tags.define(context, *values)Reads or extends project tag definitions.
Layers.names(context=None) · Layers.define(context, name, index=None)Reads or defines named collision layers.
Layers.index(context, layer) · bit(...) · name(...) · mask(context, *layers)Converts names, indices, bits, and masks.
entity_layer(...) · entity_layer_name(...) · set_entity_layer(..., layer='Default')Reads or assigns an Entity layer.
entity_collision_mask(...) · set_entity_collision_mask(..., layers_or_mask=None)Reads or assigns layers an Entity may collide with.
Gameplay
Instantiate serialized authored assets with optional root overrides.
Use case
Enemies, projectiles, pickups, effects, and reusable authored hierarchies.from IronGrid import Behavior, Archetypes
class WaveSpawner(Behavior):
def start(self):
spawned = Archetypes.instantiate(self,
"Assets/Archetypes/Drone.archetype",
position=(8, 1.5, -4), name="Drone 01")Archetypes.instantiate(context, path, *, position=None, rotation=None, scale=None, name=None) -> list[Entity]Instantiates one asset and returns spawned Entities, root first.
Archetypes.instantiate_many(context, paths, **overrides) -> list[Entity]Instantiates multiple asset paths with shared root overrides.
Gameplay
Frame timing plus Stage-driven one-shot and repeating callbacks.
Use case
Frame-rate independent motion, cooldowns, delayed actions, and repeating gameplay events.from IronGrid import Behavior, Time, Timers
class AutoClose(Behavior):
def start(self):
self.handle = Timers.after(self, 2.5, self.close)
def update(self, dt):
self.transform.rotation.y += 45 * Time.delta_time
def close(self): print("Closing")Time.delta_time · Time.elapsed_time · Time.fixed_delta_timeRendered-frame delta, accumulated time, and fixed simulation step in seconds.
Timers.after(context, seconds, callback) -> TimerHandle | NoneSchedules a one-shot callback.
Timers.every(context, seconds, callback) -> TimerHandle | NoneSchedules a repeating callback.
Timers.cancel(handle) · handle.cancel()Cancels a timer safely.
handle.active -> boolWhether a TimerHandle is still active.
Media
Control clips and Animator state through the public SDK.
Use case
Direct clip playback and parameter-driven character state machines.from IronGrid import Animation, Behavior
class CharacterMotion(Behavior):
def start(self): Animation.play_state(self.entity, "Idle")
def set_running(self, speed):
Animation.set_parameter(self.entity, "speed", speed)get_animation(entity) · require_animation(entity) · get_animator(entity) · require_animator(entity)Optional getters and required getters that report a missing module.
play(entity, clip=None) · pause(entity) · stop(entity)Controls direct clip playback.
set_time(entity, seconds) · set_speed(entity, speed) · set_loop(entity, enabled)Seeks and configures playback.
play_state(entity, state_name) · set_parameter(entity, name, value)Changes Animator state or parameters.
Media
Play Entity AudioSources, fire one-shots, and control source or bus state.
Use case
Authored looping or spatial sources, transient effects, and mixer-style bus controls.from IronGrid import Audio, Behavior
class ImpactSound(Behavior):
clip = "Assets/Audio/metal_hit.wav"
def on_collision_3d(self, event):
Audio.play_one_shot(self.clip, volume=0.85, bus_name="SFX")play_source(entity, volume_scale=1.0) · play_one_shot(clip_or_path, volume=1.0, bus_name='SFX')Plays an authored source or transient clip.
stop_source(entity) · pause_source(entity) · resume_source(entity)Controls source playback.
set_source_volume(entity, volume) · set_source_pitch(entity, pitch)Changes source gain or pitch.
set_bus_volume(bus_name, volume) · set_bus_mute(bus_name, muted)Controls a named audio bus.
Audio.stop_all() -> boolStops all active playback.
Tools
Log information and inspect supported script health telemetry.
Use case
Development logs, health panels, smoke checks, and locating slow or failing scripts.from IronGrid import Behavior, Debug, Diagnostics
class Probe(Behavior):
def update(self, dt):
if Diagnostics.exception_count(self):
Debug.error(Diagnostics.recent_exceptions(self, 5))Debug.log(*parts) · warning(*parts) · error(*parts)Writes normal, warning, or error log lines.
Diagnostics.script_snapshot(context) -> dictReturns the supported high-level script health snapshot.
Diagnostics.exception_count(context) -> intReturns the recorded script exception count.
Diagnostics.slow_scripts(context, limit=20) -> list[dict]Returns the slowest measured scripts.
Diagnostics.recent_exceptions(context, limit=20) -> list[dict]Returns recent public exception details.
Core
Small ergonomic vector types used throughout the scripting SDK.
Use case
Arithmetic, readable field access, and values passed to Transform and Physics helpers.from IronGrid import Vector3
forward = Vector3(0, 0, -1)
velocity = forward * 6.5
next_position = Vector3(2, 1, 4) + velocity * 0.016Vector2(x=0.0, y=0.0)Mutable two-element value type.
Vector3(x=0.0, y=0.0, z=0.0)Mutable three-element value type.
a + b · a - b · a * b · a / b · in-place formsElement-wise arithmetic; scalar values are broadcast.
vector.copy() · tuple(vector)Copies or unpacks vector values.
MODULE CATALOG
Transform, CameraModule, LightModule, EnvironmentModule, TagsModule
MeshFilter, MeshRenderer, Material
Canvas, RectTransform, UIImage, UIPanel, UIText, Text3D, UIButton, UIInputField, UICheckbox, UISlider, UIProgressBar
AudioClipRef
RigidBody2D, BoxCollider2D, CircleCollider2D
RigidBody, BoxCollider, SphereCollider, CapsuleCollider, CylinderCollider, ColliderSurface