#include "game.h" #include "level.h" #include "frame.h" //===== Player implementation =======// num player::world_angle() const { num arc = space_platform_arc(); num angle = this->platform * arc; if(this->airborne()) { /* Time spent rotating; caps at the full rotation time */ num t = num_clamp(this->jump_t, 0, TIME_ROTATION); angle += this->jump_dir * arc * t / TIME_ROTATION; } return angle; } vec2 player::world_angle_vector() const { num angle = this->world_angle(); return vec2(num_cos(angle), num_sin(angle)); } vec3 player::pos() const { /* Local position without accounting for current platform's angle */ vec3 pos(0, -space_cylinder_quasiradius() + this->height, this->z); return vec_rotate_around_z(pos, this->world_angle_vector()); } vec3 player::forward() const { return vec3(0, 0, 1); } vec3 player::backward() const { return -this->forward(); } vec3 player::up() const { return vec_rotate_around_z(vec3(0, 1, 0), this->world_angle_vector()); } vec3 player::down() const { return -this->up(); } void player::get_anim(struct anim **anim, int *frame) { extern struct anim anim_erik_running; extern struct anim anim_erik_jumping; num vanim = num(1) + this->energy_percent / 200; if(this->stance == Running) { this->frame = this->frame + vanim; if(this->frame >= anim_erik_running.frame_count) this->frame = 0; *anim = &anim_erik_running; *frame = (int)this->frame; } else { this->frame = this->frame + vanim; if(this->frame >= anim_erik_jumping.frame_count) this->frame = 12; *anim = &anim_erik_jumping; *frame = (int)this->frame; } } //======= Functions on the game world space =======// static vec2 _platform_rotations[PLATFORM_COUNT]; static num _cylinder_quasiradius; num space_cylinder_quasiradius(void) { return _cylinder_quasiradius; } /* We can't use a constructor function because g++ already generates a call to the default constructor, which would run after us and override the data. */ void space_init(void) { num arc = space_platform_arc(); for(int i = 0; i < PLATFORM_COUNT; i++) { num angle = arc * i - (arc / 2); _platform_rotations[i] = vec2(num_cos(angle), num_sin(angle)); } _cylinder_quasiradius = LEVEL_RADIUS * num_cos(arc / 2); } struct prect space_platform_position(struct platform const *p) { struct prect r; vec3 radius(0, -space_cylinder_quasiradius() + p->height, p->z); int angle_l = p->face; int angle_r = (p->face + 1) % PLATFORM_COUNT; r.nl = r.fl = vec_rotate_around_z(radius, _platform_rotations[angle_l]); r.nr = r.fr = vec_rotate_around_z(radius, _platform_rotations[angle_r]); r.fl.z += p->length; r.fr.z += p->length; return r; } struct frect space_block_position(struct platform const *p) { vec3 r1(0, -2 * PLATFORM_HEIGHT_STEP, p->z); vec3 r2(0, -space_cylinder_quasiradius() + p->height, p->z); int angle_l = p->face; int angle_r = (p->face + 1) % PLATFORM_COUNT; struct frect f; f.tr = vec_rotate_around_z(r1, _platform_rotations[angle_r]); f.tl = vec_rotate_around_z(r1, _platform_rotations[angle_l]); f.br = vec_rotate_around_z(r2, _platform_rotations[angle_r]); f.bl = vec_rotate_around_z(r2, _platform_rotations[angle_l]); return f; } struct prect space_block_top_position(struct platform const *p) { vec3 r1(0, -2 * PLATFORM_HEIGHT_STEP, p->z); int angle_l = p->face; int angle_r = (p->face + 1) % PLATFORM_COUNT; struct prect t; t.nl = t.fl = vec_rotate_around_z(r1, _platform_rotations[angle_l]); t.nr = t.fr = vec_rotate_around_z(r1, _platform_rotations[angle_r]); t.fl.z += p->length; t.fr.z += p->length; return t; } struct srect space_wall_position(struct platform const *p) { vec3 r1(0, -2 * PLATFORM_HEIGHT_STEP, p->z); vec3 r2(0, -space_cylinder_quasiradius() + p->height, p->z); struct srect s; s.nt = s.ft = vec_rotate_around_z(r1, _platform_rotations[p->face]); s.nb = s.fb = vec_rotate_around_z(r2, _platform_rotations[p->face]); s.ft.z += p->length; s.fb.z += p->length; return s; } //======= Game implementation =======// void game_advance(struct game *game) { struct level *level = &game->level; auto it = level->platform_buffer.begin(); while(it != level->platform_buffer.end()) { /* If a platform is dead, remove it. We include the camera's distance in the calculation because we only remove platforms that have been passed *and* are now invisible. */ if(game->player.z - RENDER_CAMERA_BACK_DISTANCE > it->z + it->length) it = level->platform_buffer.erase(it); else ++it; } } static bool standable(struct platform const &p) { return p.type != PLATFORM_SEPARATING_WALL && p.type != PLATFORM_BLOCK && p.type != PLATFORM_BLOCK_TOP; } static bool collidable(struct platform const &p) { return p.type == PLATFORM_BLOCK_TOP; } num game_height_at(struct game *game, num z, int face) { num max_h = -KILL_PLANE_RADIUS; for(auto const &p: game->level.platform_buffer) { if(standable(p) && p.face == face && z >= p.z && z <= p.z + p.length) max_h = (max_h >= p.height) ? max_h : p.height; } return max_h; } struct platform *game_platform_under_player(struct game *game, struct player const *player) { if(player->stance != player::Running) return NULL; for(auto &p: game->level.platform_buffer) { if(standable(p) && player->platform == p.face && player->z >= p.z && player->z <= p.z + p.length) { return &p; } } return NULL; } struct platform *game_block_hitting_player(struct game *game, struct player const *player) { for(auto &p: game->level.platform_buffer) { if(collidable(p) && player->platform == p.face && player->z >= p.z && player->z <= p.z + p.length) { return &p; } } return NULL; }