Emsko
Emsko

Reputation: 95

Ball is getting more and more energi for each collision

Im trying to write some simple 2d physics in monogame. I release a ball from a given start position with a given velocity and I want it to bounce back up when it is colliding with the floor.

My problem is that I seem to give the ball more energi for each bounce i.e. it bounces higher and higher for each collision with the floor. It should be the other way around.

I have:

float get_VelocityX(float _speed, double _angle)
{
    return velocity_x = velocity_x +_speed * (float)Math.Cos(_angle);
}

public float get_VelocityY(float _speed, double _angle, float _t, float gravity)
{
    return velocity_y = velocity_y + _speed * (float)Math.Cos(_angle); // - (float)(-gravity * _t);
}

And in my Update function I have this:

            if (speed > 0)
            {
                timeCount += (float)gameTime.ElapsedGameTime.TotalSeconds;
                t += timeCount;
            }
            else
            {
                return;
            }

            Vx = ball.get_VelocityX(speed, angle);
            Vy = ball.get_VelocityY(speed, angle, t, gravity);
           
            if (posX >= windowMAX)
            {
                posX = posX + -Vx * friction * t;
            }
            if (posY > windowMIN)
            {
                posY = posY + -Vy * friction * t;
            }
            else
            {
                posY += gravity;
            }

            ballRect.X = (int)posX;
            ballRect.Y = (int)posY;

Where posX, posY and speed are user inputs for start position and velocity. Gravity is just a float = 9.82f;

Right now Im not doing anything with the posX except setting the balls starting position. Next step will be to implement a throwing motion.

EDIT: Friction = 0.001f; t is deltatime.

Upvotes: 0

Views: 94

Answers (1)

AzuxirenLeadGuy
AzuxirenLeadGuy

Reputation: 2860

I went through your logic and have prepared a sample code. Please read the following before you go through it.

  1. In order to simulate real-life motion, you need to implement the physics accurately. Although your implemented velocity and position seems mostly correct, the gravity needs to be treated as acceleration, and therefore adding its value to the position (as done in your code) is incorrect. I assume that this is the reason why you aren't getting your expected result since the value of increment on the Y-component of position is far greater than it should be.

  2. Instead of keeping PosX, PosY for the position, Velocity_X..(), Velocity_Y..() for velocity, I would advise you to use struct Vector2 as shown below in my code, which is included in the Monogame framework and has a lot more helping functions built-in. This will help in making your code shorter and cleaner.

  3. I did not understand why you used the Cosine of the given angle in your implementation of Velocity for both its X and Y components. My code below is ignoring this.

You can see my code below. Here the bouncing object Box is of the type struct PhyObj with all the needed Physics of motion implemented within it.

    public class Game1 : Game
    {
        private SpriteBatch _batch;
        internal Texture2D Texture;
        public static Vector2 GravityAcceleration => new Vector2(0, 9.8f);//Constant accerleration along Y-Axis
        internal Rectangle Ground;
        internal PhyObj Box;
        public Game1()
        {
            _ = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        protected override void LoadContent()
        {
            Point center = Window.ClientBounds.Center;
            Box = new PhyObj(new Vector2(center.X, 0), Vector2.Zero, 30, 30);
            Ground = new Rectangle(0, center.Y, center.X * 2, 10);
            _batch = new SpriteBatch(GraphicsDevice);
            Texture = new Texture2D(GraphicsDevice, 1, 1);
            Texture.SetData(new[] { Color.White });
        }
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            Box.Accelerate(GravityAcceleration, gameTime);
            if (Box.Pos.Y > Ground.Top - Box.Dest.Height)//Check if bounce needed
            {
                Box.Pos.Y = Ground.Top - Box.Dest.Height;//Clipping
                Box.Vel.Y *= -1;                         //Bouncing
            }
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            _batch.Begin();
            _batch.Draw(Texture, Ground, Color.Black);
            _batch.Draw(Texture, Box.Dest, Color.White);
            _batch.End();
            base.Draw(gameTime);
        }
    }
    public struct PhyObj
    {
        internal static float friction => 0.005f;
        public PhyObj(Vector2 x, Vector2 v, int width, int height)
        {
            Pos = x;
            Vel = v;
            Dest = new Rectangle(0, 0, width, height);
            (Dest.X, Dest.Y) = ((int)Pos.X, (int)Pos.Y);
        }
        internal Vector2 Pos, Vel;
        internal Rectangle Dest;
        public void Accelerate(Vector2 acc, GameTime time)
        {
            Vel += acc - Vel * friction;
            Pos += Vel * (float)time.ElapsedGameTime.TotalSeconds;
            (Dest.X, Dest.Y) = ((int)Pos.X, (int)Pos.Y);
        }
    }

As shown in the Update() function, the PhyObj Box is being accelerated externally (In this case gravity, but you can add your custom external force), and the velocity/position it needs to attain is calculated internally.

The bouncing logic is simple: The Y-component of velocity is inverted.

The "Clipping" process here makes sure that the Box does not cross the Ground object even when the downward acceleration is acting upon it.

The next subsequent bounces have their height reduced due to the friction value (Done internally by the struct PhyObj).

Upvotes: 1

Related Questions