petal

Specimen · bouncing-balls.ptl

Bouncing Balls

Gravity, elastic walls, and persistent state. Click the canvas to fling more.

physicsinteractive
bouncing-balls.ptl
compiling petal…

this sketch is interactive — click the canvas and use the mouse / arrow keys to play.

bouncing-balls.ptl
1// Bouncing Balls — click to add more balls.
2// Demonstrates state, frame timing, mouse input, and the drawing API.
3 
4state balls = []
5 
6let sw = float(screen_width())
7let sh = float(screen_height())
8let delta = dt()
9 
10// Seed with a few balls on first frame
11if len(balls) == 0 then
12 for i in range(0, 12) do
13 let f = float(i)
14 push(balls, {
15 x: 50.0 + f * 60.0,
16 y: 80.0 + f * 20.0,
17 vx: 80.0 + f * 15.0,
18 vy: 40.0 - f * 8.0,
19 r: 12.0 + f * 1.5,
20 cr: 80 + (i * 23) % 175,
21 cg: 120 + (i * 47) % 135,
22 cb: 200 - (i * 31) % 150
23 })
24 end
25end
26 
27// Add a ball on click
28if mouse_pressed(1) then
29 let mx = float(mouse_x())
30 let my = float(mouse_y())
31 push(balls, {
32 x: mx, y: my,
33 vx: random(-200.0, 200.0),
34 vy: random(-200.0, 0.0),
35 r: random(8.0, 28.0),
36 cr: int(random(80.0, 255.0)),
37 cg: int(random(80.0, 255.0)),
38 cb: int(random(80.0, 255.0))
39 })
40end
41 
42let gravity = 600.0
43 
44// Physics step
45let new_balls = []
46for b in balls do
47 let nvy = b.vy + gravity * delta
48 let nx = b.x + b.vx * delta
49 let ny = b.y + nvy * delta
50 let nvx = b.vx
51 
52 // Wall collisions
53 let final_vx = nvx
54 let final_x = nx
55 if nx - b.r < 0.0 then
56 final_x = b.r
57 final_vx = -nvx * 0.85
58 end
59 if nx + b.r > sw then
60 final_x = sw - b.r
61 final_vx = -nvx * 0.85
62 end
63 
64 let final_vy = nvy
65 let final_y = ny
66 if ny + b.r > sh then
67 final_y = sh - b.r
68 final_vy = -nvy * 0.85
69 end
70 if ny - b.r < 0.0 then
71 final_y = b.r
72 final_vy = -nvy * 0.85
73 end
74 
75 push(new_balls, {
76 x: final_x, y: final_y,
77 vx: final_vx, vy: final_vy,
78 r: b.r, cr: b.cr, cg: b.cg, cb: b.cb
79 })
80end
81balls = new_balls
82 
83// === Drawing ===
84clear(14, 16, 28)
85 
86for b in balls do
87 // soft outer halo
88 draw_circle(int(b.x), int(b.y), int(b.r + 3.0), b.cr / 4, b.cg / 4, b.cb / 4)
89 draw_circle(int(b.x), int(b.y), int(b.r), b.cr, b.cg, b.cb)
90 draw_circle(int(b.x - b.r * 0.3), int(b.y - b.r * 0.3), int(b.r * 0.35),
91 min(255, b.cr + 60), min(255, b.cg + 60), min(255, b.cb + 60))
92end
93 
94draw_text("Bouncing Balls — click to add", 16, 12, 14, 200, 200, 220)
95draw_text("count: " ++ str(len(balls)), 16, 32, 12, 150, 150, 180)

The whole program is the source above — there is no hidden runtime. Petal re-runs it every frame: state values persist between frames, draw calls paint to the canvas, and edits take effect live. Open it in the playground to poke at the numbers and watch the picture change.