How can I stop a RigidBody without directly setting its linear velocity?
I have a ball with a mass of 1 kg, and there is no damping (linear or angular) or friction in the world. The ball’s rotation is frozen.
The gravity_scale of the body is 4, but since there’s no friction, it shouldn’t affect the horizontal movement.
The setup consists of:
RigidBody3D
MeshInstance3D (Sphere)
CollisionShape (Sphere)
Timer
My goal is to stop the ball when the timer runs out, but it’s not working. Why is that?
Bonus question: How can I stop the ball over a specified duration? For example, if I want the ball to decelerate to 0 over 5 seconds, regardless of its initial velocity, how would I do that?
This my test script:
extends RigidBody3D
func _process(delta: float) -> void:
if $Timer.is_stopped():
# The ball turns blue to indicate that it is stopping
$MeshInstance3D.mesh.material.albedo_color = Color.BLUE;
# Since the mass is 1, shouldn't applying a negative linear velocity immediately stop the body?
apply_central_force(-linear_velocity * delta);
else:
apply_central_force(Vector3.FORWARD * 100 * delta);
Hi It’s important to note that applying a force is not an instantaneous change in the object’s speed, but a gradual effect.
Your Problem is that you’re applying a force to slow down the object in _process(), but it doesn’t stop the object immediately.
Problems:
Applying a Force: Using apply_central_force(-linear_velocity * delta) will slow the object down. But the force works as a gradual change in speed, not an instant stop.
Timer: It looks like you’re using is_stopped() to check the state of the timer, but that doesn’t handle the stop correctly when the timer expires.
Possible solutions:
Stopping the object instantly when the timer expires
Instead of applying forces, it is better to use the sleep function, which will freeze the object’s speed:
extends RigidBody3D
func _process(delta: float) -> void:
if $Timer.is_stopped():
# Change the color of the ball to blue
$MeshInstance3D.mesh.material.albedo_color = Color.BLUE
# Stop the object completely
linear_velocity = Vector3.ZERO
angular_velocity = Vector3.ZERO
else:
apply_central_force(Vector3.FORWARD * 100 * delta)
This way, as soon as the timer expires, you can force the body’s speed to zero, and the ball will stop instantly.
Slowing Down an Object Gradually
To slow down a ball over a certain amount of time (e.g. 5 seconds), you can do the following:
Add a slowdown time variable.
Gradually decrease the speed of the object.
extends RigidBody3D
var slow_down_time = 5.0 # Braking time in seconds
var time_passed = 0.0
var initial_velocity = Vector3.ZERO
func _ready():
initial_velocity = linear_velocity # Save the initial velocity
func _process(delta: float) -> void:
if !$Timer.is_stopped():
apply_central_force(Vector3.FORWARD * 100 * delta)
else:
# Change the ball color to blue
$MeshInstance3D.mesh.material.albedo_color = Color.BLUE
# Gradually slow down the ball
if time_passed < slow_down_time:
time_passed += delta
var factor = 1.0 - (time_passed / slow_down_time)
linear_velocity = initial_velocity * factor
else:
# Stop the ball completely after the deceleration time
linear_velocity = Vector3.ZERO
angular_velocity = Vector3.ZERO
How it works:
initial_velocity stores the initial velocity of the ball.
Over 5 seconds (slow_down_time), the ball’s velocity decreases linearly to zero.
After the ball has completely slowed down, its velocity is set to Vector3.ZERO and it stops.
This way you can stop the ball either instantly or smoothly over a given time.
Thank you for the response, but unfortunately I cannot set the linear_velocity directly. I am looking for the correct formula to accurately calculate the force needed to stop the body.
In this case, since you can’t directly set linear_velocity, you need to calculate the force required to smoothly decelerate the body. This can be done using Newton’s second law:
𝐹 =𝑚𝑎
where is the force 𝐹 - is equal to the mass of the object
(𝑚) - multiplied by (𝑎) - acceleration.
So You want the body to stop in a fixed time, say (𝑡) seconds. To do this, you need to calculate the acceleration that will allow the body to slow down to a complete stop.
Steps:
Definition of initial speed: Let the initial speed of the object be 𝑣(zero).
Stopping time: You want to stop the object in time 𝑡
Calculate acceleration: The acceleration required to stop the object can be calculated using the formula: (Acceleration is negative because it is directed against the motion.)
Deceleration force: Now, apply Newton’s law to calculate the force:
extends RigidBody3D
var slow_down_time = 5.0 # Time to decelerate
var initial_velocity = Vector3.ZERO
func _ready():
initial_velocity = linear_velocity # Save the initial velocity
func _process(delta: float) -> void:
if !$Timer.is_stopped():
apply_central_force(Vector3.FORWARD * 100 * delta)
else:
# Change the ball color to blue
$MeshInstance3D.mesh.material.albedo_color = Color.BLUE
# Calculate the deceleration force
var force = -mass * initial_velocity / slow_down_time
# Apply the deceleration force
apply_central_force(force * delta)