Hi, Learning Godot.

I'm following this tutorial that it makes a Minigolf project. My problem is that I try to stop the Ball (Rigidbody) when the LinearVelocity.Length < 0.1, but it doesn't work.

Here is the code (C#)

using Godot;
using System;

public class Ball : RigidBody
{
    [Signal]
    delegate void Stopped();

    public void Shoot(float angle, float power)
    {
        var force = Vector3.Forward.Rotated(Vector3.Up, angle);
        ApplyImpulse(Vector3.Zero, force * power / 5f);
    }

    public override void _IntegrateForces(PhysicsDirectBodyState state)
    {
        GD.Print($"LinerVelocity: {state.LinearVelocity}");
        GD.Print($"LinerVelocity.Lenght: {state.LinearVelocity.Length()}");
    
        if (state.LinearVelocity.Length() <= 0.1f)
        {
            GD.Print("--> Emit Signal Stopped");
            EmitSignal(nameof(Stopped));
            // TODO: for some reason we can't stop the ball
            state.LinearVelocity = new Vector3(0, 0, 0);
            // state.LinearVelocity *= 0;
            
        }
    }
    
}

I tried also with GDScript and found the same problem

Any idea how to implement this?

Thanks.

Welcome to the forums @YakDogGames!

Looking at the code, the only thing I can think of that may be causing the ball to continue to move is the angular_velocity. It could be pushing the ball just a bit, causing it not to come to a complete standstill.

@TwistedTwigleg said: Welcome to the forums @YakDogGames!

Looking at the code, the only thing I can think of that may be causing the ball to continue to move is the angular_velocity. It could be pushing the ball just a bit, causing it not to come to a complete standstill.

Well thought, but still it doesn't stop it...

This is the updated code:

using Godot;
using System;

public class Ball : RigidBody
{
    [Signal]
    delegate void Stopped();

    public void Shoot(float angle, float power)
    {
        var force = Vector3.Forward.Rotated(Vector3.Up, angle);
        ApplyImpulse(Vector3.Zero, force * power / 5f);
    }

    public override void _IntegrateForces(PhysicsDirectBodyState state)
    {
        // GD.Print($"LinerVelocity: {state.LinearVelocity}");
        // GD.Print($"LinerVelocity.Lenght: {state.LinearVelocity.Length()}");

        if (state.LinearVelocity.Length() <= 0.5f)
        {
            GD.Print($"{OS.GetTicksMsec()} --> Emit Signal Stopped");
            EmitSignal(nameof(Stopped));
            // TODO: for some reason we can't stop the ball
            state.LinearVelocity = new Vector3(0, 0, 0);
            state.AngularVelocity = new Vector3(0, 0, 0);
            // state.LinearVelocity *= 0;
        }
    }
}

The print statement is called many times till the ball stops 'organically' I would say.

Strange. I just tested in a project I'm working on, and the following works for me:

extends RigidBody

# other, non-related code here

func _physics_process(delta):
	# other, non-related code here
	
	if (Input.is_action_just_pressed("action_y")):
		linear_velocity = Vector3.ZERO;
		angular_velocity = Vector3.ZERO;

Is there anything in your scene that could be pushing the RigidBody or any code that is applying forces to it? I did notice that zeroing out the linear_velocity and angular_velocity only stopped the RigidBody if nothing else was modifying it. I added the code above to a player script that uses a RigidBody, and if the movement actions were pressed, the RigidBody would still move a little even if action_y was pressed at the same time.

@TwistedTwigleg said: Strange. I just tested in a project I'm working on, and the following works for me:

extends RigidBody

# other, non-related code here

func _physics_process(delta):
	# other, non-related code here
	
	if (Input.is_action_just_pressed("action_y")):
		linear_velocity = Vector3.ZERO;
		angular_velocity = Vector3.ZERO;

Is there anything in your scene that could be pushing the RigidBody or any code that is applying forces to it? I did notice that zeroing out the linear_velocity and angular_velocity only stopped the RigidBody if nothing else was modifying it. I added the code above to a player script that uses a RigidBody, and if the movement actions were pressed, the RigidBody would still move a little even if action_y was pressed at the same time.

Any reason you don't use _integrate_forces instead? The idea is to stop the ball from moving when the velocity is already slow.

For my project, using _physics_process works fine because I am just adding and removing forces using the add_force and apply_impulse functions, rather than directly modifying the velocity vectors. I just slapped the code in and used _physics_process for testing purposes.

I knew the code was for stopping the ball from moving when velocity is low, but the project I am using has linear damping and angular damping on the RigidBody, which slows the RigidBody. This would make it hard to tell how the code was working in the project, so I opted for triggering the result using Input instead.

@TwistedTwigleg said: For my project, using _physics_process works fine because I am just adding and removing forces using the add_force and apply_impulse functions, rather than directly modifying the velocity vectors. I just slapped the code in and used _physics_process for testing purposes.

I knew the code was for stopping the ball from moving when velocity is low, but the project I am using has linear damping and angular damping on the RigidBody, which slows the RigidBody. This would make it hard to tell how the code was working in the project, so I opted for triggering the result using Input instead.

First of all, Thank you a lot for taking your time trying to figure out this.

I found out why I think it doesn't stop.

_integrate_forces is called when there is physics processing, in my case movement. So, I was playing around and using your example I found that setting the Velocity to Zero doesn't actually make the Velocity Zero instantly, visually yes but in the Physics engine, No. Here is whats going on:

LinearVelocity.Lenght: 0.10027980000000000000
LinearVelocity.Lenght: 0.09946802000000000000
19198 --> Emit Signal Stopped
LinearVelocity.Lenght: 0.00000286102300000000
21217 --> Emit Signal Stopped
LinearVelocity.Lenght: 0.00000286102300000000
... Many more here
21217 --> Emit Signal Stopped
LinearVelocity.Lenght: 0.00000000000000000000

As you can see above it drops to a negligibly small number BUT the _integrated_forces is still being called until it finally drops to Zero. So I can 'safely' assume that if the Velocity length is under 0.0001 the ball has stooped and work accordingly.

Thanks

2 years later