From fe2fe20a5824ea17f0e858ba646374b6698a2d35 Mon Sep 17 00:00:00 2001 From: HumanoidSandvichDispenser Date: Fri, 13 Mar 2026 15:14:33 -0700 Subject: [PATCH] fix: Use incrementing instead of continuous --- as5/as5.cpp | 119 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 36 deletions(-) diff --git a/as5/as5.cpp b/as5/as5.cpp index 43212b5..15c9459 100644 --- a/as5/as5.cpp +++ b/as5/as5.cpp @@ -28,6 +28,14 @@ raylib::Degree angle_normalize(raylib::Degree angle) { return raylib::Degree(normalized + decimal); } +float shortest_angle_delta(raylib::Degree from, raylib::Degree to) { + float diff = std::fmod(float(to) - float(from) + 180.0f, 360.0f); + if (diff < 0.0f) { + diff += 360.0f; + } + return diff - 180.0f; +} + raylib::Vector3 velocity_from_speed_heading(float speed, raylib::Degree heading) { return raylib::Vector3{speed * std::sin(heading.RadianValue()), 0.0f, speed * std::cos(heading.RadianValue())}; @@ -47,7 +55,7 @@ void DrawBoundedModel(raylib::Model &model, bool drawBoundingBox, auto transform // draw the model, passing the origin and default scale as arguments since // the transform is already applied to the model - model.Draw({ 0, 0, 0 }, 1.0f, raylib::Color::White()); + model.Draw({0, 0, 0}, 1.0f, raylib::Color::White()); // get the bounding box of the model after applying the transform auto box = model.GetTransformedBoundingBox(); @@ -264,22 +272,46 @@ struct InputComponent : public Component { raylib::BufferedInput *input = nullptr; bool isActive = false; - float axisForward = 0.0f; - float axisTurn = 0.0f; - bool keySpace = false; + bool wishInitialized = false; + float wishSpeed = 0.0f; + raylib::Degree wishHeading = 0.0f; + + // these do not actually indicate any acceleration or angular velocity, it + // just updates the target velocity/heading, but the rate the character + // turns to this target is limited by its PhysicsComponent + float speedStep = 40.0f; + float headingStep = 18.0f; void Setup() override { if (!input) { return; } - input->actions["forward"].AddCallback( - [this](float state, float delta) { axisForward = state; }); - - input->actions["turn"].AddCallback([this](float state, float delta) { axisTurn = state; }); - - input->actions["space"].AddCallback( - [this](float state, float delta) { keySpace = (state > 0.0f); }); + input->actions["forward_pos"].AddPressedCallback([this]() { + if (isActive) { + wishSpeed += speedStep; + } + }); + input->actions["forward_neg"].AddPressedCallback([this]() { + if (isActive) { + wishSpeed -= speedStep; + } + }); + input->actions["turn_pos"].AddPressedCallback([this]() { + if (isActive) { + wishHeading = angle_normalize(wishHeading + raylib::Degree(headingStep)); + } + }); + input->actions["turn_neg"].AddPressedCallback([this]() { + if (isActive) { + wishHeading = angle_normalize(wishHeading - raylib::Degree(headingStep)); + } + }); + input->actions["space"].AddPressedCallback([this]() { + if (isActive) { + wishSpeed = 0.0f; + } + }); } void Cleanup() override {} @@ -296,19 +328,36 @@ struct InputComponent : public Component { return; } + // this is so we start with whatever velocity we had before as our wish + // heading and velocity. otherwise at the start of the game, it just + // moves you towards whatever wish was initialized with rather than + // what the actual velocity/heading was. + if (!wishInitialized) { + wishHeading = tf->get().heading; + + if (auto orientedInit = entity->GetComponent()) { + wishSpeed = orientedInit->get().speed; + } else if (auto physInit = entity->GetComponent()) { + PhysicsComponent &p = physInit->get(); + wishSpeed = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z); + } + + wishInitialized = true; + } + if (oriented) { OrientedPhysicsComponent &phys = oriented->get(); - float forward = axisForward; - float turn = axisTurn; + wishSpeed = std::clamp(wishSpeed, -phys.maxSpeed, phys.maxSpeed); - phys.speed += forward * phys.acceleration * dt; - tf->get().heading = - angle_normalize(tf->get().heading + raylib::Degree(turn * phys.turningRate * dt)); + float speedDiff = wishSpeed - phys.speed; + float maxSpeedStep = phys.acceleration * dt; + phys.speed += std::clamp(speedDiff, -maxSpeedStep, maxSpeedStep); - if (keySpace) { - phys.speed *= std::pow(0.05f, dt); - } + float headingDiff = shortest_angle_delta(tf->get().heading, wishHeading); + float maxHeadingStep = phys.turningRate * dt; + float headingStepNow = std::clamp(headingDiff, -maxHeadingStep, maxHeadingStep); + tf->get().heading = angle_normalize(tf->get().heading + raylib::Degree(headingStepNow)); } else { auto phys = entity->GetComponent(); if (!phys) { @@ -317,20 +366,20 @@ struct InputComponent : public Component { PhysicsComponent &p = phys->get(); - float spd = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z); - float forward = axisForward; - float turn = axisTurn; + wishSpeed = std::clamp(wishSpeed, -p.maxSpeed, p.maxSpeed); - spd += forward * p.acceleration * dt; - tf->get().heading = - angle_normalize(tf->get().heading + raylib::Degree(turn * p.turningRate * dt)); + float currentSpeed = + std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z); + float speedDiff = wishSpeed - currentSpeed; + float maxSpeedStep = p.acceleration * dt; + currentSpeed += std::clamp(speedDiff, -maxSpeedStep, maxSpeedStep); - if (keySpace) { - spd *= std::pow(0.05f, dt); - } + float headingDiff = shortest_angle_delta(tf->get().heading, wishHeading); + float maxHeadingStep = p.turningRate * dt; + float headingStepNow = std::clamp(headingDiff, -maxHeadingStep, maxHeadingStep); + tf->get().heading = angle_normalize(tf->get().heading + raylib::Degree(headingStepNow)); - spd = std::clamp(spd, -p.maxSpeed, p.maxSpeed); - p.velocity = velocity_from_speed_heading(spd, tf->get().heading); + p.velocity = velocity_from_speed_heading(currentSpeed, tf->get().heading); } } }; @@ -357,12 +406,10 @@ int main() { raylib::BufferedInput input; - input.actions["forward"] = - raylib::Action::button_axis({raylib::Button::key(KEY_W)}, {raylib::Button::key(KEY_S)}) - .move(); - input.actions["turn"] = - raylib::Action::button_axis({raylib::Button::key(KEY_A)}, {raylib::Button::key(KEY_D)}) - .move(); + input.actions["forward_pos"] = raylib::Action::key(KEY_W).move(); + input.actions["forward_neg"] = raylib::Action::key(KEY_S).move(); + input.actions["turn_pos"] = raylib::Action::key(KEY_A).move(); + input.actions["turn_neg"] = raylib::Action::key(KEY_D).move(); input.actions["space"] = raylib::Action::key(KEY_SPACE).move(); input.actions["tab"] = raylib::Action::key(KEY_TAB).move();