首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >物理模拟球落地

物理模拟球落地
EN

Stack Overflow用户
提问于 2021-04-12 00:16:11
回答 1查看 237关注 0票数 0

在过去的几天里,我一直在用MonoGame和C#对一个球进行物理模拟。球弹跳得很好,但是当球的弹力太低时,球就会进入地面。我能阻止这一切发生吗?我已经试过降低重力常数,改变碰撞的工作方式等等,但是似乎没有什么效果。(我对处理图形相当陌生,所以一个简单的解释将是非常有用的)

代码语言:javascript
复制
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);
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-12 02:52:30

这是碰撞检测的经典问题之一,碰撞发生在物体路径的某个点,但物体移动得足够远,下一个滴答无法解决问题,让物体--在这种情况下,你的球--永远落在视口之外。

要解决这个问题,不仅需要改变垂直速度,还要让球在碰撞点上反射。你已经在弹跳速度矢量了,你只需要增加位置反射。简单的方法就是取超射量,从极限中减去,把球放回界内:

代码语言:javascript
复制
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是多长时间,并且它将是不一致的。如果一个框架需要很长的时间来处理,那么球的加速度就会变慢。同样,短帧时间也会使球移动得更快。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67051313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档