# 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
After gravity adding
49.01105
After Friction
9.80221
After Stop
0
After bounce
0
After gravity adding
10
After gravity adding
20
After gravity adding
30
After gravity adding
40
After Friction
8
After Stop
0
After bounce
0
After gravity adding
10
After gravity adding
20
After gravity adding
30
After gravity adding
40
After Friction
8
After Stop
0


And keeps so on.

Thank you all in advance.

• 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! – formatc2013 Sep 24 '20 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. – Philipp Sep 24 '20 at 11:39

## 2 Answers

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. – ibrahim topçu Sep 24 '20 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.