From 01d395b92b5ba972a6e1c3d8f2bf4803f155a3cb Mon Sep 17 00:00:00 2001 From: Wintermate Date: Sun, 20 Oct 2013 04:07:20 +0200 Subject: [PATCH] =?utf8?q?Kr=C3=A4ftig=20aufger=C3=A4umt.=20Kollisions-=20?= =?utf8?q?und=20Sprungt=C3=B6tungsphysik=20jetzt=20allein=20auf=20Hitboxba?= =?utf8?q?sis.=20TODO:=20Wenn=20man=20von=20unten=20angesprungen=20wird,?= =?utf8?q?=20wie=20verhalten=3F?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- badge/jumpnrun/collision.c | 24 +-- badge/jumpnrun/enemies.c | 295 ++++++++++++++---------------------- badge/jumpnrun/enemies.h | 18 +-- badge/jumpnrun/game_state.h | 30 ++++ badge/jumpnrun/gnobbel.lv | 4 +- badge/jumpnrun/items.c | 9 +- badge/jumpnrun/jumpnrun.c | 264 ++++++++------------------------ badge/jumpnrun/jumpnrun.h | 31 +--- badge/jumpnrun/level_load.c | 9 +- badge/jumpnrun/levels.txt | 2 +- badge/jumpnrun/moveable.c | 1 + badge/jumpnrun/moveable.h | 15 +- badge/jumpnrun/player.h | 27 ++++ badge/jumpnrun/render.c | 74 +++++++++ badge/jumpnrun/shots.c | 19 +++ badge/jumpnrun/shots.h | 27 ++++ badge/jumpnrun/stats.c | 36 +++-- badge/jumpnrun/stats.h | 2 +- badge/jumpnrun/tiles.h | 8 +- badge/util/rectangle.h | 7 + mock/Makefile | 9 +- 21 files changed, 448 insertions(+), 463 deletions(-) create mode 100644 badge/jumpnrun/game_state.h create mode 100644 badge/jumpnrun/moveable.c create mode 100644 badge/jumpnrun/player.h create mode 100644 badge/jumpnrun/render.c create mode 100644 badge/jumpnrun/shots.c create mode 100644 badge/jumpnrun/shots.h diff --git a/badge/jumpnrun/collision.c b/badge/jumpnrun/collision.c index 0f254e0..20617bb 100644 --- a/badge/jumpnrun/collision.c +++ b/badge/jumpnrun/collision.c @@ -4,7 +4,7 @@ uint8_t collision_displace(vec2d *desired_pos, jumpnrun_moveable *current, rectangle const *obstacle, vec2d *inertia_mod) { - rectangle desired = current->current_box; + rectangle desired = current->hitbox; rectangle_move_to(&desired, *desired_pos); if(!rectangle_intersect(obstacle, &desired)) { @@ -21,7 +21,7 @@ uint8_t collision_displace(vec2d *desired_pos, if(fixed_point_le(rectangle_top ( obstacle), rectangle_top(&desired)) && fixed_point_gt(rectangle_bottom( obstacle), rectangle_top(&desired)) && - fixed_point_lt(rectangle_top (&desired ), rectangle_top(¤t->current_box))) { + fixed_point_lt(rectangle_top (&desired ), rectangle_top(¤t->hitbox))) { coll_y = JUMPNRUN_COLLISION_BOTTOM; y = fixed_point_sub(rectangle_bottom(obstacle), rectangle_top(&desired)); @@ -29,7 +29,7 @@ uint8_t collision_displace(vec2d *desired_pos, } else if(fixed_point_gt(rectangle_bottom( obstacle), rectangle_bottom(&desired)) && fixed_point_le(rectangle_top ( obstacle), rectangle_bottom(&desired)) && - fixed_point_gt(rectangle_top (&desired ), rectangle_top (¤t->current_box))) { + fixed_point_gt(rectangle_top (&desired ), rectangle_top (¤t->hitbox))) { coll_y = JUMPNRUN_COLLISION_TOP; y = fixed_point_sub(rectangle_bottom(&desired ), rectangle_top ( obstacle)); @@ -40,7 +40,7 @@ uint8_t collision_displace(vec2d *desired_pos, if(fixed_point_le(rectangle_left ( obstacle), rectangle_left(&desired)) && fixed_point_gt(rectangle_right( obstacle), rectangle_left(&desired)) && - fixed_point_lt(rectangle_left (&desired ), rectangle_left(¤t->current_box))) { + fixed_point_lt(rectangle_left (&desired ), rectangle_left(¤t->hitbox))) { coll_x = JUMPNRUN_COLLISION_RIGHT; x = fixed_point_sub(rectangle_right(obstacle), rectangle_left(&desired)); @@ -48,7 +48,7 @@ uint8_t collision_displace(vec2d *desired_pos, } else if(fixed_point_gt(rectangle_right( obstacle), rectangle_right(&desired)) && fixed_point_le(rectangle_left ( obstacle), rectangle_right(&desired)) && - fixed_point_gt(rectangle_left (&desired ), rectangle_left (¤t->current_box))) { + fixed_point_gt(rectangle_left (&desired ), rectangle_left (¤t->hitbox))) { coll_x = JUMPNRUN_COLLISION_LEFT; x = fixed_point_sub(rectangle_right(&desired ), rectangle_left ( obstacle)); @@ -63,7 +63,13 @@ uint8_t collision_displace(vec2d *desired_pos, } else if(fixed_point_gt(x, y)) { desired_pos->y = dy; inertia_mod->y = FIXED_INT(0); - current->touching_ground = bottom_collision; + + if(bottom_collision) { + current->flags |= JUMPNRUN_MOVEABLE_TOUCHING_GROUND; + } else { + current->flags &= ~JUMPNRUN_MOVEABLE_TOUCHING_GROUND; + } + coll = coll_y; } else { desired_pos->x = dx; @@ -86,7 +92,7 @@ bool collisions_tiles_displace(vec2d *desired_position, }; static int const collision_order[] = { 7, 1, 3, 5, 6, 8, 0, 2 }; - vec2d midpoint = rectangle_mid(&thing->current_box); + vec2d midpoint = rectangle_mid(&thing->hitbox); jumpnrun_tile_position midtile_pos = { fixed_point_cast_int(fixed_point_div(midpoint.x, FIXED_INT(JUMPNRUN_TILE_PIXEL_WIDTH ))), @@ -134,7 +140,7 @@ bool collisions_tiles_displace(vec2d *desired_position, /* collision: sort by priority (top/bottom, left/right, then diagonal) */ bool lethal = false; - thing->touching_ground = false; + thing->flags &= ~JUMPNRUN_MOVEABLE_TOUCHING_GROUND; for(size_t collision_index = 0; collision_index < ARRAY_SIZE(collision_order); ++collision_index) { if(collision_tile[collision_order[collision_index]] == -1) { @@ -150,7 +156,7 @@ bool collisions_tiles_displace(vec2d *desired_position, } } - rectangle_move_to(&thing->current_box, *desired_position); + rectangle_move_to(&thing->hitbox, *desired_position); return lethal; } diff --git a/badge/jumpnrun/enemies.c b/badge/jumpnrun/enemies.c index b518b51..61859a8 100644 --- a/badge/jumpnrun/enemies.c +++ b/badge/jumpnrun/enemies.c @@ -1,8 +1,11 @@ #include "enemies.h" #include "collision.h" +#include "game_state.h" #include "tiles.h" #include "jumpnrun.h" +#include "moveable.h" +#include "render.h" static badge_sprite const anim_cat[] = { { 8, 5, (uint8_t const *) "\xc7\x3f\xce\x38\x11" }, @@ -88,46 +91,79 @@ static void enemy_animation_advance(jumpnrun_enemy *enemy) { } } +static void enemy_spawn(jumpnrun_enemy *self) { + // enemy unspawned, available and in spawn zone. + self->base.flags = JUMPNRUN_ENEMY_SPAWNED | JUMPNRUN_ENEMY_UNAVAILABLE; + self->base.anim_frame = 0; + self->base.tick_minor = 0; + self->base.jumpable_frames = 0; +} + +void jumpnrun_enemy_despawn(jumpnrun_enemy *self) { + // Despawned enemies are reset to their spawn position, so enemy_in_spawn_area will determine whether the spawn point is in the spawn area. + self->base.flags &= ~JUMPNRUN_ENEMY_SPAWNED; + self->base.hitbox = rectangle_new(self->spawn_pos, self->type->hitbox.extent); + self->base.inertia = self->type->spawn_inertia; +} + +void jumpnrun_enemy_reset (jumpnrun_enemy *self) { + jumpnrun_enemy_despawn(self); + self->base.flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE; +} + +static void enemy_bounce(jumpnrun_enemy *self) { + self->base.inertia.x = fixed_point_neg(self->base.inertia.x); +} + +static inline vec2d enemy_pos_hitbox (jumpnrun_enemy const *self) { return self->base.hitbox.pos; } +static inline vec2d enemy_pos_display(jumpnrun_enemy const *self) { return vec2d_sub(enemy_pos_hitbox(self), self->type->hitbox.pos); } +static inline vec2d enemy_pos_desired(jumpnrun_enemy const *self) { return vec2d_add(enemy_pos_hitbox(self), self->base.inertia); } + +static inline void enemy_move_to(jumpnrun_enemy *self, vec2d new_pos) { + rectangle_move_to(&self->base.hitbox, new_pos); +} + +static inline bool enemy_in_area(jumpnrun_enemy const *self, jumpnrun_game_state *state, int margin) { + return + fixed_point_gt(rectangle_left (enemy_hitbox(self)), FIXED_INT(jumpnrun_screen_left (state) - margin)) && + fixed_point_lt(rectangle_right(enemy_hitbox(self)), FIXED_INT(jumpnrun_screen_right(state) + margin)); +} + +static inline bool enemy_on_screen(jumpnrun_enemy const *self, jumpnrun_game_state *state) { + return enemy_in_area(self, state, 0); +} + +static inline bool enemy_in_spawn_area(jumpnrun_enemy const *self, jumpnrun_game_state *state) { + return enemy_in_area(self, state, JUMPNRUN_MAX_SPAWN_MARGIN); +} + void jumpnrun_process_enemy(jumpnrun_enemy *self, badge_framebuffer *fb, struct jumpnrun_game_state *state, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int const spawn_margin = 1 + self->type->animation_frames[self->base.anim_frame].width; - - if(self->flags & JUMPNRUN_ENEMY_SPAWNED) { - if(fixed_point_lt(rectangle_left(enemy_box(self)), FIXED_POINT(state->left - spawn_margin, 0)) || - fixed_point_gt(rectangle_left(enemy_box(self)), FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0)) || - fixed_point_gt(rectangle_top (enemy_box(self)), FIXED_POINT(BADGE_DISPLAY_HEIGHT , 0))) { - self->flags &= ~JUMPNRUN_ENEMY_SPAWNED; + // Despawned enemies are reset to their spawn position, so enemy_in_spawn_area will determine whether the spawn point is in the spawn area. + if(self->base.flags & JUMPNRUN_ENEMY_SPAWNED) { + if(!enemy_in_spawn_area(self, state) || fixed_point_gt(rectangle_top (enemy_hitbox(self)), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { + jumpnrun_enemy_despawn(self); } else { self->type->move_tick(self, state, lv, visible_tiles, player_inertia_mod); self->type->collision_shots(self, state); + if (fixed_point_lt(self->base.inertia.x, FIXED_INT(0))) { self->base.flags &= ~JUMPNRUN_MOVEABLE_MIRRORED; } + else if(fixed_point_ne(self->base.inertia.x, FIXED_INT(0))) { self->base.flags |= JUMPNRUN_MOVEABLE_MIRRORED; } if(fb) { - badge_framebuffer_blt(fb, - fixed_point_cast_int(rectangle_left(enemy_box(self))) - state->left, - fixed_point_cast_int(rectangle_top (enemy_box(self))), - enemy_sprite(self), - enemy_render_flags(self)); + jumpnrun_render_enemy(fb, state, self); } } - } else if(self->flags & JUMPNRUN_ENEMY_UNAVAILABLE) { - if(state->left > fixed_point_cast_int(self->spawn_pos.x) + spawn_margin || - state->left + BADGE_DISPLAY_WIDTH + spawn_margin < fixed_point_cast_int(self->spawn_pos.x)) { - self->flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE; + } else if(self->base.flags & JUMPNRUN_ENEMY_UNAVAILABLE) { + if(!enemy_in_spawn_area(self, state)) { + self->base.flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE; } - } else if(fixed_point_gt(self->spawn_pos.x, FIXED_POINT(state->left - spawn_margin, 0)) && - fixed_point_lt(self->spawn_pos.x, FIXED_POINT(state->left + BADGE_DISPLAY_WIDTH + spawn_margin, 0))) { + } else if(enemy_in_spawn_area(self, state)) { // enemy unspawned, available and in spawn zone. - self->flags = JUMPNRUN_ENEMY_SPAWNED | JUMPNRUN_ENEMY_UNAVAILABLE; - self->base.current_box = rectangle_new(self->spawn_pos, self->type->extent); - self->base.inertia = self->type->spawn_inertia; - self->base.anim_frame = 0; - self->base.tick_minor = 0; - self->base.touching_ground = false; - self->base.jumpable_frames = 0; + enemy_spawn(self); } } @@ -144,11 +180,9 @@ void enemy_collision_tiles_bounce_horiz(jumpnrun_enemy *self, &inertia_mod); if(killed) { - self->flags &= ~JUMPNRUN_ENEMY_SPAWNED; - } - - if(fixed_point_ne(inertia_mod.x, self->base.inertia.x)) { - self->base.inertia.x = fixed_point_neg(self->base.inertia.x); + jumpnrun_enemy_despawn(self); + } else if(fixed_point_ne(inertia_mod.x, self->base.inertia.x)) { + enemy_bounce(self); } } @@ -157,10 +191,8 @@ void enemy_collision_player_deadly(struct jumpnrun_enemy *self, vec2d *player_inertia_mod) { (void) player_inertia_mod; - rectangle rect_self = enemy_hitbox(self); - - if(rectangle_intersect(&rect_self, &state->player.current_box)) { - state->status = JUMPNRUN_DEAD; + if(rectangle_intersect(enemy_hitbox(self), &state->player.base.hitbox)) { + state->player.base.flags |= JUMPNRUN_PLAYER_DEAD; } } @@ -168,17 +200,15 @@ void enemy_collision_player_jumpable(jumpnrun_enemy *self, jumpnrun_game_state *state, vec2d *player_inertia_mod) { - rectangle rect_self = enemy_hitbox(self); - - if(rectangle_intersect(&rect_self, &state->player.current_box)) { - if(fixed_point_lt(rectangle_top(&state->player.current_box), rectangle_top(&rect_self)) && - fixed_point_gt(state->player.inertia.y, FIXED_POINT(0, 0))) + if(rectangle_intersect(enemy_hitbox(self), &state->player.base.hitbox)) { + if(fixed_point_lt(rectangle_top(&state->player.base.hitbox), rectangle_top(enemy_hitbox(self))) && + fixed_point_gt(state->player.base.inertia.y, FIXED_INT(0))) { - self->flags &= ~JUMPNRUN_ENEMY_SPAWNED; + jumpnrun_enemy_despawn(self); player_inertia_mod->y = FIXED_POINT(0, -250); - state->player.jumpable_frames = 12; + state->player.base.jumpable_frames = 12; } else { - state->status = JUMPNRUN_DEAD; + state->player.base.flags |= JUMPNRUN_PLAYER_DEAD; } } } @@ -196,14 +226,12 @@ void enemy_collision_tiles_pass_through(struct jumpnrun_enemy *self, void enemy_collision_shots_die(struct jumpnrun_enemy *self, struct jumpnrun_game_state *state) { - rectangle rect_self = enemy_hitbox(self); - for(uint8_t i = 0; i < JUMPNRUN_MAX_SHOTS; ++i) { jumpnrun_shot *shot = &state->shots[i]; if(jumpnrun_shot_spawned(shot)) { - if(rectangle_intersect(&rect_self, &shot->current_box)) { - self->flags &= ~JUMPNRUN_ENEMY_SPAWNED; + if(rectangle_intersect(enemy_hitbox(self), &shot->current_box)) { + self->base.flags &= ~JUMPNRUN_ENEMY_SPAWNED; jumpnrun_shot_despawn(shot); } } @@ -212,17 +240,15 @@ void enemy_collision_shots_die(struct jumpnrun_enemy *self, void enemy_collision_shots_bounce(struct jumpnrun_enemy *self, struct jumpnrun_game_state *state) { - rectangle rect_self = enemy_hitbox(self); - for(uint8_t i = 0; i < JUMPNRUN_MAX_SHOTS; ++i) { jumpnrun_shot *shot = &state->shots[i]; if(jumpnrun_shot_spawned(shot)) { - if(rectangle_intersect(&rect_self, &shot->current_box)) { + if(rectangle_intersect(enemy_hitbox(self), &shot->current_box)) { if(fixed_point_gt(shot->inertia.x, FIXED_INT(0))) { - rectangle_move_to_x(&shot->current_box, fixed_point_sub(rectangle_left(&rect_self), rectangle_width(&shot->current_box))); + rectangle_move_to_x(&shot->current_box, fixed_point_sub(rectangle_left(enemy_hitbox(self)), rectangle_width(&shot->current_box))); } else { - rectangle_move_to_x(&shot->current_box, rectangle_right(&rect_self)); + rectangle_move_to_x(&shot->current_box, rectangle_right(enemy_hitbox(self))); } shot->inertia.x = fixed_point_neg(shot->inertia.x); @@ -237,25 +263,24 @@ void enemy_collision_shots_dontcare(struct jumpnrun_enemy *self, (void) state; } +static void enemy_tick_common(jumpnrun_enemy *self, + jumpnrun_game_state *state, + jumpnrun_level *lv, + jumpnrun_tile_range const *visible_tiles, + vec2d *player_inertia_mod) { + vec2d new_pos = enemy_pos_desired(self); + self->type->collision_tiles (self, &new_pos, lv, visible_tiles); + self->type->collision_player(self, state, player_inertia_mod); + enemy_move_to(self, new_pos); +} + void enemy_tick_straight_ahead(jumpnrun_enemy *self, jumpnrun_game_state *state, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - jumpnrun_passive_movement(&self->base.inertia); - - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); enemy_animation_advance(self); } @@ -264,23 +289,12 @@ void enemy_tick_straight_follow(jumpnrun_enemy *self, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - jumpnrun_passive_movement(&self->base.inertia); + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - - if(fixed_point_lt(rectangle_right(&state->player.current_box), rectangle_left(enemy_box(self)))) { + if(fixed_point_lt(rectangle_right(&state->player.base.hitbox), rectangle_left(enemy_hitbox(self)))) { self->base.inertia.x = self->type->spawn_inertia.x; - } else if(fixed_point_gt(rectangle_left(&state->player.current_box), rectangle_right(enemy_box(self)))) { + } else if(fixed_point_gt(rectangle_left(&state->player.base.hitbox), rectangle_right(enemy_hitbox(self)))) { self->base.inertia.x = fixed_point_neg(self->type->spawn_inertia.x); } @@ -292,24 +306,14 @@ void enemy_tick_swing_up_and_down(struct jumpnrun_enemy *self, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); self->base.inertia.y = fixed_point_add(fixed_point_add(self->base.inertia.y, fixed_point_div(self->type->spawn_inertia.y, FIXED_INT(3))), fixed_point_mul(FIXED_POINT(0, 5), fixed_point_sub(self->spawn_pos.y, - enemy_position(self).y))); + enemy_pos_display(self).y))); enemy_animation_advance(self); } @@ -319,14 +323,7 @@ void enemy_tick_stationary(struct jumpnrun_enemy *self, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - - self->type->collision_tiles(self, &self->base.current_box.pos, lv, visible_tiles); + self->type->collision_tiles(self, &self->base.hitbox.pos, lv, visible_tiles); self->type->collision_player(self, state, player_inertia_mod); enemy_animation_advance(self); @@ -337,21 +334,10 @@ void enemy_tick_jumper(jumpnrun_enemy *self, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - jumpnrun_passive_movement(&self->base.inertia); + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - - if(self->base.touching_ground) { + if(jumpnrun_moveable_touching_ground(&self->base)) { self->base.inertia.y = self->type->spawn_inertia.y; } @@ -363,19 +349,8 @@ void enemy_tick_dog(jumpnrun_enemy *self, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - jumpnrun_passive_movement(&self->base.inertia); - - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); if(self->base.tick_minor % self->type->animation_ticks_per_frame == 0) { switch(self->base.tick_minor / self->type->animation_ticks_per_frame) { @@ -386,7 +361,7 @@ void enemy_tick_dog(jumpnrun_enemy *self, case 4: case 6: self->base.anim_frame = 0; - if(self->flags & JUMPNRUN_ENEMY_FACING_RIGHT) { + if(self->base.flags & JUMPNRUN_MOVEABLE_MIRRORED) { self->base.inertia.x = fixed_point_neg(self->type->spawn_inertia.x); } else { self->base.inertia.x = self->type->spawn_inertia.x; @@ -399,7 +374,7 @@ void enemy_tick_dog(jumpnrun_enemy *self, case 5: case 7: self->base.anim_frame = 1; - if(self->flags & JUMPNRUN_ENEMY_FACING_RIGHT) { + if(self->base.flags & JUMPNRUN_MOVEABLE_MIRRORED) { self->base.inertia.x = fixed_point_neg(self->type->spawn_inertia.x); } else { self->base.inertia.x = self->type->spawn_inertia.x; @@ -421,8 +396,6 @@ void enemy_tick_dog(jumpnrun_enemy *self, } ++self->base.tick_minor; - if (fixed_point_lt(self->base.inertia.x, FIXED_INT(0))) { self->flags &= ~JUMPNRUN_ENEMY_FACING_RIGHT; } - else if(fixed_point_ne(self->base.inertia.x, FIXED_INT(0))) { self->flags |= JUMPNRUN_ENEMY_FACING_RIGHT; } } void enemy_tick_giraffe(jumpnrun_enemy *self, @@ -430,29 +403,18 @@ void enemy_tick_giraffe(jumpnrun_enemy *self, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - - bool was_on_ground = self->base.touching_ground; + bool was_on_ground = jumpnrun_moveable_touching_ground(&self->base); jumpnrun_passive_movement(&self->base.inertia); + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - - if(self->base.touching_ground) { + if(jumpnrun_moveable_touching_ground(&self->base)) { if(was_on_ground) { enemy_animation_advance(self); if(self->base.anim_frame == 0) { self->base.inertia = self->type->spawn_inertia; - if(fixed_point_gt(rectangle_mid_x(&state->player.current_box), rectangle_mid_x(enemy_box(self)))) { + if(fixed_point_gt(rectangle_mid_x(&state->player.base.hitbox), rectangle_mid_x(enemy_hitbox(self)))) { self->base.inertia.x = fixed_point_neg(self->base.inertia.x); } } @@ -469,8 +431,6 @@ void enemy_tick_giraffe(jumpnrun_enemy *self, } ++self->base.tick_minor; - if (fixed_point_lt(self->base.inertia.x, FIXED_INT(0))) { self->flags &= ~JUMPNRUN_ENEMY_FACING_RIGHT; } - else if(fixed_point_ne(self->base.inertia.x, FIXED_INT(0))) { self->flags |= JUMPNRUN_ENEMY_FACING_RIGHT; } } void enemy_tick_fly_straight(struct jumpnrun_enemy *self, @@ -478,18 +438,7 @@ void enemy_tick_fly_straight(struct jumpnrun_enemy *self, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia); - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); enemy_animation_advance(self); } @@ -498,35 +447,24 @@ void enemy_tick_fly_straight_and_dip(struct jumpnrun_enemy *self, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { - int screenpos = fixed_point_cast_int(rectangle_left(&self->base.current_box)); - - if(screenpos + JUMPNRUN_MAX_SPAWN_MARGIN < state->left || - screenpos >= state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN) { - return; - } - - if(fixed_point_lt(fixed_point_abs(fixed_point_sub(enemy_position(self).x, - state->player.current_box.pos.x)), + if(fixed_point_lt(fixed_point_abs(fixed_point_sub(enemy_pos_hitbox(self).x, + state->player.base.hitbox.pos.x)), FIXED_INT(20))) { - self->flags |= JUMPNRUN_ENEMY_EVENT_TRIGGER1; + self->base.flags |= JUMPNRUN_ENEMY_EVENT_TRIGGER1; } - if(self->flags & JUMPNRUN_ENEMY_EVENT_TRIGGER1) { + if(self->base.flags & JUMPNRUN_ENEMY_EVENT_TRIGGER1) { self->base.inertia.y = fixed_point_add(fixed_point_add(self->base.inertia.y, fixed_point_div(self->type->spawn_inertia.y, FIXED_INT(3))), fixed_point_mul(FIXED_POINT(0, 5), fixed_point_sub(self->spawn_pos.y, - enemy_position(self).y))); + enemy_pos_hitbox(self).y))); } else { self->base.inertia.y = FIXED_INT(0); } - vec2d new_pos = vec2d_add(enemy_position(self), self->base.inertia);; - self->type->collision_tiles(self, &new_pos, lv, visible_tiles); - self->type->collision_player(self, state, player_inertia_mod); - rectangle_move_to(&self->base.current_box, new_pos); - + enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); enemy_animation_advance(self); } @@ -535,7 +473,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 18, .animation_length = ARRAY_SIZE(anim_cat), .animation_frames = anim_cat, - .extent = { FIXED_INT_I(8), FIXED_INT_I(5) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(2) }, { FIXED_INT_I(6), FIXED_INT_I(3) } }, .spawn_inertia = { FIXED_POINT_I(0, -200), FIXED_INT_I(0) }, @@ -547,7 +484,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 12, .animation_length = ARRAY_SIZE(anim_mushroom), .animation_frames = anim_mushroom, - .extent = { FIXED_INT_I(7), FIXED_INT_I(7) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) }, { FIXED_INT_I(5), FIXED_INT_I(4) } }, .spawn_inertia = { FIXED_POINT_I(0, -80), FIXED_INT_I(0) }, @@ -559,7 +495,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 9, .animation_length = ARRAY_SIZE(anim_bunny), .animation_frames = anim_bunny, - .extent = { FIXED_INT_I(7), FIXED_INT_I(5) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(2) }, { FIXED_INT_I(5), FIXED_INT_I(3) } }, .spawn_inertia = { FIXED_POINT_I(0, -80), FIXED_POINT_I(0, -800) }, @@ -571,7 +506,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 6, .animation_length = ARRAY_SIZE(anim_snake), .animation_frames = anim_snake, - .extent = { FIXED_INT_I(10), FIXED_INT_I(6) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(4) }, { FIXED_INT_I(8), FIXED_INT_I(2) } }, .spawn_inertia = { FIXED_POINT_I(0, -150), FIXED_INT_I(0) }, @@ -583,7 +517,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 6, .animation_length = ARRAY_SIZE(anim_spiral), .animation_frames = anim_spiral, - .extent = { FIXED_INT_I(10), FIXED_INT_I(10) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) }, { FIXED_INT_I(8), FIXED_INT_I(8) } }, .spawn_inertia = { FIXED_INT_I(0), FIXED_POINT_I(0, -200) }, @@ -595,7 +528,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 5, .animation_length = ARRAY_SIZE(anim_rotor), .animation_frames = anim_rotor, - .extent = { FIXED_INT_I(9), FIXED_INT_I(9) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) }, { FIXED_INT_I(7), FIXED_INT_I(7) } }, .spawn_inertia = { FIXED_INT_I(0), FIXED_POINT_I(0, 0) }, @@ -607,7 +539,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 18, .animation_length = ARRAY_SIZE(anim_dog), .animation_frames = anim_dog, - .extent = { FIXED_INT_I(8), FIXED_INT_I(5) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(1) }, { FIXED_INT_I(6), FIXED_INT_I(4) } }, .spawn_inertia = { FIXED_POINT_I(0, -200), FIXED_POINT_I(0, 0) }, @@ -619,7 +550,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 36, .animation_length = ARRAY_SIZE(anim_giraffe), .animation_frames = anim_giraffe, - .extent = { FIXED_INT_I(7), FIXED_INT_I(10) }, .hitbox = { { FIXED_INT_I(2), FIXED_INT_I(1) }, { FIXED_INT_I(4), FIXED_INT_I(9) } }, .spawn_inertia = { FIXED_POINT_I(0, -150), FIXED_POINT_I(-1, -200) }, @@ -631,7 +561,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 24, .animation_length = ARRAY_SIZE(anim_bird), .animation_frames = anim_bird, - .extent = { FIXED_INT_I(9), FIXED_INT_I(7) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(3) }, { FIXED_INT_I(7), FIXED_INT_I(3) } }, .spawn_inertia = { FIXED_POINT_I(0, -400), FIXED_POINT_I(0, -150) }, @@ -643,7 +572,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 24, .animation_length = ARRAY_SIZE(anim_bird), .animation_frames = anim_bird, - .extent = { FIXED_INT_I(9), FIXED_INT_I(7) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(3) }, { FIXED_INT_I(7), FIXED_INT_I(3) } }, .spawn_inertia = { FIXED_POINT_I(0, -400), FIXED_INT_I(0) }, @@ -655,7 +583,6 @@ jumpnrun_enemy_type const jumpnrun_enemy_type_data[JUMPNRUN_ENEMY_TYPE_COUNT] = .animation_ticks_per_frame = 24, .animation_length = ARRAY_SIZE(anim_bird), .animation_frames = anim_bird, - .extent = { FIXED_INT_I(9), FIXED_INT_I(7) }, .hitbox = { { FIXED_INT_I(1), FIXED_INT_I(3) }, { FIXED_INT_I(7), FIXED_INT_I(3) } }, .spawn_inertia = { FIXED_POINT_I(0, -400), FIXED_POINT_I(0, 200) }, diff --git a/badge/jumpnrun/enemies.h b/badge/jumpnrun/enemies.h index 5b6da64..1cf8f06 100644 --- a/badge/jumpnrun/enemies.h +++ b/badge/jumpnrun/enemies.h @@ -18,7 +18,6 @@ typedef struct jumpnrun_enemy_type { size_t animation_length; badge_sprite const *animation_frames; - vec2d extent; rectangle hitbox; vec2d spawn_inertia; @@ -42,25 +41,20 @@ typedef struct jumpnrun_enemy_type { typedef struct jumpnrun_enemy { jumpnrun_moveable base; vec2d spawn_pos; - unsigned flags; jumpnrun_enemy_type const *type; } jumpnrun_enemy; enum { - JUMPNRUN_ENEMY_SPAWNED = 1, - JUMPNRUN_ENEMY_UNAVAILABLE = 2, - JUMPNRUN_ENEMY_FACING_RIGHT = 4, +// Do not collide with JUMPNRUN_MOVEABLE_* flags + JUMPNRUN_ENEMY_SPAWNED = 4, + JUMPNRUN_ENEMY_UNAVAILABLE = 8, JUMPNRUN_ENEMY_EVENT_TRIGGER1 = 128 }; -static inline rectangle const *enemy_box (jumpnrun_enemy const *enemy) { return &enemy->base.current_box ; } -static inline vec2d enemy_position (jumpnrun_enemy const *enemy) { return enemy->base.current_box.pos; } -static inline rectangle enemy_hitbox (jumpnrun_enemy const *enemy) { rectangle r = enemy->type->hitbox; rectangle_move_rel(&r, enemy_position(enemy)); return r; } -static inline badge_sprite const *enemy_sprite (jumpnrun_enemy const *enemy) { return &enemy->type->animation_frames[enemy->base.anim_frame]; } - -static inline bool enemy_facing_right(jumpnrun_enemy const *enemy) { return (enemy->flags & JUMPNRUN_ENEMY_FACING_RIGHT) || fixed_point_gt(enemy->base.inertia.x, FIXED_INT(0)); } -static inline uint8_t enemy_render_flags(jumpnrun_enemy const *enemy) { return enemy_facing_right(enemy) ? BADGE_BLT_MIRRORED : 0; } +static inline rectangle const *enemy_hitbox(jumpnrun_enemy const *enemy) { return &enemy->base.hitbox; } +void jumpnrun_enemy_despawn(jumpnrun_enemy *self); +void jumpnrun_enemy_reset (jumpnrun_enemy *self); enum { JUMPNRUN_ENEMY_TYPE_CAT, diff --git a/badge/jumpnrun/game_state.h b/badge/jumpnrun/game_state.h new file mode 100644 index 0000000..2ebe4d0 --- /dev/null +++ b/badge/jumpnrun/game_state.h @@ -0,0 +1,30 @@ +#ifndef INCLUDED_BADGE_JUMPNRUN_GAME_STATE_H +#define INCLUDED_BADGE_JUMPNRUN_GAME_STATE_H + +#include "player.h" +#include "levels.h" +#include "shots.h" +#include "../ui/display.h" + +enum { + JUMPNRUN_MAX_SHOTS = 2, + + JUMPNRUN_STATE_WON = 1 +}; + +typedef struct jumpnrun_game_state { + jumpnrun_player player; + int screen_left; + uint8_t flags; + jumpnrun_shot shots[JUMPNRUN_MAX_SHOTS]; +} jumpnrun_game_state; + +static inline int jumpnrun_screen_left (jumpnrun_game_state const *state) { return state->screen_left; } +static inline int jumpnrun_screen_right(jumpnrun_game_state const *state) { return jumpnrun_screen_left(state) + BADGE_DISPLAY_WIDTH; } + +void jumpnrun_game_state_init (jumpnrun_game_state *state, jumpnrun_level const *lv); +void jumpnrun_game_state_respawn(jumpnrun_game_state *state, jumpnrun_level const *lv); + +void jumpnrun_shot_spawn(jumpnrun_shot *shot, jumpnrun_game_state const *state); + +#endif diff --git a/badge/jumpnrun/gnobbel.lv b/badge/jumpnrun/gnobbel.lv index f6cf1dc..f06baaa 100644 --- a/badge/jumpnrun/gnobbel.lv +++ b/badge/jumpnrun/gnobbel.lv @@ -1,5 +1,5 @@ - X - + + X ### # ### diff --git a/badge/jumpnrun/items.c b/badge/jumpnrun/items.c index d4fb281..42e83b1 100644 --- a/badge/jumpnrun/items.c +++ b/badge/jumpnrun/items.c @@ -1,12 +1,13 @@ #include "items.h" #include "jumpnrun.h" +#include "game_state.h" static void on_collect_win(jumpnrun_item *self, jumpnrun_game_state *state, jumpnrun_level *lv) { (void) lv; self->flags |= JUMPNRUN_ITEM_COLLECTED; - state->status = JUMPNRUN_WON; + state->flags |= JUMPNRUN_STATE_WON; } static void on_collect_checkpoint(jumpnrun_item *self, @@ -15,7 +16,7 @@ static void on_collect_checkpoint(jumpnrun_item *self, (void) state; self->flags |= JUMPNRUN_ITEM_COLLECTED; lv->start_pos = (vec2d) { self->pos.x, - fixed_point_sub(fixed_point_add(self->pos.y, FIXED_INT(self->type->sprite.height)), hacker_extents().y) + fixed_point_sub(fixed_point_add(self->pos.y, FIXED_INT(self->type->sprite.height)), jumpnrun_player_extents().y) }; } @@ -24,13 +25,13 @@ static void on_collect_key(jumpnrun_item *self, jumpnrun_level *lv) { (void) lv; self->flags |= JUMPNRUN_ITEM_COLLECTED; - ++state->keys; + ++state->player.keys; } static void on_collect_encrypted(jumpnrun_item *self, jumpnrun_game_state *state, jumpnrun_level *lv) { - if(state->keys != 0) { + if(state->player.keys != 0) { on_collect_win(self, state, lv); } } diff --git a/badge/jumpnrun/jumpnrun.c b/badge/jumpnrun/jumpnrun.c index 79fa6b3..7dc2c22 100644 --- a/badge/jumpnrun/jumpnrun.c +++ b/badge/jumpnrun/jumpnrun.c @@ -1,6 +1,8 @@ +#include "game_state.h" #include "jumpnrun.h" #include "collision.h" #include "levels.h" +#include "render.h" #include "stats.h" #include "../ui/display.h" @@ -20,86 +22,21 @@ static fixed_point const accel_vert = FIXED_POINT_I(0, 167); static fixed_point const drag_factor = FIXED_POINT_I(0, 854); static fixed_point const speed_jump_x = FIXED_POINT_I(0, 600); -vec2d hacker_extents(void) { return (vec2d) { FIXED_INT_I(5), FIXED_INT_I(8) }; } -static vec2d const shot_spawn_inertia = { FIXED_POINT_I(0, 800), FIXED_POINT_I(0, -800) }; - -static badge_sprite const anim_hacker[] = { - { 5, 8, (uint8_t const *) "\x1c\xff\xfd\x04\x04" }, - { 5, 8, (uint8_t const *) "\x1c\xff\x3d\xc4\x04" }, - { 5, 8, (uint8_t const *) "\xdc\x3f\x1d\x24\xc4" }, - { 5, 8, (uint8_t const *) "\x1c\xff\x3d\xc4\x04" } - /* - { 5, 8, (uint8_t const *) "\x46\xfc\x73\x8c\x31" }, - { 5, 8, (uint8_t const *) "\x46\xfc\x73\x8c\x52" }, - { 5, 8, (uint8_t const *) "\x46\xfc\x73\x94\x8c" }, - { 5, 8, (uint8_t const *) "\x46\xfc\x73\x8c\x52" } - */ - /* - { 6, 8, (uint8_t const *) "\x0c\xe1\x3b\x0e\xc3\x30" }, - { 6, 8, (uint8_t const *) "\x0c\xe1\x3b\x0e\x43\x51" }, - { 6, 8, (uint8_t const *) "\x0c\xe1\x3b\x0e\x35\x82" }, - { 6, 8, (uint8_t const *) "\x0c\xe1\x3b\x0e\x43\x51" } - */ - /* - { 6, 8, (uint8_t const *) "\xff\xff\xff\xff\xff\xff" }, - { 6, 8, (uint8_t const *) "\xff\xff\xff\xff\xff\xff" }, - { 6, 8, (uint8_t const *) "\xff\xff\xff\xff\xff\xff" }, - { 6, 8, (uint8_t const *) "\xff\xff\xff\xff\xff\xff" } - */ -}; - -badge_sprite const *jumpnrun_hacker_symbol(void) { - return &anim_hacker[0]; -} - -static badge_sprite const anim_sickle[] = { - { 3, 3, (uint8_t const *) "\xab\x01" }, - { 3, 3, (uint8_t const *) "\xee\x00" } -/* - { 3, 3, (uint8_t const *) "\x8a\x01" }, - { 3, 3, (uint8_t const *) "\x6a" }, - { 3, 3, (uint8_t const *) "\xa3" }, - { 3, 3, (uint8_t const *) "\xac" } -*/ -}; - -enum { - JUMPNRUN_SHOT_EXTENT = 3, - JUMPNRUN_SHOT_TICKS_PER_FRAME = 36 -}; - -static void jumpnrun_shot_spawn(jumpnrun_shot *shot, jumpnrun_game_state const *state) { - shot->tick = 0; - shot->inertia = shot_spawn_inertia; - - if(state->player.anim_direction == BADGE_BLT_MIRRORED) { - shot->current_box = rectangle_new((vec2d) { fixed_point_sub(rectangle_left(&state->player.current_box), FIXED_INT(JUMPNRUN_SHOT_EXTENT)), rectangle_top(&state->player.current_box) }, - (vec2d) { FIXED_INT(JUMPNRUN_SHOT_EXTENT), FIXED_INT(JUMPNRUN_SHOT_EXTENT) }); - shot->inertia.x = fixed_point_neg(shot->inertia.x); - } else { - shot->current_box = rectangle_new((vec2d) { rectangle_right(&state->player.current_box), rectangle_top(&state->player.current_box) }, - (vec2d) { FIXED_INT(JUMPNRUN_SHOT_EXTENT), FIXED_INT(JUMPNRUN_SHOT_EXTENT) }); - } - - shot->old_box = shot->current_box; - shot->inertia = vec2d_add(shot->inertia, state->player.inertia); -} - static inline int imax(int x, int y) { return x < y ? y : x; } static inline fixed_point hacker_left (vec2d const *pos, jumpnrun_game_state const *state) { (void) state; return pos->x; } static inline fixed_point hacker_top (vec2d const *pos, jumpnrun_game_state const *state) { (void) state; return pos->y; } -static inline fixed_point hacker_right (vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_left(pos, state), hacker_extents().x); } -static inline fixed_point hacker_bottom(vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_top (pos, state), hacker_extents().y); } +static inline fixed_point hacker_right (vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_left(pos, state), jumpnrun_player_extents().x); } +static inline fixed_point hacker_bottom(vec2d const *pos, jumpnrun_game_state const *state) { return fixed_point_add(hacker_top (pos, state), jumpnrun_player_extents().y); } int jumpnrun_level_assert_left_side(jumpnrun_game_state const *state) { static int const lmargin = 20; static int const rmargin = 50; - int pos_cur = fixed_point_cast_int(state->player.current_box.pos.x); - int pos_rel = pos_cur - state->left; + int pos_cur = fixed_point_cast_int(state->player.base.hitbox.pos.x); + int pos_rel = pos_cur - state->screen_left; if(pos_rel < lmargin) { return imax(0, pos_cur - lmargin); @@ -107,7 +44,7 @@ int jumpnrun_level_assert_left_side(jumpnrun_game_state const *state) { return pos_cur - (BADGE_DISPLAY_WIDTH - rmargin); } - return state->left; + return state->screen_left; } static int jumpnrun_bsearch_tile(jumpnrun_level const *lv, jumpnrun_game_state const *state) { @@ -117,7 +54,7 @@ static int jumpnrun_bsearch_tile(jumpnrun_level const *lv, jumpnrun_game_state c while(len > 0) { int mid = front + len / 2; - if(fixed_point_lt(tile_right(&lv->tiles[mid]), FIXED_INT(state->left - JUMPNRUN_MAX_SPAWN_MARGIN))) { + if(fixed_point_lt(tile_right(&lv->tiles[mid]), FIXED_INT(state->screen_left - JUMPNRUN_MAX_SPAWN_MARGIN))) { front = mid + 1; len -= len / 2 + 1; } else { @@ -135,16 +72,20 @@ jumpnrun_tile_range jumpnrun_visible_tiles(jumpnrun_level const *lv, r.first = jumpnrun_bsearch_tile(lv, state); for(r.last = r.first; - r.last < lv->header.tile_count && lv->tiles[r.last].pos.x * JUMPNRUN_TILE_PIXEL_WIDTH < state->left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN; + r.last < lv->header.tile_count && lv->tiles[r.last].pos.x * JUMPNRUN_TILE_PIXEL_WIDTH < state->screen_left + BADGE_DISPLAY_WIDTH + JUMPNRUN_MAX_SPAWN_MARGIN; ++r.last) ; return r; } +void jumpnrun_apply_gravity(vec2d *inertia) { + *inertia = vec2d_add(*inertia, gravity); +} + void jumpnrun_passive_movement(vec2d *inertia) { - *inertia = vec2d_add(*inertia, gravity); + jumpnrun_apply_gravity(inertia); inertia->x = fixed_point_min(fixed_point_max(fixed_point_neg(move_max.x), inertia->x), move_max.x); inertia->y = fixed_point_min(fixed_point_max(fixed_point_neg(move_max.y), inertia->y), move_max.y); @@ -158,49 +99,49 @@ static void jumpnrun_apply_movement(jumpnrun_level const *lv, (BADGE_EVENT_KEY_LEFT | BADGE_EVENT_KEY_RIGHT)) { case BADGE_EVENT_KEY_LEFT: - // state->player.inertia.x = state->player.touching_ground ? fixed_point_sub(state->player.inertia.x, accel_horiz) : fixed_point_neg(speed_jump_x); - state->player.inertia.x = fixed_point_sub(state->player.inertia.x, accel_horiz); - state->player.anim_direction = BADGE_BLT_MIRRORED; + // state->player.base.inertia.x = state->player.touching_ground ? fixed_point_sub(state->player.base.inertia.x, accel_horiz) : fixed_point_neg(speed_jump_x); + state->player.base.inertia.x = fixed_point_sub(state->player.base.inertia.x, accel_horiz); + state->player.base.flags |= JUMPNRUN_MOVEABLE_MIRRORED; break; case BADGE_EVENT_KEY_RIGHT: - // state->player.inertia.x = state->player.touching_ground ? fixed_point_add(state->player.inertia.x, accel_horiz) : speed_jump_x; - state->player.inertia.x = fixed_point_add(state->player.inertia.x, accel_horiz); - state->player.anim_direction = 0; + // state->player.base.inertia.x = state->player.touching_ground ? fixed_point_add(state->player.base.inertia.x, accel_horiz) : speed_jump_x; + state->player.base.inertia.x = fixed_point_add(state->player.base.inertia.x, accel_horiz); + state->player.base.flags &= ~JUMPNRUN_MOVEABLE_MIRRORED; break; default: - if(state->player.touching_ground) { - state->player.inertia.x = fixed_point_mul(state->player.inertia.x, drag_factor); + if(jumpnrun_moveable_touching_ground(&state->player.base)) { + state->player.base.inertia.x = fixed_point_mul(state->player.base.inertia.x, drag_factor); } //else { - //state->player.inertia.x = FIXED_INT(0); + //state->player.base.inertia.x = FIXED_INT(0); //} break; } - if(state->player.jumpable_frames == 0) { + if(state->player.base.jumpable_frames == 0) { // intentionally left blank. } else if(badge_event_current_input_state() & BADGE_EVENT_KEY_BTN_A) { - state->player.inertia.y = fixed_point_sub(state->player.inertia.y, accel_vert); - --state->player.jumpable_frames; + state->player.base.inertia.y = fixed_point_sub(state->player.base.inertia.y, accel_vert); + --state->player.base.jumpable_frames; } else { - state->player.jumpable_frames = 0; + state->player.base.jumpable_frames = 0; } - jumpnrun_passive_movement(&state->player.inertia); + jumpnrun_passive_movement(&state->player.base.inertia); - vec2d new_pos = vec2d_add(state->player.current_box.pos, state->player.inertia); + vec2d new_pos = vec2d_add(state->player.base.hitbox.pos, state->player.base.inertia); - if(fixed_point_lt(new_pos.x, FIXED_INT(state->left))) { - new_pos.x = FIXED_INT(state->left); - state->player.inertia.x = FIXED_INT(0); + if(fixed_point_lt(new_pos.x, FIXED_INT(state->screen_left))) { + new_pos.x = FIXED_INT(state->screen_left); + state->player.base.inertia.x = FIXED_INT(0); } - *inertia_mod = state->player.inertia; - bool killed = collisions_tiles_displace(&new_pos, &state->player, lv, tilerange, inertia_mod); - state->player.inertia = *inertia_mod; + *inertia_mod = state->player.base.inertia; + bool killed = collisions_tiles_displace(&new_pos, &state->player.base, lv, tilerange, inertia_mod); + state->player.base.inertia = *inertia_mod; - if(killed || fixed_point_gt(state->player.current_box.pos.y, FIXED_INT(BADGE_DISPLAY_HEIGHT))) { - state->status = JUMPNRUN_DEAD; + if(killed || fixed_point_gt(state->player.base.hitbox.pos.y, FIXED_INT(BADGE_DISPLAY_HEIGHT))) { + state->player.base.flags |= JUMPNRUN_PLAYER_DEAD; } } @@ -208,21 +149,17 @@ void jumpnrun_level_tick(jumpnrun_level *lv, jumpnrun_game_state *state) { jumpnrun_tile_range tilerange = jumpnrun_visible_tiles(lv, state); - vec2d inertia_mod = state->player.inertia; + vec2d inertia_mod = state->player.base.inertia; jumpnrun_apply_movement(lv, &tilerange, state, &inertia_mod); - state->left = jumpnrun_level_assert_left_side(state); + state->screen_left = jumpnrun_level_assert_left_side(state); - if(state->player.tick_minor == 0) { + if(state->player.base.tick_minor == 0) { badge_framebuffer fb; badge_framebuffer_clear(&fb); for(size_t tile = tilerange.first; tile < tilerange.last; ++tile) { - badge_framebuffer_blt(&fb, - fixed_point_cast_int(tile_left(&lv->tiles[tile])) - state->left, - fixed_point_cast_int(tile_top (&lv->tiles[tile])), - &tile_type(&lv->tiles[tile])->sprite, - 0); + jumpnrun_render_tile(&fb, state, &lv->tiles[tile]); } for(size_t item = 0; item < lv->header.item_count; ++item) { @@ -232,54 +169,24 @@ void jumpnrun_level_tick(jumpnrun_level *lv, continue; } - int screenpos = fixed_point_cast_int(item_obj->pos.x) - state->left; + int screenpos = fixed_point_cast_int(item_obj->pos.x) - state->screen_left; if(screenpos > -item_obj->type->sprite.width && screenpos < BADGE_DISPLAY_WIDTH) { rectangle item_rect = rect_from_item(item_obj); - if(rectangle_intersect(&state->player.current_box, &item_rect)) { + if(rectangle_intersect(&state->player.base.hitbox, &item_rect)) { item_obj->type->on_collect(item_obj, state, lv); } - badge_framebuffer_blt(&fb, - screenpos, - fixed_point_cast_int(item_obj->pos.y), - &item_obj->type->sprite, - 0); + jumpnrun_render_item(&fb, state, item_obj); } } for(size_t shot_ix = 0; shot_ix < JUMPNRUN_MAX_SHOTS; ++shot_ix) { jumpnrun_shot *shot = &state->shots[shot_ix]; - + jumpnrun_shot_process(shot); if(jumpnrun_shot_spawned(shot)) { - rectangle_move_rel(&shot->current_box, shot->inertia); - shot->inertia = vec2d_add(shot->inertia, gravity); - - if(fixed_point_gt(rectangle_top(&shot->current_box), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { - jumpnrun_shot_despawn(shot); - } - - /* show every position twice, because LCD switching time. This makes the shots more - * visible on the nokia lcds. - */ - badge_framebuffer_blt(&fb, - fixed_point_cast_int(shot->old_box.pos.x) - state->left, - fixed_point_cast_int(shot->old_box.pos.y), - &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], - fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); - badge_framebuffer_blt(&fb, - fixed_point_cast_int(shot->current_box.pos.x) - state->left, - fixed_point_cast_int(shot->current_box.pos.y), - &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], - fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); - - shot->old_box = shot->current_box; - - ++shot->tick; - if(shot->tick == ARRAY_SIZE(anim_sickle) * JUMPNRUN_SHOT_TICKS_PER_FRAME) { - shot->tick = 0; - } + jumpnrun_render_shot(&fb, state, shot); } } @@ -288,38 +195,20 @@ void jumpnrun_level_tick(jumpnrun_level *lv, jumpnrun_process_enemy(enemy, &fb, state, lv, &tilerange, &inertia_mod); } - badge_framebuffer_blt(&fb, - fixed_point_cast_int(state->player.current_box.pos.x) - state->left, - fixed_point_cast_int(state->player.current_box.pos.y), - &anim_hacker[state->player.anim_frame], - state->player.anim_direction); + jumpnrun_render_player(&fb, state); badge_framebuffer_flush(&fb); - if(!state->player.touching_ground) { - state->player.anim_frame = 2; - } else if(fixed_point_gt(fixed_point_abs(state->player.inertia.x), FIXED_POINT(0, 200))) { - state->player.anim_frame = (state->player.anim_frame + 1) % ARRAY_SIZE(anim_hacker); + if(!jumpnrun_moveable_touching_ground(&state->player.base)) { + state->player.base.anim_frame = 2; + } else if(fixed_point_gt(fixed_point_abs(state->player.base.inertia.x), FIXED_POINT(0, 200))) { + state->player.base.anim_frame = (state->player.base.anim_frame + 1) % JUMPNRUN_PLAYER_FRAMES; } else { - state->player.anim_frame = 0; + state->player.base.anim_frame = 0; } } else { for(size_t shot_ix = 0; shot_ix < JUMPNRUN_MAX_SHOTS; ++shot_ix) { - jumpnrun_shot *shot = &state->shots[shot_ix]; - - if(jumpnrun_shot_spawned(shot)) { - rectangle_move_rel(&shot->current_box, shot->inertia); - shot->inertia = vec2d_add(shot->inertia, gravity); - - if(fixed_point_gt(rectangle_top(&shot->current_box), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { - jumpnrun_shot_despawn(shot); - } - - ++shot->tick; - if(shot->tick == ARRAY_SIZE(anim_sickle) * JUMPNRUN_SHOT_TICKS_PER_FRAME) { - shot->tick = 0; - } - } + jumpnrun_shot_process(&state->shots[shot_ix]); } for(size_t enemy_ix = 0; enemy_ix < lv->header.enemy_count; ++enemy_ix) { @@ -328,10 +217,10 @@ void jumpnrun_level_tick(jumpnrun_level *lv, } } - state->player.inertia = inertia_mod; - ++state->player.tick_minor; - if(state->player.tick_minor == 3) { - state->player.tick_minor = 0; + state->player.base.inertia = inertia_mod; + ++state->player.base.tick_minor; + if(state->player.base.tick_minor == 3) { + state->player.base.tick_minor = 0; } } @@ -341,36 +230,13 @@ uint8_t jumpnrun_play(char const *lvname) { JUMPNRUN_LEVEL_LOAD(lv, lvname); jumpnrun_game_state gs; - memset(&gs, 0, sizeof(gs)); - for(gs.lives = 99; gs.status != JUMPNRUN_WON && gs.lives != 0; --gs.lives) { + for(jumpnrun_game_state_init(&gs, &lv); (gs.flags & JUMPNRUN_STATE_WON) == 0 && gs.player.lives != 0; --gs.player.lives) { jumpnrun_show_lives_screen(&gs); + jumpnrun_game_state_respawn(&gs, &lv); - for(uint8_t i = 0; i < 75; ) { - badge_event_t ev = badge_event_wait(); - if(badge_event_type(ev) == BADGE_EVENT_GAME_TICK) { - ++i; - } else if(i > 25) { - uint8_t old_state = badge_event_old_input_state(ev); - uint8_t new_state = badge_event_new_input_state(ev); - uint8_t new_buttons = new_state & (old_state ^ new_state); - - if(new_buttons != 0) break; - } - } - - gs.status = JUMPNRUN_PLAYING; - gs.left = 0; - memset(&gs.player, 0, sizeof(gs.player)); - memset(&gs.shots , 0, sizeof(gs.shots )); - gs.player.current_box = rectangle_new(lv.start_pos, - hacker_extents()); - - for(size_t i = 0; i < lv.header.enemy_count; ++i) { - lv.enemies[i].flags = 0; - } - - while(gs.status == JUMPNRUN_PLAYING) { + while((gs.player.base.flags & JUMPNRUN_PLAYER_DEAD) == 0 && + (gs. flags & JUMPNRUN_STATE_WON ) == 0) { badge_event_t ev = badge_event_wait(); switch(badge_event_type(ev)) { @@ -380,8 +246,8 @@ uint8_t jumpnrun_play(char const *lvname) { uint8_t new_state = badge_event_new_input_state(ev); uint8_t new_buttons = new_state & (old_state ^ new_state); - if((new_buttons & BADGE_EVENT_KEY_BTN_A) && gs.player.touching_ground) { - gs.player.jumpable_frames = 12; + if((new_buttons & BADGE_EVENT_KEY_BTN_A) && jumpnrun_moveable_touching_ground(&gs.player.base)) { + gs.player.base.jumpable_frames = 12; } if((new_buttons & BADGE_EVENT_KEY_BTN_B)) { @@ -405,5 +271,7 @@ uint8_t jumpnrun_play(char const *lvname) { } } - return gs.status; + if(gs.flags & JUMPNRUN_STATE_WON) { return JUMPNRUN_WON; } + if(gs.player.lives == 0) return JUMPNRUN_LOST; + return JUMPNRUN_ERROR; } diff --git a/badge/jumpnrun/jumpnrun.h b/badge/jumpnrun/jumpnrun.h index f2933d9..5c4024b 100644 --- a/badge/jumpnrun/jumpnrun.h +++ b/badge/jumpnrun/jumpnrun.h @@ -4,6 +4,7 @@ #include "enemies.h" #include "items.h" #include "levels.h" +#include "shots.h" #include "tiles.h" #include "../ui/sprite.h" @@ -14,8 +15,8 @@ enum { JUMPNRUN_PLAYING, - JUMPNRUN_DEAD, JUMPNRUN_WON, + JUMPNRUN_LOST, JUMPNRUN_ERROR }; @@ -24,32 +25,8 @@ enum { JUMPNRUN_MAX_SPAWNED_ENEMIES = 10 }; -typedef struct jumpnrun_shot { - rectangle old_box; - rectangle current_box; - vec2d inertia; - uint8_t tick; -} jumpnrun_shot; - -static inline bool jumpnrun_shot_spawned(jumpnrun_shot const *shot) { return fixed_point_ne(shot->inertia.x, FIXED_INT(0)); } -static inline void jumpnrun_shot_despawn(jumpnrun_shot *shot) { shot->inertia.x = FIXED_INT(0); } - -enum { - JUMPNRUN_MAX_SHOTS = 2 -}; - -typedef struct jumpnrun_game_state { - jumpnrun_moveable player; - - uint8_t status; - int left; - uint8_t lives; - uint8_t keys; - - jumpnrun_shot shots[JUMPNRUN_MAX_SHOTS]; -} jumpnrun_game_state; - -vec2d hacker_extents(void); +vec2d jumpnrun_player_extents(void); +void jumpnrun_apply_gravity(vec2d *inertia); void jumpnrun_passive_movement(vec2d *inertia); badge_sprite const *jumpnrun_hacker_symbol(void); diff --git a/badge/jumpnrun/level_load.c b/badge/jumpnrun/level_load.c index 21e2541..4b1e499 100644 --- a/badge/jumpnrun/level_load.c +++ b/badge/jumpnrun/level_load.c @@ -51,10 +51,9 @@ static void jumpnrun_level_make_enemy(jumpnrun_enemy *dest, level_thing thing) { dest->type = &jumpnrun_enemy_type_data[thing.type]; - dest->spawn_pos.x = FIXED_POINT( thing.x * JUMPNRUN_TILE_PIXEL_WIDTH , 0); - dest->spawn_pos.y = FIXED_POINT((thing.y + 1) * JUMPNRUN_TILE_PIXEL_HEIGHT - dest->type->animation_frames[0].height, 0); - dest->base.current_box = rectangle_new(dest->spawn_pos, dest->type->extent); - dest->base.inertia = dest->type->spawn_inertia; + dest->spawn_pos.x = FIXED_POINT( thing.x * JUMPNRUN_TILE_PIXEL_WIDTH , 0); + dest->spawn_pos.y = FIXED_POINT((thing.y + 1) * JUMPNRUN_TILE_PIXEL_HEIGHT - dest->type->animation_frames[0].height, 0); + jumpnrun_enemy_despawn(dest); } #ifdef __linux__ @@ -97,7 +96,7 @@ int jumpnrun_load_level_from_file(jumpnrun_level *dest, FIL *fd) { #endif return JUMPNRUN_LEVEL_LOAD_ERROR; } else { - dest->start_pos.x = fixed_point_sub(FIXED_INT((spos[0] + 1) * JUMPNRUN_TILE_PIXEL_WIDTH ), hacker_extents().x); + dest->start_pos.x = fixed_point_sub(FIXED_INT((spos[0] + 1) * JUMPNRUN_TILE_PIXEL_WIDTH ), jumpnrun_player_extents().x); dest->start_pos.y = FIXED_INT( spos[1] * JUMPNRUN_TILE_PIXEL_HEIGHT); } diff --git a/badge/jumpnrun/levels.txt b/badge/jumpnrun/levels.txt index 2ea1909..6c940c8 100644 --- a/badge/jumpnrun/levels.txt +++ b/badge/jumpnrun/levels.txt @@ -1,7 +1,7 @@ +smb lubiXOXO lubilove gnobbel -smb wrongturn foo mean diff --git a/badge/jumpnrun/moveable.c b/badge/jumpnrun/moveable.c new file mode 100644 index 0000000..26789d3 --- /dev/null +++ b/badge/jumpnrun/moveable.c @@ -0,0 +1 @@ +#include "moveable.h" diff --git a/badge/jumpnrun/moveable.h b/badge/jumpnrun/moveable.h index 5e7514b..7b680d2 100644 --- a/badge/jumpnrun/moveable.h +++ b/badge/jumpnrun/moveable.h @@ -2,17 +2,26 @@ #define INCLUDED_BADGE_JUMPNRUN_MOVEABLE_H #include "../util/util.h" +#include + +enum { + // Do not collide with JUMPNRUN_ENEMY_* and JUMPNRUN_PLAYER_* flags. + JUMPNRUN_MOVEABLE_TOUCHING_GROUND = 1, + JUMPNRUN_MOVEABLE_MIRRORED = 2 +}; typedef struct jumpnrun_moveable { - rectangle current_box; + rectangle hitbox; vec2d inertia; uint8_t tick_minor; uint8_t anim_frame; - uint8_t anim_direction; - bool touching_ground; + uint8_t flags; uint8_t jumpable_frames; } jumpnrun_moveable; +static inline bool jumpnrun_moveable_touching_ground(jumpnrun_moveable const *self) { return self->flags & JUMPNRUN_MOVEABLE_TOUCHING_GROUND; } +static inline bool jumpnrun_moveable_mirrored (jumpnrun_moveable const *self) { return self->flags & JUMPNRUN_MOVEABLE_MIRRORED ; } + #endif diff --git a/badge/jumpnrun/player.h b/badge/jumpnrun/player.h new file mode 100644 index 0000000..1b193b5 --- /dev/null +++ b/badge/jumpnrun/player.h @@ -0,0 +1,27 @@ +#ifndef INCLUDED_BADGE_JUMPNRUN_PLAYER_H +#define INCLUDED_BADGE_JUMPNRUN_PLAYER_H + +#include "moveable.h" +#include "../ui/display.h" +#include "../util/util.h" + +enum { + // Do not collide with JUMPNRUN_MOVEABLE_* flags + JUMPNRUN_PLAYER_DEAD = 4 +}; + +enum { + JUMPNRUN_PLAYER_FRAMES = 4 +}; + +typedef struct jumpnrun_player { + jumpnrun_moveable base; + + uint8_t lives; + uint8_t keys; +} jumpnrun_player; + +void jumpnrun_player_spawn (jumpnrun_player *self, vec2d spawn_pos, uint8_t lives); +void jumpnrun_player_respawn (jumpnrun_player *self, vec2d spawn_pos); + +#endif diff --git a/badge/jumpnrun/render.c b/badge/jumpnrun/render.c new file mode 100644 index 0000000..3755aa6 --- /dev/null +++ b/badge/jumpnrun/render.c @@ -0,0 +1,74 @@ +#include "render.h" + +static badge_sprite const anim_sickle[JUMPNRUN_SHOT_FRAMES] = { + { 3, 3, (uint8_t const *) "\xab\x01" }, + { 3, 3, (uint8_t const *) "\xee" } +}; + +static badge_sprite const anim_player[JUMPNRUN_PLAYER_FRAMES ] = { + { 5, 8, (uint8_t const *) "\x1c\xff\xfd\x04\x04" }, + { 5, 8, (uint8_t const *) "\x1c\xff\x3d\xc4\x04" }, + { 5, 8, (uint8_t const *) "\xdc\x3f\x1d\x24\xc4" }, + { 5, 8, (uint8_t const *) "\x1c\xff\x3d\xc4\x04" } +}; + +vec2d jumpnrun_player_extents(void) { return (vec2d) { FIXED_INT_I(5), FIXED_INT_I(8) }; } + +void jumpnrun_render_moveable (badge_framebuffer *fb, jumpnrun_game_state const *state, jumpnrun_moveable const *moveable, badge_sprite const *animation, vec2d sprite_offset) { + vec2d render_pos = vec2d_sub(moveable->hitbox.pos, sprite_offset); + badge_framebuffer_blt(fb, + fixed_point_cast_int(render_pos.x) - jumpnrun_screen_left(state), + fixed_point_cast_int(render_pos.y), + &animation[moveable->anim_frame], + (moveable->flags & JUMPNRUN_MOVEABLE_MIRRORED) ? BADGE_BLT_MIRRORED : 0); +} + +void jumpnrun_render_player (badge_framebuffer *fb, jumpnrun_game_state const *state) { + jumpnrun_render_moveable(fb, state, &state->player.base, anim_player, (vec2d) { FIXED_INT(0), FIXED_INT(0) }); +} + +void jumpnrun_render_shot (badge_framebuffer *fb, jumpnrun_game_state const *state, jumpnrun_shot *shot ) { + /* show every position twice, because LCD switching time. This makes the shots more + * visible on the nokia lcds. + */ + badge_framebuffer_blt(fb, + fixed_point_cast_int(shot->old_box.pos.x) - jumpnrun_screen_left(state), + fixed_point_cast_int(shot->old_box.pos.y), + &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], + fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); + badge_framebuffer_blt(fb, + fixed_point_cast_int(shot->current_box.pos.x) - jumpnrun_screen_left(state), + fixed_point_cast_int(shot->current_box.pos.y), + &anim_sickle[shot->tick / JUMPNRUN_SHOT_TICKS_PER_FRAME], + fixed_point_lt(shot->inertia.x, FIXED_INT(0)) ? BADGE_BLT_MIRRORED : 0); + + shot->old_box = shot->current_box; +} + +void jumpnrun_render_enemy (badge_framebuffer *fb, jumpnrun_game_state const *state, jumpnrun_enemy const *enemy ) { + jumpnrun_render_moveable(fb, state, &enemy->base, enemy->type->animation_frames, enemy->type->hitbox.pos); +} + +void jumpnrun_render_tile (badge_framebuffer *fb, jumpnrun_game_state const *state, jumpnrun_tile const *tile ) { + badge_framebuffer_blt(fb, + tile->pos.x * JUMPNRUN_TILE_PIXEL_WIDTH - jumpnrun_screen_left(state), + tile->pos.y * JUMPNRUN_TILE_PIXEL_HEIGHT, + &tile_type(tile)->sprite, + 0); +} + +void jumpnrun_render_item (badge_framebuffer *fb, jumpnrun_game_state const *state, jumpnrun_item const *item ) { + badge_framebuffer_blt(fb, + fixed_point_cast_int(item->pos.x) - jumpnrun_screen_left(state), + fixed_point_cast_int(item->pos.y), + &item->type->sprite, + 0); +} + +void jumpnrun_render_player_symbol(badge_framebuffer *fb, int8_t x, int8_t y) { + badge_framebuffer_blt(fb, x, y, &anim_player[0], 0); +} + +void jumpnrun_render_key_symbol (badge_framebuffer *fb, int8_t x, int8_t y) { + badge_framebuffer_blt(fb, x, y, &jumpnrun_item_type_data[JUMPNRUN_ITEM_TYPE_KEY].sprite, 0); +} diff --git a/badge/jumpnrun/shots.c b/badge/jumpnrun/shots.c new file mode 100644 index 0000000..275682d --- /dev/null +++ b/badge/jumpnrun/shots.c @@ -0,0 +1,19 @@ +#include "shots.h" +#include "jumpnrun.h" +#include "render.h" + +void jumpnrun_shot_process(jumpnrun_shot *shot) { + if(jumpnrun_shot_spawned(shot)) { + rectangle_move_rel(&shot->current_box, shot->inertia); + jumpnrun_apply_gravity(&shot->inertia); + + if(fixed_point_gt(rectangle_top(&shot->current_box), FIXED_INT(BADGE_DISPLAY_HEIGHT))) { + jumpnrun_shot_despawn(shot); + } + + ++shot->tick; + if(shot->tick == JUMPNRUN_SHOT_FRAMES * JUMPNRUN_SHOT_TICKS_PER_FRAME) { + shot->tick = 0; + } + } +} diff --git a/badge/jumpnrun/shots.h b/badge/jumpnrun/shots.h new file mode 100644 index 0000000..66e0501 --- /dev/null +++ b/badge/jumpnrun/shots.h @@ -0,0 +1,27 @@ +#ifndef INCLUDED_BADGE_JUMPNRUN_SHOTS_H +#define INCLUDED_BADGE_JUMPNRUN_SHOTS_H + +#include "../ui/display.h" +#include "../util/util.h" +#include +#include + +typedef struct jumpnrun_shot { + rectangle old_box; + rectangle current_box; + vec2d inertia; + uint8_t tick; +} jumpnrun_shot; + +enum { + JUMPNRUN_SHOT_EXTENT = 3, + JUMPNRUN_SHOT_TICKS_PER_FRAME = 36, + JUMPNRUN_SHOT_FRAMES = 2 +}; + +static inline bool jumpnrun_shot_spawned(jumpnrun_shot const *shot) { return fixed_point_ne(shot->inertia.x, FIXED_INT(0)); } +static inline void jumpnrun_shot_despawn(jumpnrun_shot *shot) { shot->inertia.x = FIXED_INT(0); } + +void jumpnrun_shot_process(jumpnrun_shot *shot); + +#endif diff --git a/badge/jumpnrun/stats.c b/badge/jumpnrun/stats.c index 74338ec..cbcb24b 100644 --- a/badge/jumpnrun/stats.c +++ b/badge/jumpnrun/stats.c @@ -1,35 +1,49 @@ #include "stats.h" -#include "jumpnrun.h" + #include "items.h" +#include "jumpnrun.h" +#include "render.h" + #include "../ui/display.h" +#include "../ui/event.h" #include "../ui/font.h" void jumpnrun_show_lives_screen(jumpnrun_game_state const *state) { badge_framebuffer fb = { { { 0 } } }; - badge_sprite const *hacker = jumpnrun_hacker_symbol(); - badge_sprite const *key = &jumpnrun_item_type_data[JUMPNRUN_ITEM_TYPE_KEY].sprite; - int8_t y_upper = BADGE_DISPLAY_HEIGHT / 2 - BADGE_FONT_HEIGHT; int8_t y_lower = (BADGE_DISPLAY_HEIGHT + BADGE_FONT_HEIGHT) / 2; - int8_t x_left = BADGE_DISPLAY_WIDTH / 2 - hacker->width - BADGE_FONT_WIDTH - 5; + int8_t x_left = BADGE_DISPLAY_WIDTH / 2 - fixed_point_cast_int(jumpnrun_player_extents().y) - BADGE_FONT_WIDTH - 5; int8_t x_mid = (BADGE_DISPLAY_WIDTH - BADGE_FONT_WIDTH) / 2; int8_t x_right = x_mid + BADGE_FONT_WIDTH + 5; char buf[] = "x"; - if(state->keys != 0) { + if(state->player.keys != 0) { y_upper -= BADGE_FONT_HEIGHT; } - badge_framebuffer_blt (&fb, x_left , y_upper, hacker, 0); + jumpnrun_render_player_symbol(&fb, x_left, y_upper); badge_framebuffer_render_text (&fb, x_mid , y_upper, buf); - badge_framebuffer_render_number(&fb, x_right, y_upper, state->lives); + badge_framebuffer_render_number(&fb, x_right, y_upper, state->player.lives); - if(state->keys != 0) { - badge_framebuffer_blt (&fb, x_left , y_lower, key, 0); + if(state->player.keys != 0) { + jumpnrun_render_key_symbol(&fb, x_left, y_lower); badge_framebuffer_render_text (&fb, x_mid , y_lower, buf); - badge_framebuffer_render_number(&fb, x_right, y_lower, state->keys); + badge_framebuffer_render_number(&fb, x_right, y_lower, state->player.keys); } badge_framebuffer_flush(&fb); + + for(uint8_t i = 0; i < 75; ) { + badge_event_t ev = badge_event_wait(); + if(badge_event_type(ev) == BADGE_EVENT_GAME_TICK) { + ++i; + } else if(i > 25) { + uint8_t old_state = badge_event_old_input_state(ev); + uint8_t new_state = badge_event_new_input_state(ev); + uint8_t new_buttons = new_state & (old_state ^ new_state); + + if(new_buttons != 0) break; + } + } } diff --git a/badge/jumpnrun/stats.h b/badge/jumpnrun/stats.h index e9e8950..170e130 100644 --- a/badge/jumpnrun/stats.h +++ b/badge/jumpnrun/stats.h @@ -1,7 +1,7 @@ #ifndef INCLUDED_BADGE_JUMPNRUN_STATS_H #define INCLUDED_BADGE_JUMPNRUN_STATS_H -#include "jumpnrun.h" +#include "game_state.h" void jumpnrun_show_lives_screen(jumpnrun_game_state const *state); diff --git a/badge/jumpnrun/tiles.h b/badge/jumpnrun/tiles.h index a6a5f70..3ce7869 100644 --- a/badge/jumpnrun/tiles.h +++ b/badge/jumpnrun/tiles.h @@ -39,10 +39,10 @@ typedef struct jumpnrun_tile_range { size_t last; // actually one past last. } jumpnrun_tile_range; -static inline fixed_point tile_left (jumpnrun_tile const *tile) { return FIXED_POINT(tile->pos.x * JUMPNRUN_TILE_PIXEL_WIDTH , 0); } -static inline fixed_point tile_top (jumpnrun_tile const *tile) { return FIXED_POINT(tile->pos.y * JUMPNRUN_TILE_PIXEL_HEIGHT, 0); } -static inline fixed_point tile_right (jumpnrun_tile const *tile) { return fixed_point_add(tile_left(tile), FIXED_POINT(JUMPNRUN_TILE_PIXEL_WIDTH , 0)); } -static inline fixed_point tile_bottom(jumpnrun_tile const *tile) { return fixed_point_add(tile_top (tile), FIXED_POINT(JUMPNRUN_TILE_PIXEL_HEIGHT, 0)); } +static inline fixed_point tile_left (jumpnrun_tile const *tile) { return FIXED_INT(tile->pos.x * JUMPNRUN_TILE_PIXEL_WIDTH ); } +static inline fixed_point tile_top (jumpnrun_tile const *tile) { return FIXED_INT(tile->pos.y * JUMPNRUN_TILE_PIXEL_HEIGHT); } +static inline fixed_point tile_right (jumpnrun_tile const *tile) { return fixed_point_add(tile_left(tile), FIXED_INT(JUMPNRUN_TILE_PIXEL_WIDTH )); } +static inline fixed_point tile_bottom(jumpnrun_tile const *tile) { return fixed_point_add(tile_top (tile), FIXED_INT(JUMPNRUN_TILE_PIXEL_HEIGHT)); } /************************************/ diff --git a/badge/util/rectangle.h b/badge/util/rectangle.h index 4fe5c0e..70d43ba 100644 --- a/badge/util/rectangle.h +++ b/badge/util/rectangle.h @@ -13,7 +13,14 @@ static inline vec2d vec2d_add(vec2d v1, vec2d v2) { fixed_point_add(v1.x, v2.x), fixed_point_add(v1.y, v2.y) }; + return r; +} +static inline vec2d vec2d_sub(vec2d v1, vec2d v2) { + vec2d r = { + fixed_point_sub(v1.x, v2.x), + fixed_point_sub(v1.y, v2.y) + }; return r; } diff --git a/mock/Makefile b/mock/Makefile index 93a7210..33b4ca5 100644 --- a/mock/Makefile +++ b/mock/Makefile @@ -21,11 +21,16 @@ BADGE_CSRCS = badge_main_loop.c \ ui/sprite.c \ jumpnrun/collision.c \ jumpnrun/enemies.c \ + jumpnrun/game_state.c \ jumpnrun/items.c \ jumpnrun/jumpnrun.c \ - jumpnrun/tiles.c \ jumpnrun/level_load.c \ - jumpnrun/stats.c + jumpnrun/moveable.c \ + jumpnrun/player.c \ + jumpnrun/render.c \ + jumpnrun/shots.c \ + jumpnrun/stats.c \ + jumpnrun/tiles.c BADGE_CXXOBJS = $(BADGE_CXXSRCS:%.cc=%.o) BADGE_COBJS = $(BADGE_CSRCS:%.c=%.o) -- 2.20.1