My actor.rpg avatar walking around on a GBA game
1#![no_std]
2#![no_main]
3#![cfg_attr(test, feature(custom_test_frameworks))]
4#![cfg_attr(test, reexport_test_harness_main = "test_main")]
5#![cfg_attr(test, test_runner(agb::test_runner::test_runner))]
6
7extern crate alloc;
8
9use agb::{
10 display::{
11 HEIGHT, WIDTH,
12 object::{Object, Sprite, Tag},
13 },
14 fixnum::{Num, Vector2D, num, vec2},
15 include_aseprite,
16 input::ButtonController,
17};
18
19include_aseprite!(mod sprites, "gfx/pumpkin_head.aseprite");
20use sprites::{FORWARD, LEFT, REVERSE, RIGHT};
21
22type Number = Num<i32, 8>;
23
24#[derive(Clone, Copy)]
25enum Facing {
26 Forward,
27 Reverse,
28 Left,
29 Right,
30}
31
32impl Facing {
33 fn tag(self) -> &'static Tag {
34 match self {
35 Facing::Forward => &FORWARD,
36 Facing::Reverse => &REVERSE,
37 Facing::Left => &LEFT,
38 Facing::Right => &RIGHT,
39 }
40 }
41}
42
43const SPEED: Number = num!(0.75);
44const SPRITE_WIDTH: i32 = 32;
45const SPRITE_HEIGHT: i32 = 64;
46
47// The sprite is closer to 32x47. But the gba doesn't like that sprite size so adding some padding
48const SPRITE_TOP_PADDING: i32 = 17;
49const VISIBLE_HEIGHT: i32 = SPRITE_HEIGHT - SPRITE_TOP_PADDING;
50const FRAMES_PER_STEP: usize = 8;
51
52#[agb::entry]
53fn main(gba: agb::Gba) -> ! {
54 run(gba);
55}
56
57fn run(mut gba: agb::Gba) -> ! {
58 let mut gfx = gba.graphics.get();
59 let mut input = ButtonController::new();
60
61 let mut position: Vector2D<Number> = vec2(
62 Number::new((WIDTH - SPRITE_WIDTH) / 2),
63 Number::new((HEIGHT - VISIBLE_HEIGHT) / 2 - SPRITE_TOP_PADDING),
64 );
65 let mut facing = Facing::Forward;
66 let mut walk_frames: usize = 0;
67
68 let max_x = Number::new(WIDTH - SPRITE_WIDTH);
69 let max_y = Number::new(HEIGHT - SPRITE_HEIGHT);
70 let min_y = Number::new(-SPRITE_TOP_PADDING);
71
72 loop {
73 input.update();
74
75 let dx = input.x_tri() as i32;
76 let dy = input.y_tri() as i32;
77 let moving = dx != 0 || dy != 0;
78
79 if moving {
80 facing = if dy < 0 {
81 Facing::Reverse
82 } else if dy > 0 {
83 Facing::Forward
84 } else if dx < 0 {
85 Facing::Left
86 } else {
87 Facing::Right
88 };
89
90 position.x += SPEED * dx;
91 position.y += SPEED * dy;
92
93 if position.x < num!(0.0) {
94 position.x = num!(0.0);
95 }
96 if position.y < min_y {
97 position.y = min_y;
98 }
99 if position.x > max_x {
100 position.x = max_x;
101 }
102 if position.y > max_y {
103 position.y = max_y;
104 }
105
106 walk_frames = walk_frames.wrapping_add(1);
107 }
108
109 let tag = facing.tag();
110 let sprite: &'static Sprite = if moving {
111 tag.animation_sprite(walk_frames / FRAMES_PER_STEP)
112 } else {
113 tag.sprite(0)
114 };
115
116 let mut frame = gfx.frame();
117 Object::new(sprite)
118 .set_pos(position.floor())
119 .show(&mut frame);
120 frame.commit();
121 }
122}