231 lines
6.0 KiB
C++
231 lines
6.0 KiB
C++
#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;
|
|
}
|