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) };
}
Beispiel #9
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));
}