make red platforms fall + clarify lots of space-related stuff

This commit is contained in:
Lephenixnoir 2023-06-03 21:01:19 +02:00
parent cde90744cf
commit 5e44eb2e3c
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
9 changed files with 82 additions and 66 deletions

View File

@ -24,11 +24,10 @@ vec2 player::world_angle_vector() const
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_platform_distance() + this->height, this->z);
vec3 pos(0, -space_cylinder_quasiradius() + this->height, this->z);
return vec_rotate_around_z(pos, this->world_angle_vector());
}
@ -78,12 +77,12 @@ void player::get_anim(struct anim **anim, int *frame)
//======= Functions on the game world space =======//
static vec2 platform_rotations[PLATFORM_COUNT];
static num platform_distance;
static vec2 _platform_rotations[PLATFORM_COUNT];
static num _cylinder_quasiradius;
num space_platform_distance(void)
num space_cylinder_quasiradius(void)
{
return platform_distance;
return _cylinder_quasiradius;
}
/* We can't use a constructor function because g++ already generates a call to
@ -94,32 +93,22 @@ void space_init(void)
for(int i = 0; i < PLATFORM_COUNT; i++) {
num angle = arc * i - (arc / 2);
platform_rotations[i] = vec2(num_cos(angle), num_sin(angle));
_platform_rotations[i] = vec2(num_cos(angle), num_sin(angle));
}
platform_distance = LEVEL_RADIUS * num_cos(arc / 2);
}
num space_platform_dist_from_center(int height_value)
{
return LEVEL_RADIUS * (num(12 - height_value) / 12);
}
num space_platform_height(int height_value)
{
return LEVEL_RADIUS - space_platform_dist_from_center(height_value);
_cylinder_quasiradius = LEVEL_RADIUS * num_cos(arc / 2);
}
struct prect space_platform_position(struct platform const *p)
{
struct prect r;
vec3 radius(0, -space_platform_dist_from_center(p->height), p->z);
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.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;
@ -146,25 +135,23 @@ void game_advance(struct game *game)
num game_height_at(struct game *game, num z, int face)
{
int max_h = -1;
num max_h = -KILL_PLANE_RADIUS;
for(auto const &p: game->level.platform_buffer) {
if(p.face == face && z >= p.z && z <= p.z + p.length)
max_h = (max_h >= p.height) ? max_h : p.height;
}
return max_h >= 0
? space_platform_height(max_h)
: -KILL_PLANE_RADIUS;
return max_h;
}
const struct platform *game_platform_under_player(struct game const *game,
struct platform *game_platform_under_player(struct game *game,
struct player const *player)
{
if(player->stance != player::Running)
return NULL;
for(auto const &p: game->level.platform_buffer) {
for(auto &p: game->level.platform_buffer) {
if(player->platform == p.face
&& player->z >= p.z && player->z <= p.z + p.length) {
return &p;

View File

@ -46,7 +46,7 @@ struct player
num jump_t;
/* Key to watch to end the jump. */
int jump_key;
/* Current height relative to current platform (world units). */
/* Current height relative to cylinder (world units). */
num height;
/* Vertical speed (world units/s). */
num vheight;
@ -107,12 +107,11 @@ consteval num space_platform_arc()
return num(2 * 3.14159 / PLATFORM_COUNT);
}
/* Height (in world coordinates in the range [-LEVEL_RADIUS..0]) of a platform
whose height value in the `struct platform` is given as parameter. */
num space_platform_height(int height_value);
/* Distance between the center of the world and a platform's plane. */
num space_platform_distance(void);
/* Distance between the center of the world cylinder and the center point of a
platform at default height. This is almost equal to the cylinder's radius,
but not quite, because the platform's edges touch the cylinder and the
platform itself cuts into it. */
num space_cylinder_quasiradius(void);
/* Position, in world units, of the provided flat platform. */
struct prect space_platform_position(struct platform const *p);
@ -126,7 +125,7 @@ void game_advance(struct game *game);
num game_height_at(struct game *game, num z, int face);
/* Returns the platform on which the player is running, if any. */
const struct platform *game_platform_under_player(struct game const *game,
struct platform *game_platform_under_player(struct game *game,
struct player const *player);
#endif /* __GAME_H__ */
#endif /* __GAME_H__ */

View File

@ -3,6 +3,7 @@
#include <num/num.h>
#include "settings.h"
#include "level.h"
using namespace libnum;
//======= Generation utilities =======//
@ -96,6 +97,11 @@ struct Generator
/* Generate more stuff. */
virtual void generate(struct level *) = 0;
virtual ~Generator() = default;
inline void add(struct level *level, struct platform &p) const {
p.falling = false;
level->platform_buffer.push_back(p);
}
};
struct gen1: public Generator
@ -115,6 +121,8 @@ struct AcceleronGenerator: public Generator
void generate(struct level *) override;
~AcceleronGenerator() override = default;
num generate_ascending_funnel(struct level *level, num z);
num m_z;
bool m_initial;
int m_phase;

View File

@ -29,7 +29,8 @@ void gen1::generate(struct level *level)
p.face = 0;
p.z = m_z;
p.length = PLATFORM_LEN_INITIAL;
p.height = 0;
p.height = 0.0;
p.falling = false;
level->platform_buffer.push_back(p);
m_z += p.length;

View File

@ -46,7 +46,7 @@ AcceleronGenerator::AcceleronGenerator():
....#..... [h=1]
Returns updated z. */
static num generate_ascending_funnel(struct level *level, num z)
num AcceleronGenerator::generate_ascending_funnel(struct level *level, num z)
{
/* Ascending funnel */
for(int i = 0; i < 5; i++) {
@ -57,12 +57,12 @@ static num generate_ascending_funnel(struct level *level, num z)
p.face = i + 2*j;
p.z = z;
p.length = G_PLATFORM_LEN;
p.height = i;
p.height = i * PLATFORM_HEIGHT_STEP;
if(num_rand() <= P_ASCF_RED)
p.type = PLATFORM_RED;
level->platform_buffer.push_back(p);
add(level, p);
}
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
}
@ -74,11 +74,11 @@ static num generate_ascending_funnel(struct level *level, num z)
p.face = 4;
p.z = z;
p.length = G_PLATFORM_LEN;
p.height = i + 5;
level->platform_buffer.push_back(p);
p.height = (i + 5) * PLATFORM_HEIGHT_STEP;
add(level, p);
p.face = (i & 1) ? 3 : 5;
level->platform_buffer.push_back(p);
add(level, p);
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
}
@ -89,23 +89,23 @@ static num generate_ascending_funnel(struct level *level, num z)
p.face = 4;
p.z = z;
p.length = G_PLATFORM_LEN * 3;
p.height = 8;
level->platform_buffer.push_back(p);
p.height = 8 * PLATFORM_HEIGHT_STEP;
add(level, p);
z += G_PLATFORM_LEN * 3 + G_PLATFORM_SPC;
p.type = PLATFORM_BLUE;
p.face = 3;
p.z = z;
p.length = G_PLATFORM_LEN * 3;
p.height = 5;
level->platform_buffer.push_back(p);
p.height = 5 * PLATFORM_HEIGHT_STEP;
add(level, p);
p.type = PLATFORM_WHITE;
p.face = 5;
p.z = z + G_PLATFORM_LEN;
p.length = G_PLATFORM_LEN * 2;
p.height = 4;
level->platform_buffer.push_back(p);
p.height = 4 * PLATFORM_HEIGHT_STEP;
add(level, p);
z += G_PLATFORM_LEN * 3 + G_PLATFORM_SPC;
@ -114,8 +114,8 @@ static num generate_ascending_funnel(struct level *level, num z)
p.face = 4;
p.z = z;
p.length = G_PLATFORM_LEN;
p.height = 0;
level->platform_buffer.push_back(p);
p.height = 0.0;
add(level, p);
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
return z;
@ -130,16 +130,16 @@ void AcceleronGenerator::generate(struct level *level)
p.face = 0;
p.z = m_z;
p.length = G_PLATFORM_LEN_INITIAL;
p.height = 0;
p.height = 0.0;
level->platform_buffer.push_back(p);
add(level, p);
m_z += p.length;
m_initial = false;
}
/* Phase #0: Ascending funnel and long/tight red platform */
if(m_phase == 0) {
m_z = generate_ascending_funnel(level, m_z);
m_z = this->generate_ascending_funnel(level, m_z);
m_checkerboard_carver.force_to_match(4);
m_phase = 1;
}

View File

@ -13,7 +13,7 @@ void gen3::generate(struct level *level)
{
struct platform p;
for(int i = 0; i < 3; i++) {
if(m_path_carvers[i].next(SECTION_LENGTH, &p)) {
if(m_path_carvers[i].next(3.0, &p)) {
level->platform_buffer.push_back(p);
}
}

View File

@ -14,11 +14,19 @@ typedef enum {
} platform_type_t;
struct platform {
/* Face number along the level's cylinder */
int face;
/* Depth and length; the platform lies at [z ... z+length). */
num z;
num length;
int height;
/* Platform height above the default height (cylinder quasiradius). This
can be compared with player->height. */
num height;
/* Platform kind. */
platform_type_t type;
/* Whether the platform is currently falling. This is only used for red
platforms. */
bool falling;
};
struct Generator;

View File

@ -52,7 +52,7 @@ int play_level(int level_id)
timer_start(timer);
camera_track(camera, player);
log_printf("platform distance: %s\n", str(space_platform_distance()));
log_printf("cylinder quasiradius: %s\n",str(space_cylinder_quasiradius()));
log_printf("player: at %s\n", str(player->pos()));
log_printf("camera: at %s, screen distance %s, platform %d, "
"angle vector %s\n",
@ -79,7 +79,7 @@ int play_level(int level_id)
level_update(&game.level, player->z);
camera_track(camera, player);
struct platform const *standing_on = game_platform_under_player(&game,
struct platform *standing_on = game_platform_under_player(&game,
&game.player);
//======= Rendering =======//
@ -271,6 +271,17 @@ int play_level(int level_id)
if(standing_on && standing_on->type == PLATFORM_BLUE) {
player->energy_percent += dt * vz * 5.5;
}
if(standing_on && standing_on->type == PLATFORM_RED) {
standing_on->falling = true;
}
for(auto &p: game.level.platform_buffer) {
if(p.type == PLATFORM_RED && p.falling) {
p.height -= PLATFORM_FALL_SPEED * dt;
if(standing_on == &p)
player->height = p.height;
}
}
game_advance(&game);
prof_leave_norec(perf_frame);

View File

@ -7,21 +7,23 @@ using namespace libnum;
/* Radius of the level cylinder, in world units. */
#define LEVEL_RADIUS num(4.0)
/* Radius of the kill plane */
#define KILL_PLANE_RADIUS num(10.0)
/* Section lengths, in world units.
TODO: Remove, we don't use sections anymore */
#define SECTION_LENGTH num(3.0)
#define KILL_PLANE_RADIUS num(12.0)
/* Number of platforms in the world cylinder. */
#define PLATFORM_COUNT 10
/* Height of a single platform step. Most levels generate platforms whose
height is a integer multiple of this value above the default height. */
#define PLATFORM_HEIGHT_STEP (LEVEL_RADIUS / 12)
/* Speed of red platforms falling once walked on (world units/s). */
#define PLATFORM_FALL_SPEED num(1.5)
/* Platforms len information, in word units */
#define PLATFORM_LEN_LONG num(3.0)
#define PLATFORM_LEN_SHORT num(1)
/* Magnitude of the gravity field, locally (world units/s^2), when holding the
jump button and when releasing it. */
#define HOVERING_GRAVITY num(-1.25)
#define FALLING_GRAVITY num(-8.0)
#define HOVERING_GRAVITY num(-1.75)
#define FALLING_GRAVITY num(-12.0)
/* Vertical speed granted when a jump starts (world units/s). */
#define JUMP_THRUST num(1.5)
#define JUMP_THRUST num(2.0)
/* Maximum height of a step that can be crossed without dying. */
#define STEP_HEIGHT (LEVEL_RADIUS * num(0.09))
/* Player height, for collisions with platform fronts. */
@ -41,7 +43,7 @@ using namespace libnum;
/* Distance between the player and the camera */
#define RENDER_CAMERA_BACK_DISTANCE num(0.67)
/* Depth at which we start rendering platforms */
#define RENDER_DEPTH (num(8.0) * SECTION_LENGTH)
#define RENDER_DEPTH num(24.0)
/* Set to 1 to enable logging by USB. */
#define LOG_USB_ENABLE 0