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.gzsrc/levels/director.cpp raw
#include <algorithm>
#include <unordered_set>
#include "entities/camera.hpp"
#include "entities/plate.hpp"
#include "entities/solid_box.hpp"
#include "entities/world.hpp"
#include "levels/director.hpp"
#include "levels/level.hpp"
#include "states/game_context.hpp"
#include "systems/celebration_system.hpp"
#include "systems/particle_system.hpp"
#include "utils/config.hpp"
#include "text/text.hpp"
#include "wall/wall.hpp"
namespace
Nimbin
{
namespace
Level
{
Director::Director(const Level::Data& level)
: _runner(cpputils::make_unique<Level::Progression>(level))
{}
int
Director::get_MaxAiForStep() const
{
if (_runner->is_Complete()) return 0;
return _runner->get_Current().max_ai_words;
}
void
Director::enter_Step(GameContext& ctx)
{
spawn_Grants(ctx);
setup_Scene (ctx, _runner->get_Current().scene);
show_Details(ctx);
_step_age = 0.0;
}
void
Director::spawn_Grants(GameContext& ctx)
{
DynArray<std::string> tokens = _runner->get_GarantsForStep();
static constexpr float spacing = 3.0f;
static constexpr int per_row = 8;
static constexpr float row_gap = 3.0f;
const double hover_y = World::get_FloorY<double>() + 1.5;
for (size_t i = 0; i < tokens.size(); i++) {
size_t col = i % per_row;
size_t row = i / per_row;
Vec3 pos {
-static_cast<float>(per_row) * spacing * 0.5f + static_cast<float>(col) * spacing,
hover_y,
static_cast<float>(row) * row_gap
};
Text::TokenPtr obj = Text::make_Token(tokens[i], Text::Token::depth_floor, 0.003f, pos);
obj->body.hover_height = hover_y;
ctx.words.push_back(std::move(obj));
}
}
void
Director::setup_Scene(GameContext& ctx, const Scene::Data& scene)
{
for (const Scene::Placed::Word& pw : scene.words) {
Text::TokenPtr t = Text::make_Token(pw.text, Text::Token::depth_floor, 0.003f, pw.pos, pw.color);
t->body.hover_height = pw.pos.y;
ctx.words.push_back(std::move(t));
}
for (const Scene::Placed::Plate& pp : scene.plates) {
auto plate = cpputils::make_unique<Plate>(pp.pos);
Plate* raw = plate.get();
_step_plates .push_back({ raw, pp.tag });
_step_scenery.push_back(raw);
ctx.scenery .push_back(std::move(plate));
}
for (const Scene::Placed::Platform& pl : scene.platforms) {
auto box = cpputils::make_unique<SolidBox>(pl.pos, pl.half_extents,
pl.fill_color, pl.wire_color);
GameObject* raw = box.get();
_step_scenery.push_back(raw);
ctx.scenery .push_back(std::move(box));
}
for (const Scene::Placed::Ai& a : scene.ai_seeds) {
Text::TokenPtr t = Text::make_Token(a.text, Text::Token::depth_floor, 0.003f, a.pos, Config::Color::floor);
t->body.hover_height = a.pos.y;
t->ai.aggressiveness = a.aggressiveness;
switch (a.initial_state) {
case Text::Token::Ai::State::Attack:
t->ai.state = Text::Token::Ai::State::Attack;
t->body.mode = PhysicsMode::AiHover;
t->set_Color (Config::Color::attack);
t->set_ColorSource(Text::ColorSource::Static);
t->ai.state_timer = 0.0;
t->ai.phase_timer = 0.5;
break;
case Text::Token::Ai::State::Flee:
t->ai.state = Text::Token::Ai::State::Flee;
t->body.mode = PhysicsMode::AiHover;
t->set_Color (Config::Color::flee);
t->set_ColorSource(Text::ColorSource::Static);
break;
case Text::Token::Ai::State::Idle:
case Text::Token::Ai::State::Stunned:
break;
}
ctx.words.push_back(std::move(t));
}
}
void
Director::teardown_Scene(GameContext& ctx)
{
if (!_step_scenery.empty()) {
std::unordered_set<GameObject*> scenery_set(_step_scenery.begin(), _step_scenery.end());
ctx.scenery.erase(
std::remove_if(ctx.scenery.begin(), ctx.scenery.end(),
[&scenery_set](const GameObjectPtr& sp) {
return scenery_set.count(sp.get()) > 0;
}),
ctx.scenery.end());
}
_step_scenery.clear();
_step_plates .clear();
}
void Director::show_Details(GameContext& ctx) const
{
if (!ctx.info_wall) return;
Text::Handler& info = *ctx.info_wall;
if (_runner->is_Complete()) { info.clear(); _detail_built_for = nullptr; return; }
const Level::Step* step = &_runner->get_Current();
if (_detail_built_for != step) {
_detail_tokens.clear();
const std::string& details = step->details;
DynArray<std::string> lines = details.empty()
? DynArray<std::string>{}
: Text::wrap_String(details, 92);
float y = World::get_FloorY<float>() + 1.0f;
const Wall::Transform tf = Wall::get_Transform(Wall::Role::Info, World::get_BoxScale());
for (const std::string& line : lines) {
if (line.empty()) { y += Config::Wall::text_line_spacing; continue; }
Text::TokenPtr t = Text::make_Token(line, Text::Token::depth_wall, 0.003f,
tf.position, Config::Color::white);
t->yaw = tf.yaw;
t->pos = tf.position;
t->pos.y = y;
t->set_ColorSource(Text::ColorSource::Static);
t->set_Color(Config::Color::white);
_detail_tokens.push_back(std::move(t));
y += Config::Wall::text_line_spacing;
}
_detail_built_for = step;
}
info.clear();
info.set_Borrowed(&_detail_tokens);
}
Goal::Context
Director::build_GoalCtx(const GameContext& ctx) const
{
Goal::Context gctx;
for (const StepPlate& sp : _step_plates)
if (sp.plate && sp.plate->active)
gctx.active_plate_tags.push_back(sp.tag);
gctx.buttons_pressed_this_step = _ledger.buttons_pressed;
gctx.dropped_this_step = _ledger.dropped;
gctx.shot_this_step = _ledger.shot;
gctx.compile_ok_this_step = _ledger.compile_ok;
gctx.ai_words_defeated_this_step = _ledger.ai_defeated;
gctx.picked_up_this_step = _ledger.picked_up;
if (gctx.compile_ok_this_step && ctx.editor_wall) {
std::string src;
for (const std::string& l : ctx.editor_wall->as_Lines())
{ src += l; src += '\n'; }
gctx.editor_normalized = Level::Check::normalize(src);
}
return gctx;
}
Director::AdvanceResult
Director::try_Advance(GameContext& ctx, double dt,
CelebrationSystem& celebration, ParticleSystem& particles)
{
_step_age += dt;
AdvanceResult res;
if (celebration.is_Active()) {
if (celebration.get_Progress() >= 1.0) {
celebration.finish(particles);
teardown_Scene(ctx);
_ledger.clear();
res.stepped = true;
res.advanced = _runner->advance();
res.reset_carry = res.advanced && _runner->get_Current().reset_carry;
_step_age = 0.0;
}
return res;
}
if (_runner->is_Complete()) return res;
Goal::Context gctx = build_GoalCtx(ctx);
if (!Goal::is_Satisfied(_runner->get_Current().goal, gctx)) return res;
if (_step_age < Config::Level::settle_time_for_step) return res;
double glyph_yaw = SDL_atan2(-ctx.camera->fwd.x, -ctx.camera->fwd.z);
celebration.start(*ctx.camera, glyph_yaw);
return res;
}
} // namespace Level
} // namespace Nimbin