Files

13 KiB

id, try, try_select, icon, group, group_title, group_icon, group_order, title, order
id try try_select icon group group_title group_icon group_order title order
physics try/Body2D.aescene physics.Body2D cat.physics physics Physics 2D cat.physics 50 Physics 2D 1

Physics 2D

Aego simulates 2D rigid bodies with its own solver. A body is a node with Rigid Body 2D; colliders on that node and its children give it a shape; scripts react to contacts and query the world. Physics runs during Play and in aego run. In edit mode nothing moves, and the Scene View shows collider outlines and their problems.

Quick start: Create → Physics → Rigid Body gives a falling box, Create → Physics → Static Collider a floor for it. Press Play.


id: physics/units icon: view.grid parent: physics order: 1 title: Units and axes

Units and axes

Physics works in world units. One unit is whatever size you choose for your game; shapes between 0.1 and 10 units behave best. render.pixelsPerUnit in project.aego is used only for the default size of imported sprites, the default Camera2D.Zoom and Snap to Sprite; physics never reads it, so changing it does not change how anything falls.

Axes follow the 2D scene: +X right, +Y down, positive angles turn clockwise. Default gravity is (0, 9.81), pointing down the screen. Normals and velocities in events and queries use the same axes, so a floor under a body has a normal with a negative Y.


id: physics/components try: try/CircleCollider2D.aescene try_select: physics.CircleCollider2D icon: comp.rigidbody parent: physics order: 2 title: Components

Components

Component Purpose
Rigid Body 2D makes the node a body: static, kinematic or dynamic
Box / Circle / Capsule / Polygon / Edge Collider 2D shapes
Distance Joint 2D keeps a distance to the Target body, rigid or springy
Revolute Joint 2D pins to the Target body at Anchor, with optional limit and motor

Every collider has Offset, IsTrigger, Friction, Restitution and Density. Capsules lie along the node's local X axis; Length includes the caps. Polygons are convex with 3 to 8 points. Edge colliders are polylines for level geometry; Loop closes them, OneSided makes them solid only from the side the points wind towards (left-to-right points are solid from above).

Rigid Body 2D:

Field Meaning
Type static never moves, kinematic moves by velocity and ignores forces, dynamic reacts to everything
MassMode, Mass auto takes mass from collider density, override uses Mass
GravityScale multiplier of the project gravity
LinearDamping, AngularDamping slow the body down over time
FixedRotation the body never turns
Bullet swept collision for small fast bodies
AllowSleep let the body rest when it stops
Interpolate draw between physics steps; scripts still see the exact pose
Layer, Mask see Layers
Velocity, AngularVelocity, Awake live values during Play, read-only

id: physics/hierarchy icon: panel.hierarchy parent: physics order: 3 title: Bodies and hierarchy

Bodies and hierarchy

A collider belongs to the nearest node at or above it that has a Rigid Body 2D. One body can therefore be built from several child nodes, each with its own collider; mass, centre of mass and inertia come from all of them. A collider with no body above it becomes a static body of its own.

The collider's position, rotation and uniform scale relative to its body are baked into the shape. Boxes and polygons also take non-uniform scale; circles and capsules need a uniform one and report PHY001 otherwise. Nodes under a 3D parent are not simulated (PHY005).

The transform of a moving body belongs to physics. Write it from FixedUpdate or through Teleport and it is applied as a teleport at the next step, keeping the velocity. A write from Update is reported once per body (PHY007) and applied at the next step. Static and kinematic bodies follow their node every step. Reparenting a moving body during Play recreates it with the same world pose and velocity (PHY006).


id: physics/layers icon: view.overlays parent: physics order: 4 title: Layers

Layers

Up to 32 named layers and the pairs that collide are declared in project.aego or in Project Settings → Physics:

physics {
  layers=[Default, Ground, Player, Enemy]
  collide {
    Player=[Ground, Enemy]
    Enemy=[Ground, Player]
  }
}

The matrix is symmetric: Player=[Enemy] also lets enemies hit players. Without a collide block every layer collides with every other. An unknown layer name in collide is a load error.

A body stores its layer as an index, so renaming a layer keeps every body on it; clearing a name keeps the index. Two shapes collide when both bodies' Mask accept the other's layer and the matrix allows the pair. Changing a layer or mask during Play ends the contacts it forbids in the next step.


id: physics/events icon: panel.events parent: physics order: 5 title: Events

Events

Declare a method with one of these names in any script on the body node or on the collider node:

func OnCollisionEnter(other NodeRef, c physics.Contact)
func OnCollisionStay(other NodeRef, c physics.Contact)
func OnCollisionExit(other NodeRef, c physics.Contact)
func OnTriggerEnter(other NodeRef)
func OnTriggerExit(other NodeRef)

Both participants get the event, each from its own side. other is the other body's node; c.Normal points from the other body into the receiver, so a floor under you reports c.Normal.Y < 0. c.SelfCollider and c.OtherCollider name the collider nodes. Events run after the physics step, before script.events_fixed ends the fixed tick.

OnCollisionStay runs every step while two bodies touch, and only when some script handles it; prefer Enter/Exit counters. Exit also comes when a body is destroyed or disabled; other.IsAlive() is then false.

Destroying nodes inside a handler is safe: the removal happens after all handlers ran.


id: physics/scripting icon: file.script parent: physics order: 6 title: Scripting

Scripting

Body methods are called on the component:

body := node.Get<Body2D>()
v := body.Velocity
body.SetVelocity(Vec2{x * Speed, v.Y})
body.ApplyImpulse(JumpImpulse)
Method
ApplyForce(f), ApplyForceAt(f, p), ApplyTorque(t) push during the next step, call from FixedUpdate
ApplyImpulse(j), ApplyImpulseAt(j, p) change the velocity at once, scaled by mass
SetVelocity(v), SetAngularVelocity(w)
MoveTo(p, angle) drive a kinematic body to a pose by the end of the next step
Teleport(p, angle) move without sweeping, velocity kept
WakeUp(), Sleep(), Mass()

Queries live in aego/physics. They ignore the caller's own body and skip triggers:

Function
Raycast(origin, dir, maxDist) RayHit closest hit
Linecast(from, to, mask) RayHit first hit on the layers in mask, -1 for all
RaycastAll(from, to, out) int fills out nearest first
OverlapPoint(p, out), OverlapCircle(c, r, out), OverlapBox(c, size, out) bodies touching the area
Gravity(), SetGravity(g)
Layer(name), LayerMask(name) layer index and mask bit by name

Functions that fill out write at most len(out) entries; size the slice once with append. Queries work only during Play.


id: physics/settings icon: panel.settings parent: physics order: 7 title: Settings

Settings

Project Settings → Physics with the gravity and contact previews

Project Settings → Physics edits the physics block of project.aego: gravity, substeps, iterations, contact stiffness, sleep thresholds, layers and the matrix. An empty or zero field takes the engine default, shown greyed out. Substeps and both iteration counts accept 1 to 64. Changes apply at the next Play.

Tall free-standing stacks and fast motors need the stiff profile: substeps=8 and contactHertz=60, at about twice the solver cost. At the default 30 Hz with 4 substeps a free column stands up to about twelve boxes; bonded brick layers stand much higher.


id: physics/editor try: try/EdgeCollider2D.aescene try_select: physics.EdgeCollider2D icon: tool.move parent: physics order: 8 title: Editor tools

Editor tools

Collider outlines and contacts drawn over the Game View during Play

  • Handles. Select a node with a collider to drag its sides, radius, length or vertices; double-click an edge of a polygon to add a vertex, Alt-click a vertex to remove it. Joints show anchors on both bodies. Every drag is one undo step.
  • Snap to Sprite in the inspector of box, circle and capsule colliders fits the shape to the node's sprite.
  • Physics menu. Debug Overlay with Shapes, Contacts, AABBs, Joints, Islands and Broadphase Tree. In edit mode only shapes are drawn.
  • Vectors (V in the Scene View) draws velocity, angular velocity, forces, contact impulses, gravity and script fields with @export(gizmo="vector"). Drag the tip of a field arrow to change the value.
  • Game View → Overlays draws the same layers over the running game with the game camera.
  • Problems lists collider and joint errors with a link to the node; broken geometry blocks Play.
  • Profiler → Physics shows bodies, pairs, islands and stage timings during Play.

id: physics/lifecycle icon: panel.history parent: physics order: 9 title: Lifecycle

Lifecycle

What happens to bodies, shapes and contact events when the scene changes during Play.

Action during Play Result
Destroy a body node its shapes leave the world at the next step, Exit events in the same step
Destroy a collider child the shape is removed, mass and inertia recomputed
Disable a node all shapes below it switch off with Exit events; enabling brings Enter at the next step
Remove Rigid Body 2D child colliders become static bodies
Remove a collider the shape is removed with Exit
Change layer or mask forbidden pairs end in the same step
Change a trigger flag or the geometry contacts of the shape end, new ones begin at the next step
Add a body or collider picked up at the next step, starting at rest
Reparent a moving body recreated with world pose and velocity, PHY006
Script hot reload the world keeps running, handlers are rebound by name
Native rebuild the play world is recreated with the editor
Stop the world is destroyed without Exit events

id: physics/world icon: vec.gravity parent: physics order: 10 title: World

World

modules/physics/world is the solver under the components, usable on its own from Go (see demos/physics2d).

Step(dt) collides once and then solves in Config.Substeps substeps (4 by default): each substep applies gravity, solves contacts as stiff springs that push overlapping shapes apart at most ContactPushVelocity units per second, moves the bodies and relaxes the push so it does not turn into a bounce. The engine steps physics at the fixed rate (FixedHz, 60 by default), never with the frame delta.

A body moves at most MaxTranslationPerStep units and turns at most MaxRotationPerStep radians per step. Fast small bodies should set Bullet: their contacts look ahead by the distance they travel in one step.

Every definition is validated: NaN, infinities, negative sizes, concave polygons and zero-length segments are rejected with an error and the world stays unchanged.

Material Meaning Mix of two shapes
Friction 0 is ice, 1 is rubber sqrt(a·b)
Restitution 0 stops, 1 bounces back at full speed max(a, b)
Density mass per square unit —

Bounces slower than RestitutionThreshold are not restituted. A group of touching bodies falls asleep when all of them move slower than SleepLinear and SleepAngular for SleepTime seconds; a contact with an awake body, a force, an impulse, a teleport or a new joint wakes it.

The same binary on the same CPU with the same sequence of calls produces bit-identical results; Snapshot() and Restore() capture the whole state for replays and rollback.


id: physics/pitfalls icon: status.warning parent: physics order: 11 title: Common mistakes

Common mistakes

  • Moving a dynamic body with SetPosition from Update. Use SetVelocity, forces or Teleport from FixedUpdate.
  • Reading input edges in FixedUpdate. input.Pressed is true for one frame, and a frame may have zero or two fixed steps. Read it in Update and act in FixedUpdate, or use input.Down.
  • Circle on a stretched node. Circles and capsules need a uniform scale. Scale the collider fields instead.
  • Objects falling through thin floors. Mark small fast bodies as Bullet, or make the floor thicker.
  • Wobbling tall towers. Use the stiff profile, stagger the boxes like bricks, or build the tower as one body.
  • Nothing collides. Check both masks, the layer matrix, and that the node is 2D and not under a 3D parent.
  • Units that feel floaty. A 64-pixel sprite at zoom 64 is one unit; gravity 9.81 assumes a unit is about a metre.