球在每次碰撞中获得越来越多的能量
Ball is getting more and more energi for each collision
我正在尝试在 monogame 中编写一些简单的 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 和速度是用户输入的起始位置和速度。
重力只是一个浮点数 = 9.82f;
现在除了设置球的起始位置外,我没有对 posX 做任何事情。下一步将是实现投掷动作。
编辑:
摩擦力 = 0.001f;
t 是增量时间。
我分析了你的逻辑并准备了示例代码。请在阅读之前阅读以下内容。
为了模拟现实生活中的运动,您需要准确地实现物理。尽管您实施的速度和位置似乎大部分是正确的,但重力需要被视为加速度,因此将其值添加到位置(如您的代码中所做的那样)是不正确的。我认为这就是您没有得到预期结果的原因,因为位置的 Y 分量上的增量值远大于应有的值。
我建议您不要使用 PosX
、PosY
表示位置,Velocity_X..()
、Velocity_Y..()
表示速度,而是使用 struct Vector2
如下所示在我的代码中,它包含在 Monogame 框架中并且内置了更多的帮助功能。这将有助于使您的代码更短更清晰。
我不明白为什么在 X 和 Y 分量的 Velocity 实现中使用给定角度的余弦。我下面的代码忽略了这一点。
你可以在下面看到我的代码。这里的弹跳对象 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, 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);
}
}
如Update()
函数所示,PhyObj Box
是在外部加速(本例为重力,但你可以添加自定义外力),而velocity/position它需要达到的目标是内部计算的。
弹跳逻辑很简单:速度的 Y 分量被反转。
此处的“裁剪”过程确保 Box
不会越过 Ground
对象,即使向下加速度作用于它也是如此。
由于摩擦值,接下来的后续弹跳高度降低(由 struct PhyObj
内部完成)。
我正在尝试在 monogame 中编写一些简单的 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 和速度是用户输入的起始位置和速度。 重力只是一个浮点数 = 9.82f;
现在除了设置球的起始位置外,我没有对 posX 做任何事情。下一步将是实现投掷动作。
编辑: 摩擦力 = 0.001f; t 是增量时间。
我分析了你的逻辑并准备了示例代码。请在阅读之前阅读以下内容。
为了模拟现实生活中的运动,您需要准确地实现物理。尽管您实施的速度和位置似乎大部分是正确的,但重力需要被视为加速度,因此将其值添加到位置(如您的代码中所做的那样)是不正确的。我认为这就是您没有得到预期结果的原因,因为位置的 Y 分量上的增量值远大于应有的值。
我建议您不要使用
PosX
、PosY
表示位置,Velocity_X..()
、Velocity_Y..()
表示速度,而是使用struct Vector2
如下所示在我的代码中,它包含在 Monogame 框架中并且内置了更多的帮助功能。这将有助于使您的代码更短更清晰。我不明白为什么在 X 和 Y 分量的 Velocity 实现中使用给定角度的余弦。我下面的代码忽略了这一点。
你可以在下面看到我的代码。这里的弹跳对象 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, 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);
}
}
如Update()
函数所示,PhyObj Box
是在外部加速(本例为重力,但你可以添加自定义外力),而velocity/position它需要达到的目标是内部计算的。
弹跳逻辑很简单:速度的 Y 分量被反转。
此处的“裁剪”过程确保 Box
不会越过 Ground
对象,即使向下加速度作用于它也是如此。
由于摩擦值,接下来的后续弹跳高度降低(由 struct PhyObj
内部完成)。