0
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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! \$\endgroup\$ Sep 24, 2020 at 10:33
  • \$\begingroup\$ 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. \$\endgroup\$
    – Philipp
    Sep 24, 2020 at 11:39

2 Answers 2

0
\$\begingroup\$

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;
\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$ Sep 24, 2020 at 14:52
0
\$\begingroup\$

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.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .