球在每次碰撞中获得越来越多的能量

问题描述

我正在尝试在单游戏中编写一些简单的 2d 物理。 我从给定的起始位置以给定的速度释放球,并希望它在与地板碰撞时弹回。

我的问题是,我似乎在每次弹跳时给球更多的能量,即每次与地板碰撞时它弹得越来越高。应该是相反的。

我有

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);
}

在我的更新功能中,我有这个:

            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;

其中 posX、posY 和 speed 是用户输入的起始位置和速度。 重力只是一个浮点数 = 9.82f;

现在除了设置球的起始位置外,我不会对 posX 做任何事情。下一步将是实现投掷动作。

编辑: 摩擦 = 0.001f; t 是增量时间。

解决方法

我了解了您的逻辑并准备了示例代码。请在阅读之前阅读以下内容。

  1. 为了模拟现实生活中的运动,您需要准确地实现物理。尽管您实现的速度和位置似乎大部分是正确的,但重力需要被视为加速度,因此将其值添加到位置(如您的代码中所做的那样)是不正确的。我认为这就是您没有得到预期结果的原因,因为位置 Y 分量的增量值远大于应有的值。

  2. 与其保持 C,PosX 为位置,PosY,Velocity_X..() 为速度,我建议您使用 Velocity_Y..() 作为下面显示在我的代码中,它包含在 Monogame 框架中,并且内置了更多帮助功能。这将有助于使您的代码更短、更简洁。

  3. 我不明白您为什么在 X 和 Y 分量的 Velocity 实现中使用给定角度的余弦。我下面的代码忽略了这一点。

你可以在下面看到我的代码。此处弹跳对象 struct Vector2 属于 Box 类型,其中实现了所有所需的运动物理。

struct PhyObj

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,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,(int)Pos.Y); } } 函数所示,Update() 正在被外部加速(在这种情况下为重力,但您可以添加自定义外力),它需要达到的速度/位置为内部计算。

弹跳逻辑很简单:速度的 Y 分量被反转。

此处的“裁剪”过程可确保 PhyObj Box 不会越过 Box 对象,即使向下加速度作用在其上也是如此。

由于摩擦值(由 Ground 在内部完成),下一次后续弹跳的高度会降低。