# annotations.ludic — the annotation-first style. Behaviour is expressed with # @-decorators that desugar to plain handlers, queries and expressions, so the # properties stay pure data and the data-oriented model is untouched. @Handles(Move) program RPG2D { property Transform { x: int = 0, y: int = 0, scale: int = 1 } property Velocity { dx: int = 0 dy: int = 0 @Computed speed2: int = dx * dx + dy * dy # derived; no storage, inlined at use } model Actor { Transform, Velocity } # A constructor: every Actor starts visible. Runs at spawn with the model's # properties bound by name — no per-frame cost, no observer machinery. @OnSpawn(Actor) handler InitActor { Transform.scale = 2 } handler Spawn phase Start { spawn Actor { Transform { x: 0 } Velocity { dx: 3, dy: 4 } } spawn Actor { Transform { x: 0 } Velocity { dx: 0, dy: 0 } } } # Move every Actor whose scale is positive and that is actually moving. The # query is the decorator; each bound property is addressed by its own name. @Queries(these: [Transform{scale > 0}, Velocity{dx > 0 or dy > 0}], on: Actor) handler Move phase Update { Transform.x = Transform.x + Velocity.dx Transform.y = Transform.y + Velocity.dy } handler Report phase Render { for (t, v) in query [Transform, Velocity] { print(t.x); print(v.speed2) } quit() } }