plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


9cfafea — Peter John 2026-11-02T20:47:29+05:30
game_scene: keep animating at game over
Files changed (1) hide show
  1. plum-examples/game_scene.plum +48 -9
plum-examples/game_scene.plum CHANGED
@@ -90,7 +90,7 @@ fun mineCount(score: Int) -> Int =
90
90
  # (origin at the middle of the box, so `rotation` turns it about its centre).
91
91
 
92
92
  # The player. `ax` and `ay` are the input axes (-1..1) for the next `act`.
93
- record Ship(Actor, vx: Float, vy: Float, ax: Float, ay: Float, hurt: Float, clock: Float, tex: Int) =
93
+ record Ship(Actor, vx: Float, vy: Float, ax: Float, ay: Float, hurt: Float, clock: Float, tex: Int, live: Bool) =
94
94
 
95
95
  fun create(sheet: Int, x: Float, y: Float) -> Ship =
96
96
  size := Rules.Cell * Rules.Zoom
@@ -99,12 +99,14 @@ record Ship(Actor, vx: Float, vy: Float, ax: Float, ay: Float, hurt: Float, cloc
99
99
  scaleX: 1.0, scaleY: 1.0, rotation: 0.0, color: Color.White, visible: true,
100
100
  children: List[Actor](), parent: null, scratch: List[Actor](),
101
101
  cull: false, cullX: 0.0, cullY: 0.0, cullW: 0.0, cullH: 0.0,
102
- vx: 0.0, vy: 0.0, ax: 0.0, ay: 0.0, hurt: 0.0, clock: 0.0, tex: sheet)
102
+ vx: 0.0, vy: 0.0, ax: 0.0, ay: 0.0, hurt: 0.0, clock: 0.0, tex: sheet, live: true)
103
103
 
104
104
  # Accelerates by the input axes, applies drag, keeps the ship in the arena and
105
105
  # blinks it while it is hurt (the blink is just `visible`).
106
106
  fun act(self, dt: Float) =
107
107
  self.clock = self.clock + dt
108
+ if !self.live
109
+ return
108
110
  self.hurt = {self.hurt - dt}.max(0.0)
109
111
  self.vx = self.vx + self.ax * Rules.Thrust * dt
110
112
  self.vy = self.vy + self.ay * Rules.Thrust * dt
@@ -137,7 +139,7 @@ record Ship(Actor, vx: Float, vy: Float, ax: Float, ay: Float, hurt: Float, cloc
137
139
  drawSpriteFrame(m, alpha, self.width, self.height, self.color, self.tex, frame * Rules.Cell, 0.0, Rules.Cell, Rules.Cell)
138
140
 
139
141
  # A glowing orb drifting about. `phase` offsets its animation from the other orbs.
140
- record Orb(Actor, vx: Float, vy: Float, phase: Float, clock: Float, tex: Int) =
142
+ record Orb(Actor, vx: Float, vy: Float, phase: Float, clock: Float, tex: Int, live: Bool) =
141
143
 
142
144
  fun create(sheet: Int, phase: Float, at: Motion) -> Orb =
143
145
  size := Rules.Cell * Rules.Zoom
@@ -146,7 +148,7 @@ record Orb(Actor, vx: Float, vy: Float, phase: Float, clock: Float, tex: Int) =
146
148
  scaleX: 1.0, scaleY: 1.0, rotation: 0.0, color: Color.White, visible: true,
147
149
  children: List[Actor](), parent: null, scratch: List[Actor](),
148
150
  cull: false, cullX: 0.0, cullY: 0.0, cullW: 0.0, cullH: 0.0,
149
- vx: at.vx, vy: at.vy, phase: phase, clock: 0.0, tex: sheet)
151
+ vx: at.vx, vy: at.vy, phase: phase, clock: 0.0, tex: sheet, live: true)
150
152
 
151
153
  fun motion(self) -> Motion =
152
154
  Motion(x: self.x, y: self.y, vx: self.vx, vy: self.vy)
@@ -159,6 +161,8 @@ record Orb(Actor, vx: Float, vy: Float, phase: Float, clock: Float, tex: Int) =
159
161
 
160
162
  fun act(self, dt: Float) =
161
163
  self.clock = self.clock + dt
164
+ if !self.live
165
+ return
162
166
  m := self.motion()
163
167
  drift(m, Rules.OrbRadius, dt)
164
168
  self.place(m)
@@ -174,7 +178,7 @@ record Orb(Actor, vx: Float, vy: Float, phase: Float, clock: Float, tex: Int) =
174
178
  drawSpriteFrame(m, alpha, self.width, self.height, self.color, self.tex, frame * Rules.Cell, Rules.Cell, Rules.Cell, Rules.Cell)
175
179
 
176
180
  # A spinning mine drifting about.
177
- record Mine(Actor, vx: Float, vy: Float, clock: Float, tex: Int) =
181
+ record Mine(Actor, vx: Float, vy: Float, clock: Float, tex: Int, live: Bool) =
178
182
 
179
183
  fun create(sheet: Int, at: Motion) -> Mine =
180
184
  size := Rules.Cell * Rules.Zoom
@@ -183,7 +187,7 @@ record Mine(Actor, vx: Float, vy: Float, clock: Float, tex: Int) =
183
187
  scaleX: 1.0, scaleY: 1.0, rotation: 0.0, color: Color.White, visible: true,
184
188
  children: List[Actor](), parent: null, scratch: List[Actor](),
185
189
  cull: false, cullX: 0.0, cullY: 0.0, cullW: 0.0, cullH: 0.0,
186
- vx: at.vx, vy: at.vy, clock: 0.0, tex: sheet)
190
+ vx: at.vx, vy: at.vy, clock: 0.0, tex: sheet, live: true)
187
191
 
188
192
  fun motion(self) -> Motion =
189
193
  Motion(x: self.x, y: self.y, vx: self.vx, vy: self.vy)
@@ -196,6 +200,8 @@ record Mine(Actor, vx: Float, vy: Float, clock: Float, tex: Int) =
196
200
 
197
201
  fun act(self, dt: Float) =
198
202
  self.clock = self.clock + dt
203
+ if !self.live
204
+ return
199
205
  m := self.motion()
200
206
  drift(m, Rules.MineRadius, dt)
201
207
  self.place(m)
@@ -336,18 +342,27 @@ fun sync(w: World) =
336
342
  w.lifeIcons.at(i).visible = i < w.lives
337
343
  w.overlay.visible = w.over
338
344
 
345
+ # Lets the actors move (while the game runs) or only animate (once it is over).
346
+ fun setLive(w: World, live: Bool) =
347
+ w.ship.live = live
348
+ for i := range w.orbList.length()
349
+ w.orbList.at(i).live = live
350
+ for i := range w.mineList.length()
351
+ w.mineList.at(i).live = live
352
+
339
353
  fun overlaps(ax: Float, ay: Float, ra: Float, bx: Float, by: Float, rb: Float) -> Bool =
340
354
  Math.hypot(ax - bx, ay - by) < ra + rb
341
355
 
342
356
  # One simulation step: every actor acts through the stage, then the rules look at
343
- # the result. Does nothing once the game is over.
357
+ # the result. Once the game is over the actors only animate; nothing moves or scores.
344
358
  fun step(w: World, ax: Float, ay: Float, dt: Float) =
345
359
  w.clock = w.clock + dt
346
- if w.over
360
+ setLive(w, !w.over)
347
- return
348
361
  w.ship.ax = ax
349
362
  w.ship.ay = ay
350
363
  w.stage.act(dt)
364
+ if w.over
365
+ return
351
366
  ship := w.ship
352
367
  for i := range w.orbList.length()
353
368
  orb := w.orbList.at(i)
@@ -544,6 +559,30 @@ test "the game ends at zero lives and then ignores steps"
544
559
  step(w, 1.0, 0.0, 0.5)
545
560
  assert w.ship.x == x
546
561
 
562
+ test "after game over nothing moves but the animations keep running"
563
+ w := emptyWorld()
564
+ w.lives = 1
565
+ mine := w.mineList.at(0)
566
+ mine.place(Motion(x: w.ship.x, y: w.ship.y, vx: 10.0, vy: 0.0))
567
+ step(w, 0.0, 0.0, 0.016)
568
+ assert w.over
569
+ x := mine.x
570
+ rot := mine.rotation
571
+ clock := mine.clock
572
+ orbClock := w.orbList.at(0).clock
573
+ star := Star.create(0)
574
+ w.stage.root.children.at(1).add(star)
575
+ for i := range 10
576
+ step(w, 1.0, 0.0, 0.1)
577
+ assert mine.x == x
578
+ assert mine.rotation == rot
579
+ assert w.ship.x == Rules.ArenaW / 2.0
580
+ assert !w.ship.visible
581
+ assert mine.clock > clock + 0.9
582
+ assert w.orbList.at(0).clock > orbClock + 0.9
583
+ assert star.clock > 0.9
584
+ assert w.score == 0
585
+
547
586
  test "restart resets the run and keeps the best score"
548
587
  w := emptyWorld()
549
588
  w.score = 90