void enemy_tick_fly_straight_and_dip(struct jumpnrun_enemy *self, struct jumpnrun_game_state *state, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { 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->base.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_pos_hitbox(self).y))); } else { self->base.inertia.y = FIXED_INT(0); } enemy_tick_common(self, state, lv, visible_tiles, player_inertia_mod); enemy_animation_advance(self); }
void enemy_tick_dog(jumpnrun_enemy *self, jumpnrun_game_state *state, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { jumpnrun_passive_movement(&self->base.inertia); 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) { case 12: self->base.tick_minor = 0; case 0: case 2: case 4: case 6: self->base.anim_frame = 0; 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; } break; case 1: case 3: case 5: case 7: self->base.anim_frame = 1; 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; } break; case 8: case 10: self->base.anim_frame = 2; self->base.inertia.x = FIXED_INT(0); break; case 9: case 11: self->base.anim_frame = 3; self->base.inertia.x = FIXED_INT(0); break; } } ++self->base.tick_minor; }
void enemy_tick_giraffe(jumpnrun_enemy *self, jumpnrun_game_state *state, jumpnrun_level *lv, jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { 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); 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.base.hitbox), rectangle_mid_x(enemy_hitbox(self)))) { self->base.inertia.x = fixed_point_neg(self->base.inertia.x); } } } else { self->base.tick_minor = 0; self->base.anim_frame = 3; self->base.inertia.x = FIXED_INT(0); } } else if(was_on_ground) { self->base.tick_minor = 0; self->base.anim_frame = 1; } else if(self->base.anim_frame == 1) { enemy_animation_advance(self); } ++self->base.tick_minor; }
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) { // 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 if(jumpnrun_moveable_dying(&self->base)) { if(jumpnrun_moveable_finished_dying(&self->base)) { jumpnrun_enemy_despawn(self); } else { if(fb) { jumpnrun_render_splosion(fb, state, &self->base); } ++self->base.tick_minor; } } else { if((self->base.flags & JUMPNRUN_ENEMY_MOVING) || enemy_on_screen(self, state)) { self->base.flags |= JUMPNRUN_ENEMY_MOVING; 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) { jumpnrun_render_enemy(fb, state, self); } } } else if(self->base.flags & JUMPNRUN_ENEMY_UNAVAILABLE) { if(!enemy_in_spawn_area(self, state)) { self->base.flags &= ~JUMPNRUN_ENEMY_UNAVAILABLE; } } else if(enemy_in_spawn_area(self, state)) { // enemy unspawned, available and in spawn zone. enemy_spawn(self); } }
void enemy_tick_swing_up_and_down(struct jumpnrun_enemy *self, struct jumpnrun_game_state *state, struct jumpnrun_level *lv, struct jumpnrun_tile_range const *visible_tiles, vec2d *player_inertia_mod) { 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_pos_display(self).y))); enemy_animation_advance(self); }
void enemy_collision_player_jumpable(jumpnrun_enemy *self, jumpnrun_game_state *state, vec2d *player_inertia_mod) { 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)) && jumpnrun_player_alive(&state->player)) { jumpnrun_enemy_kill(self); player_inertia_mod->y = FIXED_POINT(0, -250); state->player.base.jumpable_frames = 12; } else { jumpnrun_player_kill(&state->player); } } }
void enemy_collision_shots_bounce(struct jumpnrun_enemy *self, struct jumpnrun_game_state *state) { for(uint8_t i = 0; i < JUMPNRUN_MAX_SHOTS; ++i) { jumpnrun_shot *shot = &state->shots[i]; if(jumpnrun_shot_spawned(shot)) { 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(enemy_hitbox(self)), rectangle_width(&shot->current_box))); } else { rectangle_move_to_x(&shot->current_box, rectangle_right(enemy_hitbox(self))); } shot->inertia.x = fixed_point_neg(shot->inertia.x); } } } }
void jumpnrun_player_despawn(jumpnrun_player *self) { self->base.flags |= JUMPNRUN_PLAYER_DEAD; self->base.flags &= ~JUMPNRUN_MOVEABLE_DYING; self->base.inertia = (vec2d) { FIXED_INT(0), FIXED_INT(0) }; }
int main(int argc, char **argv) { plan_tests(46); // test constructor GeoPoint p1(Angle::Degrees(fixed(345.32)), Angle::Degrees(fixed(-6.332))); ok1(equals(p1, -6.332, 345.32)); // test normalize() p1.Normalize(); ok1(equals(p1, -6.332, -14.68)); // test parametric() GeoPoint p2(Angle::Degrees(fixed_two), Angle::Degrees(fixed_one)); GeoPoint p3 = p1.Parametric(p2, fixed(5)); ok1(equals(p3, -1.332, -4.68)); // test interpolate GeoPoint p4 = p1.Interpolate(p3, fixed_half); ok1(equals(p4, -3.832, -9.68)); GeoPoint p5 = p1.Interpolate(p3, fixed(0.25)); ok1(equals(p5, -5.082, -12.18)); // test * GeoPoint p6 = p2 * fixed(3.5); ok1(equals(p6, 3.5, 7)); // test + p6 = p6 + p2; ok1(equals(p6, 4.5, 9)); // test += p6 += p2; ok1(equals(p6, 5.5, 11)); // test - p6 = p6 - p2; ok1(equals(p6, 4.5, 9)); // test sort() ok1(!p1.Sort(p3)); ok1(p3.Sort(p1)); ok1(!p1.Sort(p4)); ok1(p4.Sort(p1)); ok1(!p1.Sort(p5)); ok1(p5.Sort(p1)); ok1(!p4.Sort(p3)); ok1(p3.Sort(p4)); ok1(!p5.Sort(p3)); ok1(p3.Sort(p5)); ok1(!p5.Sort(p4)); ok1(p4.Sort(p5)); // test distance() // // note: distance between p1 and p4 and between p3 and p4 is not // the same due to linear interpolation instead of real geographic // intermediate point calculation ok1(equals(p2.Distance(p6), 869326.653160)); ok1(equals(p6.Distance(p2), 869326.653160)); ok1(equals(p1.Distance(p5), 309562.219016)); ok1(equals(p1.Distance(p4), 619603.149273)); ok1(equals(p1.Distance(p3), 1240649.267606)); ok1(equals(p3.Distance(p4), 621053.760625)); // test bearing() // // note: the bearings p1 -> p5, p5 -> p4 and so on are not the same due to // linear interpolation instead of real geographic intermediate point // calculation ok1(equals(p2.Bearing(p6), 63.272424)); ok1(equals(p6.Bearing(p2), 243.608847)); ok1(equals(p1.Bearing(p5), 63.449343)); ok1(equals(p1.Bearing(p4), 63.582620)); ok1(equals(p1.Bearing(p3), 63.784526)); ok1(equals(p5.Bearing(p4), 63.466726)); ok1(equals(p5.Bearing(p3), 63.646072)); ok1(equals(p4.Bearing(p3), 63.540756)); ok1(equals(p5.Bearing(p6), 65.982854)); ok1(equals(p2.Bearing(p3), 250.786774)); // test distance_bearing() // note: should be the same output as bearing() and distance() GeoVector v = p2.DistanceBearing(p6); ok1(equals(v.distance, 869326.653160)); ok1(equals(v.bearing, 63.272424)); // test intermediate_point() GeoPoint p7(Angle::Degrees(fixed_zero), Angle::Degrees(fixed_zero)); GeoPoint p8 = p7.IntermediatePoint(p2, fixed(100000)); ok1(equals(p8, 0.402274, 0.804342)); ok1(equals(p8.Distance(p7), 100000)); GeoPoint p9 = p7.IntermediatePoint(p2, fixed(100000000)); ok1(equals(p9, p2)); // test projected_distance() ok1(equals(p8.ProjectedDistance(p7, p2), 100000)); ok1(equals(p4.ProjectedDistance(p1, p3), 619599.304393)); ok1(equals((p2 * fixed_two).ProjectedDistance(p2, p6), 248567.832772)); // Tests moved here from test_fixed.cpp GeoPoint l1(Angle::Zero(), Angle::Zero()); GeoPoint l2(Angle::Degrees(fixed(-0.3)), Angle::Degrees(fixed(1.0))); GeoPoint l3(Angle::Degrees(fixed(0.00001)), Angle::Degrees(fixed_zero)); GeoPoint l4(Angle::Degrees(fixed(10)), Angle::Degrees(fixed_zero)); v = l1.DistanceBearing(l2); printf("Dist %g bearing %d\n", FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees())); // 116090 @ 343 v = l1.DistanceBearing(l3); printf("Dist %g bearing %d\n", FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees())); ok(positive(v.distance) && v.distance < fixed_two, "earth distance short", 0); v = l1.DistanceBearing(l4); printf("Dist %g bearing %d\n", FIXED_DOUBLE(v.distance), FIXED_INT(v.bearing.Degrees())); return exit_status(); }
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)); }