Stopping my player object when moving with rigidbody.addrelativeforce

Hi,

In my game I have a player object who runs around a sphere (‘planet’). To do this I’ve implemented a very basic ‘gravity’ script that just applies a constant force to the player object every fixed update:

void FixedUpdate()
{
    //From the gravity source to the player to get right direction
    Vector3 direction = (gravitySource.position - transform.position).normalized;
    Vector3 acceleration = direction * g;

    rb.AddForce(acceleration, ForceMode.Acceleration);
}

In my player script, I grab the input, check that it’s not zero then apply it as a force to the players rigidbody:

private void move()
{
	float horizontalAxis = Input.GetAxis("Horizontal");
	float vertcialAxis =  Input.GetAxis("Vertical");
	float delta = 0.02f;

	bool applyMove = (horizontalAxis>0.0f+delta) || (vertcialAxis>0.0f+delta); 
	moveDirection = new Vector3(horizontalAxis, 0.0f, vertcialAxis);

	Vector3 move = moveDirection*Time.deltaTime*MoveSpeed;

	if( applyMove)
	{
		rigidbody.AddRelativeForce(move);
	}
}

My problem:

When the player stops pressing one of the input keys, I’d like the player object to stop moving.

So far I’ve tried setting the rigidbody’s velocity to zero, but because this happens every fixedUpdate the player is’t pressing a key it stops the force being applied from the gravity script. I have also read that it is a bad idea to set a rigidbodys velocity every fixed update.

I’ve tried adding a counteracting force when the player isn’t pressing a key like:

	if( applyMove)
	{
		rigidbody.AddRelativeForce(move);
		last_force = move;
	}
	else
	{
		if(last_force.sqrMagnitude > 0+delta)
		{
			rigidbody.AddRelativeForce(-rigidbody.velocity);
		}
		last_force = new Vector3(0,0,0);
	}

However this seems to have little effect.

I’ve also tried using rigidbody.MovePosition(). This has two problems, 1) because you’re moving to an absolute position, the force applied due to the gravity script gets ignored so I added a movement due to gravity to the vector I passed to MovePosition which led to 2) my player object seem to constantly be bouncing in and out of the surface of the sphere it was resting on.

What am I doing wrong here? Should I be using rigidbody.addrelativeforce to move my player object? should I be using moveposition? If I use move position how do I stop the player object from ‘bumping into’ what he’s standing on? If I use addrelativeforce, how do I slow my player object down sensibly?

Any thoughts or comments would be appreciated.

Cheers!

The problem with using AddForce for movement is that unless there’s a drag factor, the object will continuously accelerate. You have little ways to know how much your object was accelerated

If you want to keep the current system you can:

  • Add a drag factor. This means the your object will slowly come to rest after the player stopped inputing anything. If a force is continuously applied, by gravity or the player, the object will only accelerate until they reach terminal velocity. It’s a pretty intuitive system.
  • Use a vector var to accumulate every force applied to the player, and then apply the negative of that accumulator once the player stops inputing anything. Expect side-effects. For example moving against the gravity of a planet for 10s, and then letting go of the controls will result in the player rocketing down to the planet at full speed.
  • Don’t use a force to accelerate anything, but simply store a “true velocity” and an “input velocity”. Every frame, take the current velocity, substract the previous input velocity to get the true velocity, and maybe apply a new input velocity. This has the advantage of using no slow acceleration or deceleration, but will look a bit jarring.

Now for miscellaneous infos.

  • AddForce simply increments the velocity, dividing the force by mass and/or multiplying it by Time.fixedDeltaTime depending on the ForceMode.
  • If you want realistic gravity, you should divide the force by the square of the distance. This is what allows all the pretty orbit curves.
  • If you want even more realistic gravity, use AddForce with ForceMode.Acceleration, as gravity doesn’t care much about your mass, it will accelerate all your atoms at the same rate.
  • MovePosition is dangerous, as it requires you to make your own raycast to avoid the bouncing effect. If you take that in account, it’s pretty easy to implement your own true velocity, input velocity, gravity, collisions, etc. with MovePosition, but with more work.

Set Rigidbody.Velocity = Vector3.zero. This should stop it.