1use ponko::*;
11
12struct Scene {
13 crab: Texture,
14 plop: Sound,
15 follow: bool,
16 dropped: usize,
17}
18
19fn scene(ctx: &mut Ctx) {
21 let t = ctx.time() as f32;
22
23 for y in 0..20 {
25 for x in 0..20 {
26 let shade = if (x + y) % 2 == 0 { 0.16 } else { 0.19 };
27 let tile = Rect::new(x as f32 * 64.0, y as f32 * 64.0, 64.0, 64.0);
28 ctx.draw_rect(tile, Color::rgb(shade, shade + 0.03, shade));
29 }
30 }
31 let center = vec2(640.0, 640.0);
32 ctx.draw_circle(center, 180.0, Color::hex(0x3a86ff).with_alpha(0.15));
33 let orbit = center + Vec2::from_angle(t * 0.6) * 180.0;
34 ctx.draw_line(center, orbit, 3.0, Color::hex(0xffbe0b));
35 let crab = ctx.world.resource::<Scene>().crab;
36 ctx.draw_ex(
37 &crab,
38 orbit,
39 DrawParams {
40 rotation: t,
41 ..Default::default()
42 },
43 );
44
45 let above = ctx.camera.world_to_screen(orbit) + vec2(-28.0, -40.0);
47 ctx.draw_text("orbiter", above, 16.0, Color::hex(0xffbe0b));
48
49 if ctx.world.resource::<Scene>().follow {
50 ctx.camera.look_at(orbit);
51 }
52 if ctx.mouse_pressed(MouseButton::Left) && !ctx.mouse_over_ui() {
53 let at = ctx.mouse_world();
54 ctx.world.spawn((Transform2D::at(at), Sprite::new(crab)));
55 let plop = ctx.world.resource::<Scene>().plop;
56 let speed = 0.8 + ctx.random().stream(0).f32() * 0.4;
57 ctx.play_sound_ex(
58 &plop,
59 SoundParams {
60 speed,
61 ..Default::default()
62 },
63 );
64 ctx.world.resource_mut::<Scene>().dropped += 1;
65 }
66}
67fn hud(ctx: &mut Ctx) {
71 let panel = Rect::new(12.0, 12.0, 230.0, 172.0);
72 ctx.ui_panel(panel);
73 let mut at = panel.min + ctx.ui_style.padding;
74 let (zoom, dropped) = (ctx.camera.zoom, ctx.world.resource::<Scene>().dropped);
75 let lines = format!("zoom {zoom:.2}x\ncrabs dropped: {dropped}\n{:.0} FPS", ctx.fps());
76 at.y += ctx.ui_label(at, &lines).y + 8.0;
77
78 let follow = ctx.world.resource::<Scene>().follow;
79 let label = if follow { "Stop following" } else { "Follow orbiter" };
80 if ctx.ui_button(Rect::new(at.x, at.y, 210.0, 30.0), label) {
81 ctx.world.resource_mut::<Scene>().follow = !follow;
82 }
83 at.y += 38.0;
84 if ctx.ui_button(Rect::new(at.x, at.y, 210.0, 30.0), "Reset camera") {
85 ctx.camera.zoom = 1.0;
86 ctx.camera.position = Vec2::ZERO;
87 ctx.world.resource_mut::<Scene>().follow = false;
88 }
89}
90fn plop(ctx: &mut Ctx) -> Sound {
94 let rate = 44_100;
95 let samples: Vec<f32> = (0..rate / 8)
96 .map(|i| {
97 let t = i as f32 / rate as f32;
98 let freq = 900.0 - t * 4000.0;
99 (t * freq * std::f32::consts::TAU).sin() * (1.0 - t * 8.0).max(0.0) * 0.25
100 })
101 .collect();
102 ctx.create_sound(rate, &samples)
103}
104
105fn main() {
106 Game::new("Crabby Engine: camera, shapes, text, UI", 1280, 720)
107 .system(camera_controls)
108 .system(scene)
109 .system(hud)
110 .run(|ctx| {
111 let crab = ctx.load_texture("crab.png");
112 let plop = plop(ctx);
113 ctx.world.insert_resource(Scene {
114 crab,
115 plop,
116 follow: false,
117 dropped: 0,
118 });
119 });
120}