From 08411fc90cd8042d8c2f9561c2e14ca86238f823 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Wed, 24 May 2023 19:59:36 +0200 Subject: [PATCH] lv2: add a random checkerboard path phase --- src/generator.h | 42 ++++++++++++++++++++++- src/generator/gen2.cpp | 26 +++++++++++++-- src/generator/path.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++ src/main.cpp | 7 ---- src/render.h | 2 +- src/settings.h | 2 +- 6 files changed, 141 insertions(+), 13 deletions(-) diff --git a/src/generator.h b/src/generator.h index 7a61cd7..28e1547 100644 --- a/src/generator.h +++ b/src/generator.h @@ -31,6 +31,45 @@ private: bool m_last_skipped; }; +/* A path carver that generates multiple simultaneous paths following a + grid-like structure (platforms all of the same length, minus some random + variation). */ +struct MultiPathCarver +{ + /* Create a carver with a set number of parallel paths. */ + MultiPathCarver(int N); + + /* Set initial positions. */ + void set_faces(int *faces /* size N */); + + /* Force the carver to generate all platforms and never skip. */ + void set_noskip(bool noskip); + + /* Force the carver to generate paths along a checkerboard. */ + void set_checkerboard(bool checkerboard); + + /* Rotate the current state to force one platform to be at `face`. */ + void force_to_match(int face); + + /* Add the next set of platforms (all at z) to the level. */ + void next(struct level *level, num z, num length); + +private: + /* Number of parallel paths */ + int m_N; + /* Information specific to each path */ + struct { + /* Current face */ + int face; + /* Whether last platform was skipped */ + bool last_skipped; + } *m_paths; + /* Force all platforms to be generated */ + bool m_noskip; + /* Force a checkerboard pattern */ + bool m_checkerboard; +}; + static inline int add_to_face(int face, int how_much) { int f = (face + how_much) % PLATFORM_COUNT; @@ -75,7 +114,8 @@ struct AcceleronGenerator: public Generator num m_z; bool m_initial; - path_carver m_path_carver; + int m_phase; + MultiPathCarver m_checkerboard_carver; }; struct gen3: public Generator diff --git a/src/generator/gen2.cpp b/src/generator/gen2.cpp index 55b8342..ca16052 100644 --- a/src/generator/gen2.cpp +++ b/src/generator/gen2.cpp @@ -10,11 +10,18 @@ /* Probabilities */ #define P_ASCF_RED num(0.2) -AcceleronGenerator::AcceleronGenerator(): m_path_carver{0} +AcceleronGenerator::AcceleronGenerator(): + m_checkerboard_carver{3} { srand(123456); m_initial = true; m_z = 0.0; + m_phase = 0; + + int faces[3] = { 0, 4, 8 }; + m_checkerboard_carver.set_faces(faces); + m_checkerboard_carver.set_noskip(true); + m_checkerboard_carver.set_checkerboard(true); } /* Generates an ascending funnel up to a long red platform on face #4, in the @@ -128,7 +135,21 @@ void AcceleronGenerator::generate(struct level *level) m_initial = false; } - m_z = generate_ascending_funnel(level, m_z); + /* Phase #0: Ascending funnel and long/tight red platform */ + if(m_phase == 0) { + m_z = generate_ascending_funnel(level, m_z); + m_checkerboard_carver.force_to_match(4); + m_phase = 1; + } + /* Phase #1: Checkerboard random paths */ + else if(m_phase == 1) { + int length = 4 + 2 * (rand() % 2); + for(int i = 0; i < length; i++) { + m_checkerboard_carver.next(level, m_z, G_PLATFORM_LEN); + m_z += G_PLATFORM_LEN + G_PLATFORM_SPC; + } + m_phase = 0; + } /* Phase #1: Almost-full tunnel with random holes? */ @@ -136,7 +157,6 @@ void AcceleronGenerator::generate(struct level *level) /* Phase #3: Full + odd + even tunnel combination leading into #0 */ - /* Phase #4: Checkerboard random paths */ /* Phase #5: Obstacles - ##.##.#.#. diff --git a/src/generator/path.cpp b/src/generator/path.cpp index 773373c..3caa679 100644 --- a/src/generator/path.cpp +++ b/src/generator/path.cpp @@ -36,3 +36,78 @@ void path_carver::teleport(num z) { m_z = z; } + +//~ + +MultiPathCarver::MultiPathCarver(int N) +{ + m_N = N; + m_paths = static_cast(malloc(N * sizeof *m_paths)); + m_noskip = false; + m_checkerboard = false; + + for(int i = 0; i < N; i++) + m_paths[i].last_skipped = false; +} + +void MultiPathCarver::set_faces(int *faces) +{ + for(int i = 0; i < m_N; i++) + m_paths[i].face = faces[i]; +} + +void MultiPathCarver::set_noskip(bool noskip) +{ + m_noskip = noskip; +} + +void MultiPathCarver::set_checkerboard(bool checkerboard) +{ + m_checkerboard = checkerboard; +} + +void MultiPathCarver::force_to_match(int face) +{ + if(m_N <= 0) + return; + + int diff = face - m_paths[0].face; + for(int i = 0; i < m_N; i++) { + m_paths[i].face = add_to_face(m_paths[i].face, diff); + } +} + +void MultiPathCarver::next(struct level *level, num z, num length) +{ + /* Decide whether to skip */ + for(int i = 0; i < m_N; i++) { + bool skip = !m_noskip && !m_paths[i].last_skipped && (rand() % 4 == 0); + m_paths[i].last_skipped = skip; + } + + /* Generate platforms for the current positions */ + for(int face = 0; face < PLATFORM_COUNT; face++) { + bool is_hit = false; + for(int i = 0; i < m_N; i++) + is_hit |= (!m_paths[i].last_skipped && m_paths[i].face == face); + + if(is_hit) { + struct platform p; + p.face = face; + p.z = z; + p.length = length; + p.height = 0; + p.type = PLATFORM_WHITE; + level->platform_buffer.push_back(p); + } + } + + /* Advance positions */ + for(int i = 0; i < m_N; i++) { + /* In checkerboard mode, only allow diff -1/+1 instead of -1/0/+1 */ + int diff = m_checkerboard + ? 2 * (rand() % 2) - 1 + : rand() % 3 - 1; + m_paths[i].face = add_to_face(m_paths[i].face, diff); + } +} diff --git a/src/main.cpp b/src/main.cpp index 3afc42e..f25d961 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -111,18 +111,11 @@ int play_level(int level_id) 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); } diff --git a/src/render.h b/src/render.h index 3c2074f..ca5787f 100644 --- a/src/render.h +++ b/src/render.h @@ -20,7 +20,7 @@ struct camera /* Distance to the near plane, for clipping. TODO: Figure out a better choice of a near plane. */ - num near_plane() const { return this->screen_distance() * num(0.75); } + num near_plane() const { return this->screen_distance() * num(0.25); } //======= World data =======// diff --git a/src/settings.h b/src/settings.h index 8bc2cdd..4de78df 100644 --- a/src/settings.h +++ b/src/settings.h @@ -23,7 +23,7 @@ using namespace libnum; /* 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)) +#define STEP_HEIGHT (LEVEL_RADIUS * num(0.09)) /* Player height, for collisions with platform fronts. */ #define PLAYER_HEIGHT num(0.8)