*FINALLY* a somewhat convincing recreation of level 1
Took absolute AGES.
This commit is contained in:
parent
4de6f917c1
commit
339c538d63
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue