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\$ – formatc2013 Sep 24 '20 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 '20 at 11:39
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\$ – ibrahim topçu Sep 24 '20 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.