fix: Use incrementing instead of continuous

master
John Montagu, the 4th Earl of Sandvich 2026-03-13 15:14:33 -07:00
parent b1af0e709c
commit fe2fe20a58
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
1 changed files with 83 additions and 36 deletions

View File

@ -28,6 +28,14 @@ raylib::Degree angle_normalize(raylib::Degree angle) {
return raylib::Degree(normalized + decimal); 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) { raylib::Vector3 velocity_from_speed_heading(float speed, raylib::Degree heading) {
return raylib::Vector3{speed * std::sin(heading.RadianValue()), 0.0f, return raylib::Vector3{speed * std::sin(heading.RadianValue()), 0.0f,
speed * std::cos(heading.RadianValue())}; 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 // draw the model, passing the origin and default scale as arguments since
// the transform is already applied to the model // 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 // get the bounding box of the model after applying the transform
auto box = model.GetTransformedBoundingBox(); auto box = model.GetTransformedBoundingBox();
@ -264,22 +272,46 @@ struct InputComponent : public Component {
raylib::BufferedInput *input = nullptr; raylib::BufferedInput *input = nullptr;
bool isActive = false; bool isActive = false;
float axisForward = 0.0f; bool wishInitialized = false;
float axisTurn = 0.0f; float wishSpeed = 0.0f;
bool keySpace = false; 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 { void Setup() override {
if (!input) { if (!input) {
return; return;
} }
input->actions["forward"].AddCallback( input->actions["forward_pos"].AddPressedCallback([this]() {
[this](float state, float delta) { axisForward = state; }); if (isActive) {
wishSpeed += speedStep;
input->actions["turn"].AddCallback([this](float state, float delta) { axisTurn = state; }); }
});
input->actions["space"].AddCallback( input->actions["forward_neg"].AddPressedCallback([this]() {
[this](float state, float delta) { keySpace = (state > 0.0f); }); 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 {} void Cleanup() override {}
@ -296,19 +328,36 @@ struct InputComponent : public Component {
return; 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<OrientedPhysicsComponent>()) {
wishSpeed = orientedInit->get().speed;
} else if (auto physInit = entity->GetComponent<PhysicsComponent>()) {
PhysicsComponent &p = physInit->get();
wishSpeed = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z);
}
wishInitialized = true;
}
if (oriented) { if (oriented) {
OrientedPhysicsComponent &phys = oriented->get(); OrientedPhysicsComponent &phys = oriented->get();
float forward = axisForward; wishSpeed = std::clamp(wishSpeed, -phys.maxSpeed, phys.maxSpeed);
float turn = axisTurn;
phys.speed += forward * phys.acceleration * dt; float speedDiff = wishSpeed - phys.speed;
tf->get().heading = float maxSpeedStep = phys.acceleration * dt;
angle_normalize(tf->get().heading + raylib::Degree(turn * phys.turningRate * dt)); phys.speed += std::clamp(speedDiff, -maxSpeedStep, maxSpeedStep);
if (keySpace) { float headingDiff = shortest_angle_delta(tf->get().heading, wishHeading);
phys.speed *= std::pow(0.05f, dt); float maxHeadingStep = phys.turningRate * dt;
} float headingStepNow = std::clamp(headingDiff, -maxHeadingStep, maxHeadingStep);
tf->get().heading = angle_normalize(tf->get().heading + raylib::Degree(headingStepNow));
} else { } else {
auto phys = entity->GetComponent<PhysicsComponent>(); auto phys = entity->GetComponent<PhysicsComponent>();
if (!phys) { if (!phys) {
@ -317,20 +366,20 @@ struct InputComponent : public Component {
PhysicsComponent &p = phys->get(); PhysicsComponent &p = phys->get();
float spd = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z); wishSpeed = std::clamp(wishSpeed, -p.maxSpeed, p.maxSpeed);
float forward = axisForward;
float turn = axisTurn;
spd += forward * p.acceleration * dt; float currentSpeed =
tf->get().heading = std::sqrt(p.velocity.x * p.velocity.x + p.velocity.z * p.velocity.z);
angle_normalize(tf->get().heading + raylib::Degree(turn * p.turningRate * dt)); float speedDiff = wishSpeed - currentSpeed;
float maxSpeedStep = p.acceleration * dt;
currentSpeed += std::clamp(speedDiff, -maxSpeedStep, maxSpeedStep);
if (keySpace) { float headingDiff = shortest_angle_delta(tf->get().heading, wishHeading);
spd *= std::pow(0.05f, dt); 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(currentSpeed, tf->get().heading);
p.velocity = velocity_from_speed_heading(spd, tf->get().heading);
} }
} }
}; };
@ -357,12 +406,10 @@ int main() {
raylib::BufferedInput input; raylib::BufferedInput input;
input.actions["forward"] = input.actions["forward_pos"] = raylib::Action::key(KEY_W).move();
raylib::Action::button_axis({raylib::Button::key(KEY_W)}, {raylib::Button::key(KEY_S)}) input.actions["forward_neg"] = raylib::Action::key(KEY_S).move();
.move(); input.actions["turn_pos"] = raylib::Action::key(KEY_A).move();
input.actions["turn"] = input.actions["turn_neg"] = raylib::Action::key(KEY_D).move();
raylib::Action::button_axis({raylib::Button::key(KEY_A)}, {raylib::Button::key(KEY_D)})
.move();
input.actions["space"] = raylib::Action::key(KEY_SPACE).move(); input.actions["space"] = raylib::Action::key(KEY_SPACE).move();
input.actions["tab"] = raylib::Action::key(KEY_TAB).move(); input.actions["tab"] = raylib::Action::key(KEY_TAB).move();