7 static badge_sprite
const anim_cat
[] = {
8 { 8, 5, (uint8_t const *) "\xc7\x3f\xce\x38\x11" },
9 { 8, 5, (uint8_t const *) "\xd7\x7d\xc6\x19\x25" }
12 static badge_sprite
const anim_mushroom
[] = {
13 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
14 { 7, 7, (uint8_t const *) "\x20\x18\x1e\x8f\x87\x81" },
15 { 7, 7, (uint8_t const *) "\x10\x0c\x9f\xcf\xc7\x40" },
16 { 7, 7, (uint8_t const *) "\x08\x86\xdf\xef\x67\x20" },
17 { 7, 7, (uint8_t const *) "\x04\xc3\xef\xf7\x33\x10" },
18 { 7, 7, (uint8_t const *) "\x04\xc3\xe7\xf3\x31\x10" }
21 static badge_sprite
const anim_kaninchen
[] = {
22 { 7, 5, (uint8_t const *) "\x60\x30\xbe\x31\x02" },
23 { 7, 5, (uint8_t const *) "\x42\x30\xbe\x31\x01" },
24 { 7, 5, (uint8_t const *) "\x42\x30\xae\x35\x01" },
25 { 7, 5, (uint8_t const *) "\x60\x30\xae\x35\x02" },
26 { 7, 5, (uint8_t const *) "\x60\x30\xbe\x31\x01" }
29 static badge_sprite
const anim_snake
[] = {
30 { 10, 6, (uint8_t const *) "\x10\x86\x83\x30\x04\x83\xa2\x0f" },
31 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x0c\xc1\xa2\x0f" },
32 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x08\x82\xe0\x0f" },
33 { 10, 6, (uint8_t const *) "\x10\x86\x83\x20\x08\x86\xe1\x0f" }
36 static badge_sprite
const anim_spiral
[] = {
37 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xf6\x1a\xe8\xbf\x00\xfe\x0f" },
38 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xd6\xda\x69\xb0\x7f\x02\x0c" },
39 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x6f\xa1\xb5\xd6\x5a\x6a\xaf\x81\xfe\x0b" },
40 { 10, 10, (uint8_t const *) "\xff\x07\xd8\x4f\x61\x35\xd5\x55\x54\x5f\x01\xfd\x07" },
41 { 10, 10, (uint8_t const *) "\xff\x07\xd0\x7f\x81\xf5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
42 { 10, 10, (uint8_t const *) "\x03\xe4\xdf\x60\xb9\xb5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
43 { 10, 10, (uint8_t const *) "\xfd\x17\x58\x6f\xa5\xb5\xd6\x5a\x68\xbf\x01\xfe\x0f" },
44 { 10, 10, (uint8_t const *) "\xfe\x0b\xa8\xaf\xa2\xba\xca\x6a\x28\xbf\x01\xfe\x0f" }
47 static void enemy_animation_advance(jumpnrun_enemy
*enemy
) {
48 ++enemy
->base
.tick_minor
;
49 if(enemy
->base
.tick_minor
== enemy
->type
->animation_ticks_per_frame
) {
50 enemy
->base
.tick_minor
= 0;
52 ++enemy
->base
.anim_frame
;
53 if(enemy
->base
.anim_frame
>= enemy
->type
->animation_length
) {
54 enemy
->base
.anim_frame
= 0;
59 void jumpnrun_process_enemy(jumpnrun_enemy
*self
,
60 badge_framebuffer
*fb
,
61 struct jumpnrun_game_state
*state
,
62 struct jumpnrun_level
*lv
,
63 struct jumpnrun_tile_range
const *visible_tiles
,
64 vec2d
*player_inertia_mod
) {
65 int const spawn_margin
= 1 + self
->type
->animation_frames
[self
->base
.anim_frame
].width
;
67 if(self
->flags
& JUMPNRUN_ENEMY_SPAWNED
) {
68 if(fixed_point_lt(rectangle_left(enemy_box(self
)), FIXED_POINT(state
->left
- spawn_margin
, 0)) ||
69 fixed_point_gt(rectangle_left(enemy_box(self
)), FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
, 0)) ||
70 fixed_point_gt(rectangle_top (enemy_box(self
)), FIXED_POINT(BADGE_DISPLAY_HEIGHT
, 0))) {
71 self
->flags
&= ~JUMPNRUN_ENEMY_SPAWNED
;
73 self
->type
->game_tick(self
, state
, lv
, visible_tiles
, player_inertia_mod
);
76 badge_framebuffer_blt(fb
,
77 fixed_point_cast_int(rectangle_left(enemy_box(self
))) - state
->left
,
78 fixed_point_cast_int(rectangle_top (enemy_box(self
))),
80 enemy_render_flags(self
));
83 } else if(self
->flags
& JUMPNRUN_ENEMY_UNAVAILABLE
) {
84 if(state
->left
> fixed_point_cast_int(self
->spawn_pos
.x
) + spawn_margin
||
85 state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
< fixed_point_cast_int(self
->spawn_pos
.x
)) {
86 self
->flags
&= ~JUMPNRUN_ENEMY_UNAVAILABLE
;
88 } else if((fixed_point_gt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
- spawn_margin
, 0)) &&
89 fixed_point_lt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
- spawn_margin
/ 2, 0))) ||
90 (fixed_point_lt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
+ spawn_margin
, 0)) &&
91 fixed_point_gt(self
->spawn_pos
.x
, FIXED_POINT(state
->left
+ BADGE_DISPLAY_WIDTH
, 0)))) {
92 // enemy unspawned, available and in spawn zone.
93 self
->flags
|= JUMPNRUN_ENEMY_SPAWNED
| JUMPNRUN_ENEMY_UNAVAILABLE
;
94 self
->base
.current_box
= rectangle_new(self
->spawn_pos
, self
->type
->extent
);
95 self
->base
.inertia
= self
->type
->spawn_inertia
;
96 self
->base
.anim_frame
= 0;
97 self
->base
.tick_minor
= 0;
98 self
->base
.touching_ground
= false;
99 self
->base
.jumpable_frames
= 0;
103 void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy
*self
,
104 vec2d
*desired_position
,
106 jumpnrun_tile_range
const *visible_tiles
) {
107 vec2d inertia_mod
= self
->base
.inertia
;
109 collisions_tiles_displace(desired_position
,
115 if(fixed_point_ne(inertia_mod
.x
, self
->base
.inertia
.x
)) {
116 self
->base
.inertia
.x
= fixed_point_neg(self
->base
.inertia
.x
);
120 void enemy_collision_player_jumpable(jumpnrun_enemy
*self
,
121 jumpnrun_game_state
*state
,
122 vec2d
*player_inertia_mod
)
124 rectangle rect_self
= enemy_hitbox(self
);
126 if(rectangle_intersect(&rect_self
, &state
->player
.current_box
)) {
127 if(fixed_point_gt(state
->player
.inertia
.y
, FIXED_POINT(0, 0))) {
128 self
->flags
&= ~JUMPNRUN_ENEMY_SPAWNED
;
129 player_inertia_mod
->y
= FIXED_POINT(0, -250);
130 state
->player
.jumpable_frames
= 12;
132 state
->status
= JUMPNRUN_DEAD
;
137 void enemy_tick_straight_ahead(jumpnrun_enemy
*self
,
138 jumpnrun_game_state
*state
,
140 jumpnrun_tile_range
const *visible_tiles
,
141 vec2d
*player_inertia_mod
) {
142 int screenpos
= fixed_point_cast_int(rectangle_left(&self
->base
.current_box
));
144 if(screenpos
+ JUMPNRUN_MAX_SPAWN_MARGIN
< state
->left
||
145 screenpos
>= state
->left
+ BADGE_DISPLAY_WIDTH
+ JUMPNRUN_MAX_SPAWN_MARGIN
) {
149 jumpnrun_passive_movement(&self
->base
.inertia
);
151 vec2d new_pos
= vec2d_add(enemy_position(self
), self
->base
.inertia
);
152 self
->type
->collision_tiles(self
, &new_pos
, lv
, visible_tiles
);
153 self
->type
->collision_player(self
, state
, player_inertia_mod
);
154 rectangle_move_to(&self
->base
.current_box
, new_pos
);
156 enemy_animation_advance(self
);
159 void enemy_collision_tiles_pass_through(struct jumpnrun_enemy
*self
,
160 vec2d
*desired_position
,
161 struct jumpnrun_level
*lv
,
162 struct jumpnrun_tile_range
const *visible_tiles
) {
164 (void) desired_position
;
166 (void) visible_tiles
;
170 void enemy_collision_player_deadly(struct jumpnrun_enemy
*self
,
171 struct jumpnrun_game_state
*state
,
172 vec2d
*player_inertia_mod
) {
173 (void) player_inertia_mod
;
175 rectangle rect_self
= enemy_hitbox(self
);
177 if(rectangle_intersect(&rect_self
, &state
->player
.current_box
)) {
178 state
->status
= JUMPNRUN_DEAD
;
182 void enemy_tick_swing_up_and_down(struct jumpnrun_enemy
*self
,
183 struct jumpnrun_game_state
*state
,
184 struct jumpnrun_level
*lv
,
185 struct jumpnrun_tile_range
const *visible_tiles
,
186 vec2d
*player_inertia_mod
) {
187 int screenpos
= fixed_point_cast_int(rectangle_left(&self
->base
.current_box
));
189 if(screenpos
+ JUMPNRUN_MAX_SPAWN_MARGIN
< state
->left
||
190 screenpos
>= state
->left
+ BADGE_DISPLAY_WIDTH
+ JUMPNRUN_MAX_SPAWN_MARGIN
) {
194 self
->base
.inertia
.y
= fixed_point_add(self
->base
.inertia
.y
,
195 fixed_point_mul(FIXED_POINT(0, 5),
196 fixed_point_sub(self
->spawn_pos
.y
,
197 self
->base
.current_box
.pos
.y
)));
199 jumpnrun_passive_movement(&self
->base
.inertia
);
201 vec2d new_pos
= vec2d_add(enemy_position(self
), self
->base
.inertia
);
202 self
->type
->collision_tiles(self
, &new_pos
, lv
, visible_tiles
);
203 self
->type
->collision_player(self
, state
, player_inertia_mod
);
204 rectangle_move_to(&self
->base
.current_box
, new_pos
);
206 enemy_animation_advance(self
);
209 jumpnrun_enemy_type
const jumpnrun_enemy_type_data
[JUMPNRUN_ENEMY_TYPE_COUNT
] = {
211 .animation_ticks_per_frame
= 16,
212 .animation_length
= ARRAY_SIZE(anim_cat
),
213 .animation_frames
= anim_cat
,
214 .extent
= { FIXED_INT_I(8), FIXED_INT_I(5) },
215 .hitbox
= { { FIXED_INT_I(1), FIXED_INT_I(2) },
216 { FIXED_INT_I(6), FIXED_INT_I(3) } },
217 .spawn_inertia
= { FIXED_POINT_I(0, -100), FIXED_INT_I(0) },
218 .collision_tiles
= enemy_collision_tiles_bounce_horiz
,
219 .collision_player
= enemy_collision_player_jumpable
,
220 .game_tick
= enemy_tick_straight_ahead
222 .animation_ticks_per_frame
= 12,
223 .animation_length
= ARRAY_SIZE(anim_mushroom
),
224 .animation_frames
= anim_mushroom
,
225 .extent
= { FIXED_INT_I(7), FIXED_INT_I(7) },
226 .hitbox
= { { FIXED_INT_I(1), FIXED_INT_I(1) },
227 { FIXED_INT_I(5), FIXED_INT_I(4) } },
228 .spawn_inertia
= { FIXED_POINT_I(0, -50), FIXED_INT_I(0) },
229 .collision_tiles
= enemy_collision_tiles_bounce_horiz
,
230 .collision_player
= enemy_collision_player_jumpable
,
231 .game_tick
= enemy_tick_straight_ahead
233 .animation_ticks_per_frame
= 9,
234 .animation_length
= ARRAY_SIZE(anim_kaninchen
),
235 .animation_frames
= anim_kaninchen
,
236 .extent
= { FIXED_INT_I(7), FIXED_INT_I(5) },
237 .hitbox
= { { FIXED_INT_I(1), FIXED_INT_I(2) },
238 { FIXED_INT_I(5), FIXED_INT_I(3) } },
239 .spawn_inertia
= { FIXED_POINT_I(0, -80), FIXED_POINT_I(0, 0) },
240 .collision_tiles
= enemy_collision_tiles_bounce_horiz
,
241 .collision_player
= enemy_collision_player_jumpable
,
242 .game_tick
= enemy_tick_straight_ahead
244 .animation_ticks_per_frame
= 6,
245 .animation_length
= ARRAY_SIZE(anim_snake
),
246 .animation_frames
= anim_snake
,
247 .extent
= { FIXED_INT_I(10), FIXED_INT_I(6) },
248 .hitbox
= { { FIXED_INT_I(1), FIXED_INT_I(4) },
249 { FIXED_INT_I(8), FIXED_INT_I(2) } },
250 .spawn_inertia
= { FIXED_POINT_I(0, -150), FIXED_INT_I(0) },
251 .collision_tiles
= enemy_collision_tiles_bounce_horiz
,
252 .collision_player
= enemy_collision_player_jumpable
,
253 .game_tick
= enemy_tick_straight_ahead
255 .animation_ticks_per_frame
= 6,
256 .animation_length
= ARRAY_SIZE(anim_spiral
),
257 .animation_frames
= anim_spiral
,
258 .extent
= { FIXED_INT_I(10), FIXED_INT_I(10) },
259 .hitbox
= { { FIXED_INT_I(1), FIXED_INT_I(1) },
260 { FIXED_INT_I(8), FIXED_INT_I(8) } },
261 .spawn_inertia
= { FIXED_INT_I(0), FIXED_POINT_I(0, 200) },
262 .collision_tiles
= enemy_collision_tiles_pass_through
,
263 .collision_player
= enemy_collision_player_deadly
,
264 .game_tick
= enemy_tick_swing_up_and_down