*FINALLY* a somewhat convincing recreation of level 1

Took absolute AGES.
This commit is contained in:
Lephenixnoir 2023-07-24 14:55:39 +02:00
parent 4de6f917c1
commit 339c538d63
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
4 changed files with 233 additions and 80 deletions

View File

@ -104,15 +104,23 @@ struct Generator
}
};
struct gen1: public Generator
struct GeonGenerator: public Generator
{
gen1();
GeonGenerator();
void generate(struct level *) override;
~gen1() override = default;
~GeonGenerator() override = default;
num generate_tunnel_block(struct level *level, num z, int sections);
num generate_blue_transition(struct level *level, num z);
num generate_blue_funnel(struct level *level, num z);
num generate_random_tunnel(struct level *level, num z, int sections);
void change_phase(void);
num m_z;
bool m_initial;
path_carver m_path_carver;
int m_phase;
MultiPathCarver m_multi_carver;
};
struct AcceleronGenerator: public Generator

View File

@ -1,101 +1,249 @@
#include "../generator.h"
#include "../level.h"
#include "../util.h"
#define PLATFORM_LEN_INITIAL num(6.0)
/* Geometric parameters */
#define G_PLATFORM_LEN_INITIAL num(6.0)
#define G_UNIT num(1.0) /* Platform length unit */
gen1::gen1(): m_path_carver{0}
/* Probabilities */
#define P_ANY_BLUE num(0.15)
#define P_FUNNEL_BLUE num(0.5)
#define P_FUNNEL_ALLBLUE num(0.4)
#define P_RANDOM_TUNNEL_HOLE num(0.25)
GeonGenerator::GeonGenerator(): m_multi_carver{2}
{
srand(0xc0ffee);
m_initial = true;
m_z = 0.0;
m_phase = 0;
int faces[2] = { 0, 2 };
m_multi_carver.set_faces(faces);
m_multi_carver.set_noskip(true);
m_multi_carver.set_checkerboard(false);
}
void gen1::generate(struct level *level)
{
struct platform p1;
struct platform p2;
static const int freq[] = {
1,
2, 2, 2, 2,
3, 3, 3, 3, 3, 3,
4,
5, 5, 5,
};
/* Generates a tunnel block, which is full ring alternating with half rings.
The total length (which should be odd) is specified as a parameter.
0123456789
########## [h=0, 2u]
#.#.#.#.#. [h=0, 3u]
########## [h=0, 2u]
(...repeats)
There is a random probability for any of the platforms to turn into a 1.5u
blue followed by a whatever's left as white. */
num GeonGenerator::generate_tunnel_block(struct level *level, num z, int sec)
{
for(int i = 0; i < sec; i++) {
num len = (i & 1) ? 3 * G_UNIT : 2 * G_UNIT;
/* Generate all/even platforms on even/odd i */
for(int j = 0; j < PLATFORM_COUNT; j++) {
if((i & j) & 1)
continue;
struct platform p;
p.type = PLATFORM_WHITE;
p.face = j;
p.z = z;
p.length = len;
p.height = 0;
if(num_rand() <= P_ANY_BLUE) {
p.length = G_UNIT;
p.type = PLATFORM_BLUE;
add(level, p);
p.z += p.length;
p.length = len - p.length;
p.type = PLATFORM_WHITE;
add(level, p);
}
else {
add(level, p);
}
}
z += len;
}
return z;
}
/* Generates a blue transition, a single-block long ring with half the faces
filled with blue platforms.
0123456789
#.#.#.#.#. [h=0, 3u, all blue] */
num GeonGenerator::generate_blue_transition(struct level *level, num z)
{
num len = 3 * G_UNIT;
for(int j = 0; j < PLATFORM_COUNT / 2; j++) {
struct platform p;
p.type = PLATFORM_BLUE;
p.face = 2 * j;
p.z = z;
p.length = len;
p.height = 0;
add(level, p);
}
return z + len;
}
/* Generates a blue funnel leading to face #3-#5.
0123456789
#.#.#.#.#. [h=0, 3u]
.#.#.#.#.. [h=0, 3u]
..#.#.#... [h=1, 3u] */
num GeonGenerator::generate_blue_funnel(struct level *level, num z)
{
num len = 3 * G_UNIT;
bool allblue = (num_rand() <= P_FUNNEL_ALLBLUE);
for(int i = 0; i < 3; 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_BLUE;
p.face = i + 2*j;
p.z = z;
p.length = len;
p.height = (i == 2 ? 1 : 0) * PLATFORM_HEIGHT_STEP;
if(!allblue && num_rand() > P_FUNNEL_BLUE)
p.type = PLATFORM_WHITE;
add(level, p);
}
z += len;
}
return z;
}
/* Generates a random tunnel which arbitrary blocks missing. Any remaining
block can be randomly split between a blue and a rest. */
num GeonGenerator::generate_random_tunnel(struct level *level, num z, int sec)
{
for(int i = 0; i < sec; i++) {
num len = (i & 1) ? 3 * G_UNIT : 2 * G_UNIT;
for(int j = 0; j < PLATFORM_COUNT; j++) {
if(num_rand() <= P_RANDOM_TUNNEL_HOLE)
continue;
struct platform p;
p.type = PLATFORM_WHITE;
p.face = j;
p.z = z;
p.length = len;
p.height = 0;
if(num_rand() <= P_ANY_BLUE) {
p.length = G_UNIT;
p.type = PLATFORM_BLUE;
add(level, p);
p.z += p.length;
p.length = len - p.length;
p.type = PLATFORM_WHITE;
add(level, p);
}
else {
add(level, p);
}
}
z += len;
}
return z;
}
void GeonGenerator::change_phase(void)
{
static int const freq_table[] = {
0, 0, 0, /* Tunnel block */
1, 1, /* Blue transition */
2, /* Blue funnel */
3, 3, 3, /* Random tunnel */
4, 4, 4, /* Path carver */
};
int const FREQ_TABLE_SIZE = sizeof freq_table / sizeof freq_table[0];
int p = m_phase;
while(1) {
p = freq_table[rand() % FREQ_TABLE_SIZE];
/* Do not repeat the same phase twice in a row */
if(p == m_phase)
continue;
/* Do not follow blue transition with blue funnel or vice-versa */
if((p == 1 && m_phase == 2) || (p == 2 && m_phase == 1))
continue;
/* Only allow blue transitions when after a tunnel-like structure */
if(p == 1 && (m_phase != 0 && m_phase != 3))
continue;
/* Only allow tunnel-like structures when exiting a blue transition */
if(m_phase == 1 && (p != 0 && p != 3))
continue;
break;
}
m_phase = p;
}
void GeonGenerator::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 = PLATFORM_LEN_INITIAL;
p.length = G_PLATFORM_LEN_INITIAL;
p.height = 0.0;
p.falling = false;
level->platform_buffer.push_back(p);
m_z += p.length;
m_initial = false;
/* Start with a tunnel block */
m_phase = 0;
}
m_path_carver.next(
(rand() % 2) ? PLATFORM_LEN_LONG : PLATFORM_LEN_SHORT,
&p1,
true
);
p2 = p1;
switch (freq[rand() % (sizeof(freq) / sizeof(freq[0]))])
{
/* full circle */
case 1:
for (int i = 0 ; i < 10 ; i++) {
p2.face = i;
p2.length = (rand() % 2) ? PLATFORM_LEN_LONG : PLATFORM_LEN_SHORT;
level->platform_buffer.push_back(p2);
}
break;
/* full circle 1/2 */
case 2: {
int kind = rand() % 2;
for (int i = 0 ; i < 10 ; i++) {
if ((i & 1) == kind) { continue; }
p2.face = i;
level->platform_buffer.push_back(p2);
}
break;
if(m_phase == 0) {
int sections = 1 + 2 * (rand() % 2);
m_z = this->generate_tunnel_block(level, m_z, sections);
this->change_phase();
}
/* 3 faces, 1 empty, 5 faces */
case 3: {
int toggle_len = rand() % 2;
p2.face = p1.face;
for (int i = 0 ; i < 3 ; i++) {
p2.length = (toggle_len) ? PLATFORM_LEN_LONG : PLATFORM_LEN_SHORT;
level->platform_buffer.push_back(p2);
p2.face = (p2.face + 1) % PLATFORM_COUNT;
}
p2.face = (p2.face + 1) % PLATFORM_COUNT;
for (int i = 0 ; i < 5 ; i++) {
level->platform_buffer.push_back(p2);
p2.face = (p2.face + 1) % PLATFORM_COUNT;
}
break;
else if(m_phase == 1) {
m_z = this->generate_blue_transition(level, m_z);
this->change_phase();
}
/* 1 face, 1 empty, 1 face, 1 emtpy, 1 face */
case 4:
//TODO : height
level->platform_buffer.push_back(p2);
p2.face = add_to_face(p2.face, -2);
level->platform_buffer.push_back(p2);
p2.face = add_to_face(p2.face, 4);
level->platform_buffer.push_back(p2);
break;
/* foce 1 face */
default:
p1.length = PLATFORM_LEN_LONG;
level->platform_buffer.push_back(p1);
else if(m_phase == 2) {
m_z = this->generate_blue_funnel(level, m_z);
m_multi_carver.force_to_match(4);
m_phase = 4;
}
else if(m_phase == 3) {
int sections = 3 + rand() % 7;
m_z = this->generate_random_tunnel(level, m_z, sections);
this->change_phase();
}
else if(m_phase == 4) {
int length = 3 + rand() % 7;
for(int i = 0; i < length; i++) {
num platform_length = rand() % 2 ? 2 * G_UNIT : 3 * G_UNIT;
m_multi_carver.next(level, m_z, platform_length);
m_z += platform_length;
}
this->change_phase();
}
}

View File

@ -10,7 +10,7 @@ struct level level_create(int level)
switch(level) {
default:
l.name = "geon";
l.gen = std::make_unique<struct gen1>();
l.gen = std::make_unique<GeonGenerator>();
l.bgcolor = RGB24(0x49759f);
break;
case 2:

View File

@ -15,9 +15,6 @@ using namespace libnum;
#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.75)