Workshop IV - Rays Go Round - Adding Things Up (Mirror)
This post is a mirror of a message board post I wrote in 2020, reposted as-is. There are no errors I'm aware of, but it would be different if I wrote it all again. I'm copying it here for preservation and because it makes sense. ๐
Rays Go Round - Adding Things Up
In "Car Physics for Games", Marco describes a simplistic way of applying torque and accelerating a car, then reading the new RPM back from the wheels. He also briefly outlines a more advanced way of doing it, which is to sum up the torques acting upon the wheels and keep track of the wheel's angular velocity as a result of these competing forces. I think I've developed a pretty solid way of doing that, while avoiding the common consequence of feedback effects in physics-based game design.
The way I've organized my project is to have everything run in one _physics_process() from the RigidBody, so I can make sure all four wheels are updated at once and everything is done in order. All this suspension and tire stuff gets called in a custom method. The RigidBody also passes inputs (from a third node that collects them, for convenience) and simulates the powertrain. Once everything is ready, the RigidBody calls another method on the SpringArm to add up the torques from the engine, tire friction, and braking.
My reasoning: you can initialize the torque for the current frame with friction from your tire model, then add torque from the drivetrain, and finally apply braking torque against those. If braking torque exceeds the other two and the wheel's angular velocity is already almost zero, I just stop it. This mitigates "fidgeting" on stopped wheels from competing forces, so long as the user is on the brakes.
Here is where we calculate "spin" for the slip ratio, and complete the basic necessities for a tire model.
The first step is easy. The longitudinal tire force ("z_force") multiplied by the wheel radius gives a torque. To that, you can go ahead and add the torque from the engine:
var net_torque = z_force * radius net_torque += drive_torque
For drive torque, you can use a static value multiplied by the throttle input to get started.
Applying the brake torque was a little trickier. I mentioned the part about stopping the wheel (first line); the other part is keeping it from spinning the wheels in reverse! ๐ To do that, I multiply the brake torque by the sign of "spin". Again, a static value multiplied by input will suffice to start with:
if abs(spin) < 5 and brake_torque > abs(net_torque): spin = 0 else: net_torque -= brake_torque * sign(spin) spin += delta * net_torque / wheel_moment
Now what's going on in that last line? That is the relationship of angular velocity with torque:
torque = moment_of_inertia * acceleration
acceleration = Torque / moment_of_inertia = delta_velocity / delta_time
delta_velocity = delta_time * torque / moment_of_inertia
The wheel's moment of inertia (rotational inertia) is calculated from its mass (in kilograms), with an export variable to tweak the mass and a quick calculation in _ready() at the start. A simple moment of inertia for a solid disc-shaped object is 0.5 * mass * radius^2, which is close enough for our purposes:
wheel_moment = 0.5 * wheel_mass * radius * radius
With that, the wheels can have some mass to them and react to friction, throttle input, and brake input. To confirm, animate the angular velocity upon your wheel mesh. ๐ This part can go into an ordinary _process() thread because it's only visual:
$Mesh.rotate_x(-spin * delta)
Ackermann Steering
Now's about the time to implement steering, so I'll share my simple formula for an approximation of Ackermann steering, given a negative Ackermann variable for the front right wheel:
func steer(input, max_steer, ackermann): rotation.y = max_steer * (input + (1 - cos(input * 0.5 * PI)) * ackermann)
Adjust the variable to suit whichever model you're using. In my case for now, it is 0.15.
That's pretty much the basic core of the model! I've trimmed some details out to make it easier to follow, piece by piece. I don't know how successful I've been in that objective. ๐
Next time I can share an example I followed that helped me find an effective way to update the engine RPM.
โญ๏ธ Start Your Engines โญ๏ธ
Get GDSim
GDSim
Driving simulator prototype made with Godot
Status | Prototype |
Author | Wolfe |
Genre | Simulation, Racing |
Tags | 3D, Driving, gamepad, Local multiplayer, Physics |
Languages | English |
Accessibility | Configurable controls |
More posts
- 10,000 Downloads! Thank you so much!Apr 14, 2024
- Costly 3D Mistakes to Avoid (Postmortem)Mar 09, 2024
- Tires at Rest - A Deceptive SolutionFeb 07, 2024
- Workshop VI - Brushing Up and Misc. Details (Mirror)Feb 06, 2024
- Workshop V - Start Your Engines (Mirror)Feb 06, 2024
- Workshop III - Rays Go Round - Lateral Force (Mirror)Feb 06, 2024
- Workshop II - Suspending a RigidBody, Part 2 (Mirror)Feb 06, 2024
- Workshop I - Suspending a RigidBody (Mirror)Feb 06, 2024
- SERIES: Driving Simulator Workshop (Mirror)Feb 06, 2024
Leave a comment
Log in with itch.io to leave a comment.