sdl_runtime_compiler git · main
SDL3 game for running and compiling code at runtime
C++ 72.3% C 26.2%git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gzImprove levels With Claude
src/levels/level_list.cpp | 232 +++++++++++++++++++++++++++++++++------------- src/states/game_state.cpp | 2 +- 2 files changed, 168 insertions(+), 66 deletions(-) diff --git a/src/levels/level_list.cpp b/src/levels/level_list.cpp index d9ee3a0..b68a362 100644 --- a/src/levels/level_list.cpp +++ b/src/levels/level_list.cpp @@ -1,27 +1,42 @@ #include "level_list.hpp" #include "utils/config.hpp" +// ───────────────────────────────────────────────────────────────────────────── +// Layout conventions for the tutorial +// +// * The player spawns near the world origin (0,0,0). Keep the FIRST thing a +// step asks for at least ~4 units away so nothing spawns under the player. +// +// * "Continue plates" (ReachPlate goals that advance the tutorial) sit ON TOP +// of a solid box once jumping has been taught (step 1+). Elevating them means +// you can't drift onto them by accident — you have to deliberately jump up. +// The pattern is always: a box, and a plate centred on its top face. +// +// * floor_y == -WORLD_BOX_SCALE. Heights are written as -WORLD_BOX_SCALE + dy. +// ───────────────────────────────────────────────────────────────────────────── + static const DynArray<Level> levels = { { .name = "Tutorial", - .desc = "Learn the controls.", + .desc = "Learn the controls and the code-building loop.", .steps = { - // ── Step 0: walk to plate ──────────────────────────────────────── + // ── Step 0: walk to plate (floor — before jumping) ─────────────── { .hint = "Walk to the green plate", .details = R"(Welcome. Use W, A, S, D to walk. +Move the mouse to turn. -A green plate is on the floor nearby. +A green plate sits on the floor a short walk away. Step onto it to continue.)", .grants = { }, .scene = Scene{ .words = {}, .plates = { - { .pos = { 4.0, static_cast<double>(-WORLD_BOX_SCALE), 4.0 }, .tag = "" }, + { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE), 6.0 }, .tag = "" }, }, .platforms = {}, .ai_seeds = {}, @@ -31,22 +46,27 @@ Step onto it to continue.)", .max_ai_words = 0, }, - // ── Step 1: jump on a high plate ───────────────────────────────── + // ── Step 1: learn to jump (staircase to an elevated plate) ─────── { - .hint = "Jump onto the elevated plate", - .details = R"(You can jump with SPACE. + .hint = "Jump up the steps to the plate", + .details = R"(Press SPACE to jump. -A plate is sitting on top of a platform. +Ahead is a short staircase of blocks. +Hop up them, one at a time, and stand on the +plate at the top. -Climb up and stand on it.)", +From now on, plates that advance the tutorial sit +up high — you'll need this jump to reach them.)", .grants = {}, .scene = Scene{ .words = {}, - .plates = { { .pos = {-1.0, static_cast<double>(-WORLD_BOX_SCALE + 2.4f ),-1.0 }, .tag = "" } }, + .plates = { + { .pos = { 8.6, static_cast<double>(-WORLD_BOX_SCALE + 2.2f), 0.0 }, .tag = "" }, + }, .platforms = { - { .pos = { 2.0, static_cast<double>(-WORLD_BOX_SCALE + 0.4f ), 2.0 }, .half_extents = { 0.8, 0.2, 0.8 } }, - { .pos = { 0.5, static_cast<double>(-WORLD_BOX_SCALE + 1.2f ), 0.5 }, .half_extents = { 0.8, 0.2, 0.8 } }, - { .pos = {-1.0, static_cast<double>(-WORLD_BOX_SCALE + 2.0f ),-1.0 }, .half_extents = { 0.8, 0.2, 0.8 } }, + { .pos = { 5.0, static_cast<double>(-WORLD_BOX_SCALE + 0.4f), 0.0 }, .half_extents = { 0.9, 0.2, 0.9 } }, + { .pos = { 6.8, static_cast<double>(-WORLD_BOX_SCALE + 1.1f), 0.0 }, .half_extents = { 0.9, 0.2, 0.9 } }, + { .pos = { 8.6, static_cast<double>(-WORLD_BOX_SCALE + 1.8f), 0.0 }, .half_extents = { 0.9, 0.2, 0.9 } }, }, .ai_seeds = {}, }, @@ -55,23 +75,29 @@ Climb up and stand on it.)", .max_ai_words = 0, }, - // ── Step 2: look around ────────────────────────────────────────── + // ── Step 2: look around (elevated continue-plate) ──────────────── { - .hint = "Look at each wall, then step on the plate", + .hint = "Look at each wall, then jump onto the plate", .details = R"(Move the mouse to look around. Four walls surround you: - - Editor: where you build code + - Editor: where you build code (the pults face it) - Compiler: shows compile messages - - Program: shows program output + - Program: shows your program's output - Info: this wall, with hints -When you've seen them all, step onto the plate.)", +Tip: hold C to free-look without turning your body. + +When you've seen them all, jump onto the plate.)", .grants = {}, .scene = Scene{ .words = {}, - .plates = { { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE), 3.0 }, .tag = "" } }, - .platforms = {}, + .plates = { + { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 1.2f), 6.0 }, .tag = "" }, + }, + .platforms = { + { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 0.6f), 6.0 }, .half_extents = { 1.0, 0.4, 1.0 } }, + }, .ai_seeds = {}, }, .reset_carry = true, @@ -81,15 +107,15 @@ When you've seen them all, step onto the plate.)", // ── Step 3: pick up a word ─────────────────────────────────────── { - .hint = "Walk into the floating word and pick it up.", + .hint = "Walk into the floating word and press E", .details = R"(Words float in the air. -Walk into "hello" to pick it up by pressing 'e' -Picked words trail in front of you.)", +Walk up to "hello" and press E to pick it up. +Picked words trail in front of you as you move.)", .grants = {}, .scene = Scene{ .words = { - { .text = "hello", .pos = { 4.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), 0.0 } }, + { .text = "hello", .pos = { 5.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), 0.0 } }, }, .plates = {}, .platforms = {}, @@ -100,23 +126,19 @@ Picked words trail in front of you.)", .max_ai_words = 0, }, - // ── Step 4: pick a sequence ────────────────────────────────────── - // - // Real improvement over the old version: the previous code - // advanced on the FIRST pick. Now all three words are required. + // ── Step 4: pick up several words (order matters) ───────────────── { - .hint = "Pick up the words", + .hint = "Pick up all three words", .details = R"(You can carry several words at once. -Walk through the three "press / any / key" words. - -They line up in the order you picked them.)", +Collect "press", "any" and "key" with E. +They queue up in the order you grab them.)", .grants = {}, .scene = Scene{ .words = { - { .text = "press", .pos = { 4.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -2.0 } }, - { .text = "any", .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -2.0 } }, - { .text = "key", .pos = { -4.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -2.0 } }, + { .text = "press", .pos = { 5.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -3.0 } }, + { .text = "any", .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -3.0 } }, + { .text = "key", .pos = { -5.0, static_cast<double>(-WORLD_BOX_SCALE + 1.5f), -3.0 } }, }, .plates = {}, .platforms = {}, @@ -134,9 +156,10 @@ They line up in the order you picked them.)", // ── Step 5: drop a word ────────────────────────────────────────── { .hint = "Press Q to drop the last word", - .details = R"(Q drops the last word you picked. + .details = R"(Q drops the most recently picked word. -The dropped word falls to the floor.)", +The dropped word falls to the floor — handy for +putting back something you grabbed by mistake.)", .grants = {}, .scene = {}, .reset_carry = false, @@ -144,12 +167,14 @@ The dropped word falls to the floor.)", .max_ai_words = 0, }, - // ── Step 6: shoot a word ───────────────────────────────────────── + // ── Step 6: throw a word ───────────────────────────────────────── { - .hint = "LEFT CLICK to throw the next word", - .details = R"(Left click throws the most recent carried word. + .hint = "LEFT CLICK to throw a word", + .details = R"(Left click throws the word at the front of your line. -Throw a word — any direction is fine.)", +Aim with the crosshair and throw — any direction is fine. + +Carrying several? Tap F to throw the WHOLE line at once.)", .grants = {}, .scene = {}, .reset_carry = false, @@ -157,17 +182,15 @@ Throw a word — any direction is fine.)", .max_ai_words = 0, }, - // ── Step 7: shoot a hostile word ───────────────────────────────── + // ── Step 7: combat — shoot a hostile word ──────────────────────── { - .hint = "Shoot the red word", - .details = R"(Some words turn red and chase you. - -They want to steal what you carry. + .hint = "Grab the ammo, then shoot the red word", + .details = R"(Some words turn red and chase you to steal what +you carry. -Pick up "ammo", then shoot the red word -before it lands a hit. - -Aim with the crosshair and LEFT CLICK.)", +Pick up "ammo", then knock out the red "danger" +word by throwing at it with LEFT CLICK before it +reaches you.)", .grants = {}, .scene = Scene{ .words = { @@ -189,20 +212,25 @@ Aim with the crosshair and LEFT CLICK.)", .max_ai_words = 0, }, - // ── Step 8: compile your first program ─────────────────────────── + // ── Step 8: build on the editor wall + compile ─────────────────── { - .hint = "Build int main(void) { return 0; }", - .details = R"(Time to make code. + .hint = "Build int main(void) { return 0; } and press BUILD", + .details = R"(Now make code. -The Editor wall is behind the pults — face it, -and throw tokens at it to build source code. +Face the Editor wall (the pults point at it). Throw +tokens at the wall to place them: + - LEFT CLICK throws one word + - F throws your whole carried line at once -The "Compile" pult runs your program. +Words snap into rows. Aim between two words to drop +a token between them. Mis-placed a token? Walk up and +press E to pluck it back off the wall. -Build: +Build exactly: int main(void) { return 0; } -Walk to the Compile pult and press it.)", +Then walk to the Compile pult (labelled BUILD) and +press it.)", .grants = { TokenGrant::give("int"), TokenGrant::give("main"), @@ -218,18 +246,92 @@ Walk to the Compile pult and press it.)", .scene = {}, .reset_carry = true, .goal = CompilePattern{ "int main ( void ) { return 0 ; }" }, - .max_ai_words = 3, + .max_ai_words = 0, + }, + + // ── Step 9: make it print, then RUN it ─────────────────────────── + { + .hint = "Add printf, BUILD, then press RUN", + .details = R"(A program that does nothing is dull. Make it print. + +Add a printf line inside main, before return: + printf("hello"); + +So the whole thing reads: + int main(void) { printf("hello"); return 0; } + +Press BUILD to compile, then walk to the RUN pult and +press it. Your program runs and its output appears on +the Program wall — and that's what finishes this step.)", + .grants = { + TokenGrant::give("int"), + TokenGrant::give("main"), + TokenGrant::give("("), + TokenGrant::give("void"), + TokenGrant::give(")"), + TokenGrant::give("{"), + TokenGrant::give("printf"), + TokenGrant::give("("), + TokenGrant::give("\"hello\""), + TokenGrant::give(")"), + TokenGrant::give(";"), + TokenGrant::give("return"), + TokenGrant::give("0"), + TokenGrant::give(";"), + TokenGrant::give("}"), + TokenGrant::give("#include"), + TokenGrant::give("<stdio.h>"), + }, + .scene = {}, + .reset_carry = true, + // Must build the printf program (compiles + matches) AND press RUN. + .goal = AllOf{{ + CompilePattern{ "int main ( void ) { printf ( \"hello\" ) ; return 0 ; }" }, + PressButton{ PultAction::RunProgram }, + }}, + .max_ai_words = 0, + }, + + // ── Step 10: editor tools (scroll / clear / line numbers) ──────── + { + .hint = "Try the editor pults, then jump onto the plate", + .details = R"(A few tools for managing the Editor wall: + + - The UP / DOWN pults scroll the code. + - Each line is numbered on both sides. Shoot a line + number to scroll that line to your eye level. + - The CLEAR pult wipes the wall. + - Press E on a placed word to pull it back off. + +Have a play, then jump onto the plate to continue.)", + .grants = { + TokenGrant::give("int"), + TokenGrant::give("x"), + TokenGrant::give("="), + TokenGrant::give("0"), + TokenGrant::give(";"), + }, + .scene = Scene{ + .words = {}, + .plates = { + { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 1.2f), -6.0 }, .tag = "" }, + }, + .platforms = { + { .pos = { 0.0, static_cast<double>(-WORLD_BOX_SCALE + 0.6f), -6.0 }, .half_extents = { 1.0, 0.4, 1.0 } }, + }, + .ai_seeds = {}, + }, + .reset_carry = true, + .goal = ReachPlate{ "" }, + .max_ai_words = 0, }, - // ── Step 9: finish plate ───────────────────────────────────────── - // - // Bug fix: previously advanced on JUMP, regardless of plate. - // Now actually requires standing on the plate. + // ── Step 11: finish (elevated plate → first real level) ────────── { - .hint = "Jump onto the plate to finish", + .hint = "Jump onto the plate to begin \"Char Copy\"", .details = R"(You're ready. -Step on the plate to start the real level: +Jump onto the plate to start the first real level: "Char Copy".)", .grants = {}, .scene = Scene{ diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp index d9868c7..18ae582 100644 --- a/src/states/game_state.cpp +++ b/src/states/game_state.cpp @@ -83,7 +83,7 @@ GameState::GameState(size_t starting_level) )); _ctx.scenery.back()->body.mode = PhysicsMode::Dynamic; */ - debug_SpawnWords(0); + //debug_SpawnWords(0); }