# How can I stop the ball from bouncing forever without changing the gravity?

I am using Monogame in Visual Studio 2019 and I need to find a method to make the ball that I fired with the cannon stop after bouncing from the ground, and while doing this, I have to not change the gravity.

• gravity = 10;
• yFriction = 0.2;

    public override void Update(GameTime gameTime)
{
position += velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;

velocity.Y += gravity;

}
public void CheckBounce(SpriteGameObject other)
{
if (!this.CollidesWith(other)) return;

CollisionResult side = this.CollisionSide(other);
Bounce(side);

// Relocating the ball if it's in the wall
switch (side)
{
case CollisionResult.LEFT:
position.X = other.Position.X + other.Width + this.Center.X;
break;
case CollisionResult.RIGHT:
position.X = other.Position.X - this.Center.X;
break;
case CollisionResult.TOP:
position.Y = other.Position.Y + other.Height + this.Center.Y;
break;
case CollisionResult.BOTTOM:
position.Y = other.Position.Y - this.Center.Y;
break;
}
}

public void Bounce(CollisionResult side)
{
switch (side)
{
case CollisionResult.BOTTOM:
velocity.Y *= yFriction;
Stop();
velocity.Y *= -1;
break;
case CollisionResult.TOP:
velocity.Y = Math.Abs(velocity.Y) * yFriction;
break;
case CollisionResult.LEFT:
velocity.X = Math.Abs(velocity.X) * xFriction;
break;
case CollisionResult.RIGHT:
velocity.X = Math.Abs(velocity.X) * -xFriction;
break;
}
}
public void Stop()
{
if (velocity.Y <= gravity)
{
velocity.Y -= velocity.Y;
}
}


At this moment it puts it's velocity.Y to 0. But the problem is the gravity. After bouncing because it doesn't collides, it keeps adding velocity to the ball. As a result I printed out this variables:

After gravity adding
39.01105
49.01105
After Friction
9.80221
After Stop
0
After bounce
0
10
20
30
40
After Friction
8
After Stop
0
After bounce
0
10
20
30
40
After Friction
8
After Stop
0


And keeps so on.

• Your question is confusing, do you want your ball to float in the air forever or just keep bouncing up and down? Please edit your question to clarify it! Sep 24, 2020 at 10:33
• This might only be tangentially related to the problem, but your update-method also needs to multiply gravity with ElapsedGameTime before adding it to the velocity. Sep 24, 2020 at 11:39

the simplest way is to add a lower bound at which you invert the velocity on bounce and make it larger than gravity can add in a single timestep.

case CollisionResult.BOTTOM:
if(abs(velocity.Y) < MIN_BOUNCE_VELOCITY) {
velocity.Y = 0;
} else {
velocity.Y *= yFriction;
Stop();
velocity.Y *= -1;
}
break;


Another thing you can do in addition is to track grounded state and don't add gravity when it's resting on the ground.

if (!grounded)
velocity.Y += gravity;

• I was already able to stop it with my code but gets velocity because of gravity. In this context gravity is MIN_BOUNCE_VELOCITY. I tried to stop adding gravity too but my teacher said that is not allowed to do so in an exam. So there must be another sollution. Sep 24, 2020 at 14:52

I found that I must add gravity to the velocity before add velocity to the position. And I have also changed collision code.

    public override void Update(GameTime gameTime)
{
velocity.Y += gravity;
position += velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;

}
public void CheckBounce(SpriteGameObject other)
{
if (!this.CollidesWith(other)) return;

CollisionResult side = this.CollisionSide(other);
Bounce(side);

// Relocating the ball if it's in the wall
switch (side)
{
case CollisionResult.LEFT:
position.X = other.Position.X + other.Width + this.Center.X;
velocity.X = Math.Abs(velocity.X) * xFriction;
break;
case CollisionResult.RIGHT:
position.X = other.Position.X - this.Center.X;
velocity.X = Math.Abs(velocity.X) * -xFriction;
break;
case CollisionResult.TOP:
position.Y = other.Position.Y + other.Height + this.Center.Y;
velocity.Y = Math.Abs(velocity.Y) * yFriction;
break;
case CollisionResult.BOTTOM:
position.Y = other.Position.Y - this.Center.Y + 1;
velocity.Y *= -yFriction;
break;
}
}


Keeping the ball in the wall only 1 pixel solves the problem.