plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
db32e90
— Peter John
2026-11-02T18:28:00+05:30
README: Scene z-index, sortChildren, culling and the layer recipe
README.md
CHANGED
|
@@ -1045,6 +1045,24 @@ Games run in the browser on Plum's own WebGPU renderer (`plum-game/web/plum_brid
|
|
|
1045
1045
|
|
|
1046
1046
|
**`std/Scene`** is a scene-graph library written in Plum (see [`plum-examples/scene.plum`](plum-examples/scene.plum)): a tree of `Node`s (group, sprite, rect, circle, text) under a `Stage`, with parent-relative position, rotation, scale and colour, per-node `act` behaviours, a camera and hit testing; its demo renders a minimap into a texture with `textureCreate` and `renderTarget`. Use it for UI and other hierarchical scenes, where moving a parent should move everything in it. For a large world, keep the game objects in flat records and lists instead (for example `enum Entity = Unit | House` with an `update` and a `draw` that the enum dispatches to its variants) and draw them directly through `std/Game`; a tree of thousands of nodes costs a closure call and a matrix composition per node every frame.
|
|
1047
1047
|
|
|
1048
|
+
`std/Scene` follows libGDX Scene2D for draw order and culling. A node's z-index is its position in its parent's child list (draw order is list order, hit testing goes in reverse):
|
|
1049
|
+
|
|
1050
|
+
```plum
|
|
1051
|
+
n.zIndex() # index among its siblings, -1 without a parent
|
|
1052
|
+
n.setZIndex(0) # move within the parent (clamped to 0..length-1)
|
|
1053
|
+
n.toFront() # last child: drawn on top, hit first
|
|
1054
|
+
n.toBack() # first child: drawn first
|
|
1055
|
+
|
|
1056
|
+
world.sortChildren(|a, b| a.y < b.y) # stable, in place, no allocation once warm
|
|
1057
|
+
world.setCullingArea(cam.x, cam.y, viewW, viewH) # in world's own coordinates
|
|
1058
|
+
world.clearCullingArea()
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
`sortChildren(before)` is a natural merge sort with a scratch list kept on the node: a list that is already sorted costs n - 1 comparisons and a nearly sorted one (a y-sorted layer re-sorted every frame) about 2n, with O(n log n) as the worst case; equal keys keep their order, so ties do not flicker. `setCullingArea` makes a group skip each direct child whose box (position and size, scaled about its origin; rotation ignored) lies outside the rectangle, in both `draw` and `hit`, with the child's whole subtree; children with no size (plain groups) are never culled. In [`plum-game/web-test/BENCHMARK.md`](plum-game/web-test/BENCHMARK.md) a 20,000-sprite y-sorted layer costs 1.15 ms per frame with culling and 4.20 ms without.
|
|
1062
|
+
|
|
1063
|
+
A layered world (a layer recipe for a large map) is a few groups under the stage root, drawn in order: `terrain` (static, culled), `world` (y-sorted every frame, culled), `effects` (culled) and `ui` (not culled, in screen space with a second `Stage` or camera). Each frame: `world.sortChildren(|a, b| a.y < b.y)`, then `setCullingArea` on `terrain`, `world` and `effects` from the camera view.
|
|
1064
|
+
|
|
1065
|
+
|
|
1048
1066
|
A game declares three exports. `G` is any record and holds all game state (there are no globals):
|
|
1049
1067
|
|
|
1050
1068
|
```plum
|