在过去的几天里,我一直在用MonoGame和C#对一个球进行物理模拟。球弹跳得很好,但是当球的弹力太低时,球就会进入地面。我能阻止这一切发生吗?我已经试过降低重力常数,改变碰撞的工作方式等等,但是似乎没有什么效果。(我对处理图形相当陌生,所以一个简单的解释将是非常有用的)
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Particle_Simulation
{
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D particleTexture;
SpriteFont font;
Rectangle particle;
Vector2 velocity = new Vector2(4, 0);
Vector2 acceleration = new Vector2(0, 0.25f);
public Game1()
{
graphics = new GraphicsDeviceManager(this);
//graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
//graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
//Load your game content here
particleTexture = Content.Load<Texture2D>("ball");
font = Content.Load<SpriteFont>("textFont");
particle = new Rectangle(200, 200, 60, 60);
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
//Add your update logic here
velocity.X += acceleration.X;
velocity.Y += acceleration.Y;
particle.X += (int)velocity.X;
particle.Y += (int)velocity.Y;
if (particle.Top <= 0 || particle.Bottom >= GraphicsDevice.Viewport.Height)
velocity.Y = -velocity.Y;
if (particle.Left <= 0 || particle.Right >= GraphicsDevice.Viewport.Width)
velocity.X = -velocity.X;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
//Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(particleTexture, particle, Color.White);
spriteBatch.DrawString(font, "X: " + velocity.X.ToString() + " Y: " + velocity.Y.ToString(), new Vector2(0, 0), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
}发布于 2021-04-12 02:52:30
这是碰撞检测的经典问题之一,碰撞发生在物体路径的某个点,但物体移动得足够远,下一个滴答无法解决问题,让物体--在这种情况下,你的球--永远落在视口之外。
要解决这个问题,不仅需要改变垂直速度,还要让球在碰撞点上反射。你已经在弹跳速度矢量了,你只需要增加位置反射。简单的方法就是取超射量,从极限中减去,把球放回界内:
if (particle.Top < 0)
{
velocity.Y = -velocity.Y;
particle.Y = -particle.Y;
}
else if (particle.Bottom >= GraphicsDevice.ViewPort.Height)
{
velocity.Y = -velocity.Y;
particle.Y = GraphicsDevice.ViewPort.Height - (particle.Bottom - GraphicsDevice.ViewPort.Height + particle.Height);
}对速度和位置的X部分也这样做。在大多数情况下,最终的结果应该是好的,即使是角穿透。
因为你只是在反映整个速度,你会得到一些累积的错误,这将导致球在每次撞击后弹跳“更高”。想象一下,一个球直接下降,但目前就在表面上方。加速后,当没有碰撞时,球的速度(大致)是正确的。但是..。如果碰撞发生在行程距离的10%,那么直到那个点的速度只会加一部分加速度,那么路径的其余部分就会减慢,因为垂直速度现在与加速度相反。在极端情况下-低高度以上的底部,非常低的速度和高度的‘重力’-你仍然可以结束与球被嵌入地面。
这使得你的碰撞代码更加困难,但至少你不会因为加速错误的积累而导致球从屏幕上飞出来。
从加速和速度的代码开始,如果有碰撞,那么在计算出碰撞发生的路径有多远后,您需要返回并再次执行。你可以从简单地使用这个比率开始,但是如果你的目标是真正的精确,那么你需要做一些有趣的数学来使它真正的工作。有一些微积分可以计算出撞击时的真实速度和反弹后重力的影响,但要找到所有这些东西的参考资料应该不难。
另一件事,你可能要做的是增加一些速度下降后,冲击。完美的弹性碰撞在碰撞后给出了同样的速度,但在现实世界中,物体的一些动量被浪费成热、声音等。你可以用一个小的乘子来表示这一点--用一个小的乘子来乘以0.99或其他东西--在碰撞中增加一些损失。
由于你几乎永远不会在你的错误中获得一个完美的平衡,球要么加速,要么减速,最终逃逸或坐在地板上。确保你有一个策略来处理这两种情况发生的时候。
当你遇到任意角度的碰撞时.数学又变得更有趣了。
哦,别忘了用gameTime来缩放你的加速值。ElapsedGameTime属性将告诉您上次调用Update是多长时间,并且它将是不一致的。如果一个框架需要很长的时间来处理,那么球的加速度就会变慢。同样,短帧时间也会使球移动得更快。
https://stackoverflow.com/questions/67051313
复制相似问题