How can I apply a force perpendicular to an object, to "straighten" it

Godot Version

4.2.1

Question

I know what the issue is I’m just not sure what the best way to go about this, I’ve developed a character controller that works similar to a car, it always will apply acceleration towards the way it faces.

The issue is that while it works fine if you are doing a 180 or something it starts to break if you start going in an angle or in a direction 90 degrees from where you are standing, this is because the acceleration stops affecting your velocity going perpendicular so you start going in that direction at a constant rate while your velocity going forward is accelerating.

One possible solution that I’ve thought of is friction, which I have messed with but friction is something that messes with where I want to go in the long run, as this is a human controller, not a ball controller, humans don’t have friction when they run.

my new solution here is to find out how to apply a force that will “straighten” the character I’ve attached a little snippet of my code(which includes all the important parts that you need to know), video footage with velocity(blue), and forward direction(red) which is where acceleration is always being applied unless you stop holding a button down which only then friction is applied, and a diagram of what I want if that makes any sense.

line 1 just rotates the player toward the controllers input
line 2 accelerates the player forward
line 3/4 are just max speed setters

body_to_move.rotation.y = lerp_angle(body_to_move.rotation.y, atan2(intent.x, intent.z), delta * rot_speed)
velocity += body_to_move.global_transform.basis.z * delta * base_acceleration
velocity.x = clamp(velocity.x, -max_speed, max_speed)
velocity.z = clamp(velocity.z, -max_speed, max_speed)

Diagram

Well… humans use a complex set of forces to move, including two different sets of non-central “supported” forces called feet. (???)
You’re making a simulation. A simulation is not accurate. Your degree of accuracy is a choice.
I have made very satisfying FPS controllers that use only a downward raycaster for the feet and a thin cylinder at hip height for collision.
Since you’ve figured out how to apply a central force to your character body, why not go a step further and just use a RigidBody instead of a Kinematic?
That way you don’t have to worry so much about managing the forces, just add the intention and let the system solve friction etc.
Player controllers work best with a rather high friction or linear dampening even. What I ended up doing is detecting the “grounded” state with a feet point under the character and switch to zero dampening if we’re in the air. It works much better than trying to figure out every corner case yourself.

2 Likes

I wouldnt call this a simulation really, rather a character controller that will be very modular and controllable, I’ve used rigid body before which works fine but it feels harder to force it to do what I want in a game that wont neccecarily need the physics of a rigid body. although yeah a high friction does make sense for a character moving.

Either way, I do want to learn the math of applying a force to the side of a character to straighten it since I cant find many resources on it.

If want to use physics to achieve this, then essentially you need to apply a
friction force.

  1. Calculate the dot (Dot product) between the character’s linear_velocity and a vector that is perpendicular to its heading. If you’re using the character’s z axis as forward, then you of course need to use the x axis as the perpendicular. Because a dot product is used to compare the angle between two vectors, this will basically tell you how much the character is ‘drifting’ sideways as compared to the intended heading z direction. I’ll call this drift_factor for the purposes of this. Note that there is no need to normalize the linear velocity as the dot product will still work, and we actually want a non-normalised result that represents a drift force magnitude.

  2. Calculate the sideways drift_force vector occuring by multiplying the character’s perpendicular x axis vector by the previously calculated float drift_factor. This will result in a vector that represents the direction and magnitude of how much the character is drifting sideways.

  3. Apply this calculated drift_force as a force in the opposite direction. This will negate and zero out the drifting that is occuring. You’ll end up with a perfect grip essentially, which allows the character to move forward and turn with zero drift.

It’s basically three lines of code. I’ve done this for 2D but not checked for 3D sorry, but the principles are exactly the same. Hope that helps.

2 Likes

The direction you’re facing when moving forward is the direction you’re applying velocity. This eventually gets you moving in that direction when the momentum is around 90 degrees as you can tell in your video, but it’s not the most effective means.

What you should instead do is determine based on your current velocity and your intended direction, what velocity vector should you apply so that you start moving in that intended direction at a faster rate?

Friction is just a force applied in the opposite direction of momentum that eventually will cause the object to come to rest. That’s one way of achieving this.

I think this is exactly what I was looking for and trying to apply, I’m very new to matrix math so this helps a lot :slight_smile: I will try to implement this and reply later since it might take me a bit to wrap my head around this math. But from what I gather it should only apply the friction to the drifting not the forward velocity?

No need for any matrix math, it’s just vectors. Something like this:

drift_factor = linear_velocity.dot(transform.x)
drift_force = (transform.x * drift_factor)

Then depending on what your Node3D physics setup is, you just have to apply the negative -drift_force as a force, or potentially directly to the linear_velocity of the character.

1 Like

Oh, that’s my bad, I thought dot products were related to matrix math, I do want to clarify that I am using a characterbody3d, not a rigidbody3d. But I do think I can still apply this.

If you’re using a CharacterBody3D then your current approach might be over-complicating things potentially? If you want a bit of acceleration and deceleration for a humanoid character controller then take a look at this method: https://youtu.be/xIKErMgJ1Yk?si=3-_RpFx-pcG_jIHx&t=1385

1 Like

While that controller works fine depending on what you are doing I chose this method for a few reasons. The biggest reason for me is that there’s still a more physics-based approach without being a rigidbody3D, as I want a really specific feeling movement. Specifically, a movement system that applies a velocity forward only and dictates direction based on rotating the player. I suppose I could explain more as to why I chose this but Its a bit off-topic for this post.

Fair enough, in which case you just need to calculate the friction force and apply that to counteract the drift occuring.

1 Like

Solved! Thanks so much, ijidau!

	if intent:
		body_to_move.rotation.y = lerp_angle(body_to_move.rotation.y, atan2(intent.x, intent.z), delta * rot_speed)
		velocity += body_to_move.global_transform.basis.z * delta * base_acceleration
		var drift_factor = body_to_move.velocity.dot(body_to_move.basis.x)
		var drift_force = (body_to_move.basis.x * drift_factor)
		velocity -= drift_force
		velocity = velocity.limit_length(max_speed)
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.