lv2 + platform height + death conditions
This commit is contained in:
parent
4f38cd911b
commit
19caa845de
47
src/game.cpp
47
src/game.cpp
|
@ -96,19 +96,29 @@ void space_init(void)
|
|||
platform_distance = LEVEL_RADIUS * num_cos(arc / 2);
|
||||
}
|
||||
|
||||
struct prect space_platform_position(int face, num z, num length)
|
||||
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);
|
||||
}
|
||||
|
||||
struct prect space_platform_position(struct platform const *p)
|
||||
{
|
||||
struct prect r;
|
||||
vec3 radius(0, -LEVEL_RADIUS, z);
|
||||
vec3 radius(0, -space_platform_dist_from_center(p->height), p->z);
|
||||
|
||||
int angle_l = face;
|
||||
int angle_r = (face + 1) % PLATFORM_COUNT;
|
||||
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 += length;
|
||||
r.fr.z += length;
|
||||
r.fl.z += p->length;
|
||||
r.fr.z += p->length;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -130,10 +140,33 @@ void game_advance(struct game *game)
|
|||
}
|
||||
}
|
||||
|
||||
num game_height_at(struct game *game, num z, int face)
|
||||
{
|
||||
int max_h = -1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool game_player_above_platform(struct game *game, num height)
|
||||
{
|
||||
struct player const *player = &game->player;
|
||||
struct level const *level = &game->level;
|
||||
|
||||
for(auto const &p: game->level.platform_buffer) {
|
||||
if(player->platform == p.face
|
||||
&& player->z >= p.z && player->z <= p.z + p.length
|
||||
&& height >= space_platform_height(p.height)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
|
14
src/game.h
14
src/game.h
|
@ -98,20 +98,28 @@ 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);
|
||||
|
||||
/* Position, in world units, of a flat platform in the specified platform face
|
||||
(0..PLATFORM_COUNT-1) that has its near side at the specified depth z. */
|
||||
struct prect space_platform_position(int face, num z, num length);
|
||||
/* Position, in world units, of the provided flat platform. */
|
||||
struct prect space_platform_position(struct platform const *p);
|
||||
|
||||
//======= Game management =======//
|
||||
|
||||
/* Advance in the level by discarding platforms that have been passed. */
|
||||
void game_advance(struct game *game);
|
||||
|
||||
/* Get platform height at the provided position. */
|
||||
num game_height_at(struct game *game, num z, int face);
|
||||
|
||||
#if 0
|
||||
/* Check if the player would be standing over a platform with the provided
|
||||
height coordinate. This ignores player's height value. */
|
||||
bool game_player_above_platform(struct game *game, num height);
|
||||
#endif
|
||||
|
||||
#endif /* __GAME_H__ */
|
||||
|
|
|
@ -19,6 +19,8 @@ struct path_carver
|
|||
*p, false otherwise (in that case don't use *p). If force is set, always
|
||||
generates a platform. */
|
||||
bool next(num length, struct platform *p, bool force=false);
|
||||
/* Teleport to the specified z. */
|
||||
void teleport(num z);
|
||||
|
||||
private:
|
||||
/* Face where the next platform will be generated */
|
||||
|
@ -47,14 +49,14 @@ static inline int prev_face(int face)
|
|||
|
||||
//======= Level generator API =======//
|
||||
|
||||
struct generator
|
||||
struct Generator
|
||||
{
|
||||
/* Generate more stuff. */
|
||||
virtual void generate(struct level *) = 0;
|
||||
virtual ~generator() = default;
|
||||
virtual ~Generator() = default;
|
||||
};
|
||||
|
||||
struct gen1 : public generator
|
||||
struct gen1: public Generator
|
||||
{
|
||||
gen1();
|
||||
void generate(struct level *) override;
|
||||
|
@ -64,16 +66,18 @@ struct gen1 : public generator
|
|||
path_carver m_path_carvers[3];
|
||||
};
|
||||
|
||||
struct gen2 : public generator
|
||||
struct AcceleronGenerator: public Generator
|
||||
{
|
||||
gen2();
|
||||
AcceleronGenerator();
|
||||
void generate(struct level *) override;
|
||||
~gen2() override = default;
|
||||
~AcceleronGenerator() override = default;
|
||||
|
||||
num m_z;
|
||||
bool m_initial;
|
||||
path_carver m_path_carver;
|
||||
};
|
||||
|
||||
struct gen3 : public generator
|
||||
struct gen3: public Generator
|
||||
{
|
||||
gen3();
|
||||
void generate(struct level *) override;
|
||||
|
|
|
@ -1,16 +1,147 @@
|
|||
#include "../generator.h"
|
||||
#include "../level.h"
|
||||
#include "../util.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
gen2::gen2(): m_path_carver{0}
|
||||
/* Geometric parameters */
|
||||
#define G_PLATFORM_LEN num(3.0)
|
||||
#define G_PLATFORM_SPC num(0.5)
|
||||
#define G_PLATFORM_LEN_INITIAL num(6.0)
|
||||
/* Probabilities */
|
||||
#define P_ASCF_RED num(0.2)
|
||||
|
||||
AcceleronGenerator::AcceleronGenerator(): m_path_carver{0}
|
||||
{
|
||||
srand(123456);
|
||||
m_initial = true;
|
||||
m_z = 0.0;
|
||||
}
|
||||
|
||||
void gen2::generate(struct level *level)
|
||||
/* Generates an ascending funnel up to a long red platform on face #4, in the
|
||||
following shape.
|
||||
|
||||
0123456789
|
||||
#.#.#.#.#. [h=0]
|
||||
.#.#.#.#.. [h=1]
|
||||
..#.#.#... [h=2]
|
||||
...#.#.... [h=3]
|
||||
....#..... [h=4]
|
||||
....##.... [h=5]
|
||||
...##..... [h=6]
|
||||
....##.... [h=7]
|
||||
....R..... [h=8]
|
||||
....|.....
|
||||
....|.....
|
||||
...B|..... [h=5]
|
||||
...|.#.... [h=4]
|
||||
...|.|....
|
||||
....#..... [h=1]
|
||||
|
||||
Returns updated z. */
|
||||
static num generate_ascending_funnel(struct level *level, num z)
|
||||
{
|
||||
struct platform p;
|
||||
if(m_path_carver.next(SECTION_LENGTH, &p)) {
|
||||
level->platform_buffer.push_back(p);
|
||||
/* Ascending funnel */
|
||||
for(int i = 0; i < 5; i++) {
|
||||
/* Generate 5-i platforms starting at i, spaced by 2 */
|
||||
for(int j = 0; j < 5-i; j++) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = i + 2*j;
|
||||
p.z = z;
|
||||
p.length = G_PLATFORM_LEN;
|
||||
p.height = i;
|
||||
|
||||
if(num_rand() <= P_ASCF_RED)
|
||||
p.type = PLATFORM_RED;
|
||||
|
||||
level->platform_buffer.push_back(p);
|
||||
}
|
||||
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
|
||||
}
|
||||
|
||||
/* Steps */
|
||||
for(int i = 0; i < 3; i++) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = 4;
|
||||
p.z = z;
|
||||
p.length = G_PLATFORM_LEN;
|
||||
p.height = i + 5;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
p.face = (i & 1) ? 3 : 5;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
|
||||
}
|
||||
|
||||
/* Overlapping red platform and blue/white neighbors */
|
||||
struct platform p;
|
||||
p.type = PLATFORM_RED;
|
||||
p.face = 4;
|
||||
p.z = z;
|
||||
p.length = G_PLATFORM_LEN * 3;
|
||||
p.height = 8;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
p.type = PLATFORM_BLUE;
|
||||
p.face = 3;
|
||||
p.z = z + G_PLATFORM_LEN * 2;
|
||||
p.length = G_PLATFORM_LEN * 3;
|
||||
p.height = 5;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = 5;
|
||||
p.z = z + G_PLATFORM_LEN * 3;
|
||||
p.length = G_PLATFORM_LEN * 2;
|
||||
p.height = 4;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
z += G_PLATFORM_LEN * 5 + G_PLATFORM_SPC;
|
||||
|
||||
/* Exit platform */
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = 4;
|
||||
p.z = z;
|
||||
p.length = G_PLATFORM_LEN;
|
||||
p.height = 0;
|
||||
level->platform_buffer.push_back(p);
|
||||
|
||||
z += G_PLATFORM_LEN + G_PLATFORM_SPC;
|
||||
return z;
|
||||
}
|
||||
|
||||
void AcceleronGenerator::generate(struct level *level)
|
||||
{
|
||||
/* Friendly platform at start of level */
|
||||
if(m_initial) {
|
||||
struct platform p;
|
||||
p.type = PLATFORM_WHITE;
|
||||
p.face = 0;
|
||||
p.z = m_z;
|
||||
p.length = G_PLATFORM_LEN_INITIAL;
|
||||
p.height = 0;
|
||||
|
||||
level->platform_buffer.push_back(p);
|
||||
m_z += p.length;
|
||||
m_initial = false;
|
||||
}
|
||||
|
||||
m_z = generate_ascending_funnel(level, m_z);
|
||||
|
||||
/* Phase #1: Almost-full tunnel with random holes? */
|
||||
|
||||
/* Phase #2: Path with spacing + random onlookers */
|
||||
|
||||
/* Phase #3: Full + odd + even tunnel combination leading into #0 */
|
||||
|
||||
/* Phase #4: Checkerboard random paths */
|
||||
|
||||
/* Phase #5: Obstacles
|
||||
- ##.##.#.#.
|
||||
- .##.##.#.#
|
||||
- ..#..#..#.
|
||||
- .#..#..#.. */
|
||||
|
||||
}
|
||||
|
|
|
@ -30,3 +30,8 @@ bool path_carver::next(num length, struct platform *p, bool force)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void path_carver::teleport(num z)
|
||||
{
|
||||
m_z = z;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ struct level level_create(int level)
|
|||
|
||||
switch(level) {
|
||||
case 2:
|
||||
l.gen = std::make_unique<struct gen2>();
|
||||
l.gen = std::make_unique<AcceleronGenerator>();
|
||||
break;
|
||||
case 3:
|
||||
l.gen = std::make_unique<struct gen3>();
|
||||
|
|
|
@ -17,14 +17,15 @@ struct platform {
|
|||
int face;
|
||||
num z;
|
||||
num length;
|
||||
int height;
|
||||
platform_type_t type;
|
||||
};
|
||||
|
||||
struct generator;
|
||||
struct Generator;
|
||||
|
||||
struct level {
|
||||
std::vector<struct platform> platform_buffer;
|
||||
std::unique_ptr<struct generator> gen;
|
||||
std::unique_ptr<Generator> gen;
|
||||
};
|
||||
|
||||
|
||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -83,8 +83,7 @@ int play_level(int level_id)
|
|||
it != game.level.platform_buffer.rend();
|
||||
++it) {
|
||||
int color = camera_platform_color(&game.camera, it->face);
|
||||
struct prect p =
|
||||
space_platform_position(it->face, it->z, it->length);
|
||||
struct prect p = space_platform_position(&*it);
|
||||
|
||||
/* Near plane clipping */
|
||||
num near = camera->pos.z + camera->near_plane();
|
||||
|
@ -108,13 +107,22 @@ int play_level(int level_id)
|
|||
prof_leave_norec(perf_comp);
|
||||
azrp_update();
|
||||
|
||||
num floor = 0;
|
||||
|
||||
if(game.debug.footer) {
|
||||
drect(0, DHEIGHT-20, DWIDTH-1, DHEIGHT-1, C_WHITE);
|
||||
#if 0
|
||||
dprint(4, 209, C_BLACK, "render:%4d+%4dus comp:%4dus FPS:%02d",
|
||||
prof_time(azrp_perf_render) - prof_time(azrp_perf_r61524),
|
||||
prof_time(azrp_perf_r61524),
|
||||
prof_time(perf_comp),
|
||||
last_frame_us ? 1000000 / last_frame_us : 0);
|
||||
#else
|
||||
dprint(4, 209, C_BLACK, "floor:%f h:%f vh:%f",
|
||||
(double)floor,
|
||||
(double)game.player.height,
|
||||
(double)game.player.vheight);
|
||||
#endif
|
||||
r61524_display(gint_vram, DHEIGHT-20, 20, R61524_DMA_WAIT);
|
||||
}
|
||||
|
||||
|
@ -172,7 +180,6 @@ int play_level(int level_id)
|
|||
|
||||
//======= Simulation =======//
|
||||
|
||||
num old_height = player->height;
|
||||
player->z += player->vz * dt;
|
||||
player->height += player->vheight * dt;
|
||||
|
||||
|
@ -185,6 +192,7 @@ int play_level(int level_id)
|
|||
gravity = FALLING_GRAVITY;
|
||||
}
|
||||
player->vheight += gravity * dt;
|
||||
floor = game_height_at(&game, player->z, player->platform);
|
||||
|
||||
if(player->airborne()) {
|
||||
player->jump_t += dt;
|
||||
|
@ -205,17 +213,30 @@ int play_level(int level_id)
|
|||
player->vheight = 0.0;
|
||||
}
|
||||
|
||||
/* TODO: Reset jump after contact on platforms, not distance */
|
||||
if(old_height > 0 && player->height <= 0) {
|
||||
if(player->height >= floor - STEP_HEIGHT
|
||||
&& player->height <= floor) {
|
||||
player->stance = player::Running;
|
||||
player->jump_dir = 0;
|
||||
player->jump_t = 0.0;
|
||||
player->height = 0;
|
||||
player->height = floor;
|
||||
player->vheight = 0;
|
||||
player->jump_key = 0;
|
||||
player->frame = 0;
|
||||
}
|
||||
}
|
||||
else if(floor < player->height) {
|
||||
player->stance = player::Falling;
|
||||
player->vheight = 0.0;
|
||||
}
|
||||
|
||||
/* Death condition #1/2: inside a platform (hit it in front) */
|
||||
bool death_1 = (player->height >= floor - PLAYER_HEIGHT &&
|
||||
player->height < floor - STEP_HEIGHT);
|
||||
/* Death condition #2/2: below the kill plane */
|
||||
bool death_2 = (player->height < LEVEL_RADIUS - KILL_PLANE_RADIUS);
|
||||
|
||||
if(death_1 || death_2)
|
||||
break;
|
||||
|
||||
game_advance(&game);
|
||||
prof_leave_norec(perf_frame);
|
||||
|
@ -257,7 +278,7 @@ int main(void)
|
|||
continue;
|
||||
}
|
||||
while (menu_select_level(&level) >= 0) {
|
||||
play_level(level);
|
||||
play_level(level + 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -6,6 +6,8 @@ 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)
|
||||
|
@ -20,6 +22,10 @@ using namespace libnum;
|
|||
#define FALLING_GRAVITY num(-8.0)
|
||||
/* Vertical speed granted when a jump starts (world units/s). */
|
||||
#define JUMP_THRUST num(1.5)
|
||||
/* Maximum height of a step that can be crossed without dying. */
|
||||
#define STEP_HEIGHT (LEVEL_RADIUS * num(0.12))
|
||||
/* Player height, for collisions with platform fronts. */
|
||||
#define PLAYER_HEIGHT num(0.8)
|
||||
|
||||
/* Duration of a rotation by one platform, in seconds. */
|
||||
#define TIME_ROTATION num(0.1)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static num num_cos_dl(num a)
|
||||
{
|
||||
|
@ -33,6 +34,13 @@ num num_clamp(num t, num lower, num upper)
|
|||
return t;
|
||||
}
|
||||
|
||||
num num_rand(void)
|
||||
{
|
||||
num r;
|
||||
r.v = rand() & 0xffff;
|
||||
return r;
|
||||
}
|
||||
|
||||
vec3 vec_rotate_around_z(vec3 v, vec2 rotator)
|
||||
{
|
||||
num c = rotator.x;
|
||||
|
|
|
@ -19,6 +19,9 @@ num num_sin(num a);
|
|||
/* Clamp a num between two bounds. */
|
||||
num num_clamp(num t, num lower_bound, num upper_bound);
|
||||
|
||||
/* Random num between 0 and 1. */
|
||||
num num_rand(void);
|
||||
|
||||
/* String representation of various objects (static strings rotating; can use
|
||||
up to 8 of them at once). */
|
||||
char const *str(num x);
|
||||
|
|
Loading…
Reference in New Issue