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.gzAdd move cam while in focus With Claude
info.txt | 7 ++++ src/states/game_state.cpp | 90 +++++++++++++++++++++++++++++++------------- src/states/game_state.hpp | 7 ++-- src/systems/input_system.cpp | 9 ++++- src/systems/input_system.hpp | 8 ++-- 5 files changed, 86 insertions(+), 35 deletions(-) diff --git a/info.txt b/info.txt index 69e2615..657432d 100644 --- a/info.txt +++ b/info.txt @@ -1,4 +1,11 @@ +wall size should be monitor size +text size match somehow +--------------------------------- +zoom to wall on key press down. if other key pressed move to wall. + if zoom on editor "i" to start and jump? +add jetpack? +-------------------------------- i need to store the big info text meshes so displaying them is not that expensive. --------------------------------- diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp index a39e0f5..2ec1aa0 100644 --- a/src/states/game_state.cpp +++ b/src/states/game_state.cpp @@ -387,8 +387,8 @@ void GameState::on_Jump() { if (_focus_active) { - _ctx.player->pos = _focus_pos; - _ctx.player->prev_pos = _focus_pos; + _ctx.player->pos = _ctx.camera->pos; + _ctx.player->prev_pos = _ctx.camera->pos; _ctx.player->vel = Vec3{0, 0, 0}; _ctx.player->on_ground = false; return; @@ -630,6 +630,8 @@ GameState::update(double dt, const GlRenderer* gl) input.look_x = 0; input.look_y = 0; + input.scroll_x = 0; + input.scroll_y = 0; input.commands.clear(); } @@ -704,16 +706,24 @@ GameState::update_Input(FrameInput& input, double dt) if (input.shoot && _shoot_cooldown <= 0.0) { FP_ZONE("handle_input.onShootO"); if (on_ShootOne()) _shoot_cooldown = 0.15; } - if (!_freelook_sys->state.active && !input.focus_wall) + const bool focus = input.focus_wall; + + if (!_freelook_sys->state.active && !focus) _ctx.player->add_Look(input.look_x, input.look_y); - if (input.focus_wall) + _freelook_sys->update(dt); + + if (focus) { + const bool f = input.forward, b = input.backward, + l = input.left, r = input.right; input.forward = input.backward = input.left = input.right = false; + _ctx.player->compute_Movement(input); + input.forward = f; input.backward = b; input.left = l; input.right = r; + } else { + _ctx.player->compute_Movement(input); + } - _freelook_sys->update(dt); - _ctx.player->compute_Movement(input); _ctx.camera->sync_FromPlayer(*_ctx.player); - update_WallFocus(input, dt); } @@ -1268,13 +1278,13 @@ GameState::handler_For(Wall::Role r) } + bool GameState::compute_FocusTarget() { const Camera& cam = *_ctx.camera; const float ws = World::get_BoxScale<float>(); - // Pick the wall plane the camera faces (nearest forward intersection). const Wall::Role roles[4] = { Wall::Role::Editor, Wall::Role::Program, Wall::Role::Info, Wall::Role::Compiler }; Wall::Role best_role = Wall::Role::Editor; @@ -1284,7 +1294,7 @@ GameState::compute_FocusTarget() const Vec3 n = Wall::inward_Normal(Wall::position_Of(role)); const Vec3 p = Wall::get_Position(role, ws); const double denom = cam.fwd.x*n.x + cam.fwd.y*n.y + cam.fwd.z*n.z; - if (denom < -1e-4) { // fwd opposes inward → facing it + if (denom < -1e-4) { const double t = ((p.x-cam.pos.x)*n.x + (p.y-cam.pos.y)*n.y + (p.z-cam.pos.z)*n.z) / denom; if (t > 0.1 && t < best_t) { best_t = t; best_role = role; found = true; } } @@ -1296,7 +1306,6 @@ GameState::compute_FocusTarget() const bool horiz_is_z = (tf.wall_position == Wall::Position::PosX || tf.wall_position == Wall::Position::NegX); - // Text bounding box (skip whitespace ghosts). double y_min=1e30, y_max=-1e30, h_min=1e30, h_max=-1e30; bool any=false; if (Text::Handler* hw = handler_For(best_role)) for (const Text::Line& line : hw->get_Lines()) @@ -1314,22 +1323,21 @@ GameState::compute_FocusTarget() if (any) { cy=(y_min+y_max)*0.5; ch=(h_min+h_max)*0.5; text_w=h_max-h_min; text_h=y_max-y_min; } else { cy=tf.position.y; ch=0.0; text_w=2.0; text_h=2.0; } - // Fit distance so the text fills ~85% of the view (whichever axis binds). - const double fov = (_fov_y > 0.01f) ? static_cast<double>(_fov_y ) : (SDL_PI_D / 3.0); - const double asp = (_aspect > 0.01f) ? static_cast<double>(_aspect) : 1.7; + const double fov = (_fov_y > 0.01f) ? (double)_fov_y : (SDL_PI_D / 3.0); + const double asp = (_aspect > 0.01f) ? (double)_aspect : 1.7; const double half_tan = SDL_tan(fov * 0.5); constexpr double FIT = 0.85; const double d_v = (text_h * 0.5) / (FIT * half_tan); const double d_h = (text_w * 0.5) / (FIT * half_tan * asp); - const double d = SDL_max(SDL_max(d_v, d_h), 2.0); - Vec3 centroid = tf.position; // wall-coordinate on the normal axis - centroid.y = cy; - if (horiz_is_z) centroid.z = ch; else centroid.x = ch; + Vec3 center = tf.position; + center.y = cy; + if (horiz_is_z) center.z = ch; else center.x = ch; - _focus_pos = { centroid.x + n.x*d, centroid.y + n.y*d, centroid.z + n.z*d }; - _focus_yaw_r = tf.yaw; // facing the wall - _focus_pitch_r = 0.0; + _focus_center = center; + _focus_normal = n; + _focus_dist = SDL_max(SDL_max(d_v, d_h), 2.0); + _focus_yaw_r = tf.yaw; return true; } @@ -1342,24 +1350,52 @@ GameState::update_WallFocus(FrameInput& input, double dt) if (input.focus_wall) { if (!_focus_active) { if (!compute_FocusTarget()) return; _focus_active = true; } _focus_t = SDL_min(1.0, _focus_t + dt / DUR); + + const double ws = World::get_BoxScale(); + + // dolly (scroll wheel): wheel up = toward the wall, down = away. Clamped + // inside the room. Scale by distance so each notch feels proportional. + constexpr double DOLLY = 1.2, MIN_D = 0.6; + const double MAX_D = 2.0 * ws - 0.6; + _focus_dist -= input.scroll_y * DOLLY * (_focus_dist * 0.15 + 1.0); + _focus_dist = SDL_clamp(_focus_dist, MIN_D, MAX_D); + + // pan via mouse motion — smooth, any direction (look is suppressed while + // focused, so the mouse deltas are ours). Scale by distance so the pan + // feels the same in screen space whether zoomed in or out. + constexpr double PAN_SENS = 0.0016; + const double k = PAN_SENS * _focus_dist; + const double rx = SDL_cos(_focus_yaw_r); // focus camera right axis (y = 0) + const double rz = -SDL_sin(_focus_yaw_r); + const double pan_h = (double)input.look_x * k; + const double pan_v = (double)input.look_y * k; + const double lim = ws - 0.5; + + _focus_center.x = SDL_clamp(_focus_center.x + rx * pan_h, -lim, lim); + _focus_center.z = SDL_clamp(_focus_center.z + rz * pan_h, -lim, lim); + _focus_center.y = SDL_clamp(_focus_center.y - pan_v, -lim, lim); } else { if (!_focus_active) return; _focus_t -= dt / DUR; if (_focus_t <= 0.0) { _focus_t = 0.0; _focus_active = false; return; } } - Camera& cam = *_ctx.camera; // cam currently holds the fresh player view - const double s = _focus_t * _focus_t * (3.0 - 2.0 * _focus_t); // smoothstep + const Vec3 focus_pos = { _focus_center.x + _focus_normal.x * _focus_dist, + _focus_center.y + _focus_normal.y * _focus_dist, + _focus_center.z + _focus_normal.z * _focus_dist }; + + Camera& cam = *_ctx.camera; + const double s = _focus_t * _focus_t * (3.0 - 2.0 * _focus_t); - double dyaw = _focus_yaw_r - cam.yaw_r; // shortest angular path + double dyaw = _focus_yaw_r - cam.yaw_r; while (dyaw > SDL_PI_D) dyaw -= 2.0 * SDL_PI_D; while (dyaw < -SDL_PI_D) dyaw += 2.0 * SDL_PI_D; const double yaw_r = cam.yaw_r + dyaw * s; - const double pitch_r = cam.pitch_r + (_focus_pitch_r - cam.pitch_r) * s; - const Vec3 pos = { cam.pos.x + (_focus_pos.x - cam.pos.x) * s, - cam.pos.y + (_focus_pos.y - cam.pos.y) * s, - cam.pos.z + (_focus_pos.z - cam.pos.z) * s }; + const double pitch_r = cam.pitch_r + (0.0 - cam.pitch_r) * s; + const Vec3 pos = { cam.pos.x + (focus_pos.x - cam.pos.x) * s, + cam.pos.y + (focus_pos.y - cam.pos.y) * s, + cam.pos.z + (focus_pos.z - cam.pos.z) * s }; const double binrad = ConfigPhysics::binrad; cam.pos = pos; diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp index 042d05b..5ce9931 100644 --- a/src/states/game_state.hpp +++ b/src/states/game_state.hpp @@ -61,10 +61,11 @@ class GameState : public IState // focus wall jump START bool _focus_active { false }; - double _focus_t { 0.0 }; // 0 = player view, 1 = wall view - Vec3 _focus_pos {}; + double _focus_t { 0.0 }; + Vec3 _focus_center {}; // look-at point on the wall plane (panned by scroll) + Vec3 _focus_normal {}; // inward normal of the focused wall + double _focus_dist { 4.0 }; // camera distance from the wall plane (dolly via W/S) double _focus_yaw_r { 0.0 }; - double _focus_pitch_r { 0.0 }; float _fov_y { 0.0f }; float _aspect { 0.0f }; // focus wall jump END diff --git a/src/systems/input_system.cpp b/src/systems/input_system.cpp index 29b7857..640319a 100644 --- a/src/systems/input_system.cpp +++ b/src/systems/input_system.cpp @@ -11,8 +11,13 @@ InputSystem::handle_Event(Game& game, const SDL_Event& e, FrameInput& input) { switch (e.type) { case SDL_EVENT_MOUSE_MOTION: - input.look_x += (int)e.motion.xrel; - input.look_y += (int)e.motion.yrel; + input.look_x += static_cast<int>(e.motion.xrel); + input.look_y += static_cast<int>(e.motion.yrel); + break; + + case SDL_EVENT_MOUSE_WHEEL: + input.scroll_x += static_cast<double>(e.wheel.x); + input.scroll_y += static_cast<double>(e.wheel.y); break; case SDL_EVENT_MOUSE_BUTTON_DOWN: { diff --git a/src/systems/input_system.hpp b/src/systems/input_system.hpp index dc23808..228c72b 100644 --- a/src/systems/input_system.hpp +++ b/src/systems/input_system.hpp @@ -35,7 +35,7 @@ struct FrameInput bool right = false; bool pick = false; bool shoot = false; - bool focus_wall = false; + bool focus_wall = false; bool normal_keys = false; @@ -46,8 +46,10 @@ struct FrameInput bool typing_commit = false; bool typing_cancel = false; - int look_x = 0; - int look_y = 0; + int look_x = 0; + int look_y = 0; + double scroll_x = 0.0; + double scroll_y = 0.0; std::string typing_buffer; DynArray<int> vim_keys;