【问题标题】:Collision Detection System碰撞检测系统
【发布时间】:2012-06-17 20:40:44
【问题描述】:

我正在尝试制作一个简单的平台游戏。玩家是一个正方形,所有的平台都是正方形。我是 XNA 的初学者,但我的 C# 4.0 经验并不丰富。

我的代码的问题是,当我的角色穿过平台的底部时,即使我将其设置为他不应该穿过,他也会继续穿过。

我想提前询问是否有人可以帮助我,因为我无法解决这个问题。

以下是不同代码段如何协同工作:

  • 在平台结构中加载图像并存储一个枚举,该枚举可以保存以下三个值之一:可通过(可以通过)、不可通过(完全实心)和平台(可以通过底部并停在顶部)
  • 需要修复的碰撞检测方法(它检查交叉点,检查特定平台的枚举,然后确定它是否可以通过并返回一个数组,其中包含:{isabove, isbelow, isleft, isright} 平台)
    • 如果玩家在平台顶部,它确实返回 true,但当他们到达底部时没有任何反应
  • 我的玩家的垂直运动处理重力和垂直运动,这可能是罪魁祸首,但我不知道。碰撞检查在开始时在更新循环中运行,然后在之后运行垂直运动方法

这是碰撞的代码:

    public bool[] environmentCollisionDetect(Charachter thing, ScreenObjects sreenobjectlist, bool[] platformstatus)
    {
        //Defaults the collision to false
        platformstatus[0] = false;  //Above platform
        platformstatus[1] = false;  //Below Platform
        platformstatus[2] = false;  //Left
        platformstatus[3] = false;  //Right

        //Store the player in boxA
        boxA.Height = thing.image.Height;
        boxA.Width = thing.image.Width;
        boxA.X = (int)thing.position.X;
        boxA.Y = (int)thing.position.Y;

        //Find a collision
        foreach (Platform platform in screenobjectlist)
        {
            //Makes sure the platform cannot be passed through
            if (platform.platformCollisionProperty != platformCollision.passable)
            {
                //Store the platform's rectangle
                boxB = platform.destinationrectangle;
                boxB.Height = platform.image.Height;
                boxB.Width = platform.image.Width;
                boxB.X = (int)platform.destinationrectangle.X;
                boxB.Y = (int)platform.destinationrectangle.Y;

                //Collision Check
                if (boxA.Intersects(boxB))
                {
                    switch (platform.platformCollisionProperty)
                    {
                        //Platform is Solid
                        case platformCollision.impassible:

                            //Player is below it
                            if (boxA.Top > boxB.Bottom)
                            {
                                platformstatus[1] = true;
                            }

                            //Player is above it
                            if (boxA.Bottom > boxB.Top)
                            {
                                platformstatus[0] = true;
                            }
                            break;

                        //Platform can be passed through bottom
                        case platformCollision.platform:
                            if (boxA.Bottom > boxB.Top)
                            {
                                platformstatus[0] = true;
                            }
                            break;
                    }

                    break;
                }
            }
        }
      return platformstatus;
    }

这是垂直运动代码:

  • 当跳转按钮被激活时,isJumping bool 设置为 true
  • isinair bool 仅在此循环中用于确定玩家是否仍在空中滑行
  • 最后 i 被用作计数器,因为我无法让计时器工作

    public void verticalMotionI(GameTime gametime)
    {
        //Resets the bools if not standing on platform
        if ((this.isJumping == true) && (this.platformstatus[0] == false))
        {
            this.i = 0;
            this.isJumping = false;
            this.isinair = false;
        }
    
        //Jumps if A button is activated and standing on a platform
        else if ((this.isJumping == true) && (this.platformstatus[0] == true))
        {
            //Set up bools to jump
            this.isJumping = false;
            this.isinair = true;
    
            //Overwrites the start time
            this.starttime = currentime;
    
            //Move up
            this.position.Y -= this.playermovementspeed * 1.5f;
    
            //Increase counter
            this.i++;
        }
    
        //Pulls stops moving player if jumptimer had elapsed
        else if ((this.isinair == true) && (i == this.jumptime))
        {
            this.isinair = false;
    
            //Apply gravity
            Gravity.forceofGravity(this);
        }
    
        //Stops the jump if bottom of a platform is hit
        else if ((this.isinair == true) && (this.platformstatus[1] == true))
        {
            //Reset bools
            this.isinair = false;
    
            //reset I
            this.i = 0;
    
            //Apply gravity
            Gravity.forceofGravity(this);
        }
    
        //Continues the jump if in air
        else if ((this.isinair == true) && (this.platformstatus[1] == false))
        {
            //Move up
            this.position.Y -= this.playermovementspeed * 1.5f;
    
            //Increase counter
            this.i++;
        }
    
        //Apply Gravity
        else if ((this.isinair == false) && (this.platformstatus[0] == false))
        {
            //reset I
            this.i = 0;
    
            Gravity.forceofGravity(this);
        }
    }
    

【问题讨论】:

  • 只是查看代码,很好奇您为什么这样做:boxB = platform.destinationrectangle; boxB.Height = platform.image.Height; boxB.Width = platform.image.Width; boxB.X = (int)platform.destinationrectangle.X; boxB.Y = (int)platform.destinationrectangle.Y; 我怀疑它与问题有关,但destinationRectangle 应该已经具有所有这些值。您正在将我们的 Rectangle 设置为目标矩形,然后再次手动设置其每个值!我会继续查看代码...
  • if (boxA.Top > boxB.Bottom) - 如果boxA.Intersects(boxB),则此条件永远不会为真。你的意思是if (boxA.Top < boxB.Bottom && boxA.Top > boxB.Center),也许?这意味着 boxA 的顶部与 boxB 的下半部分发生碰撞。另外,你能否澄清一下你遇到的问题——你的角色是从固体/“平台”平台上掉下来还是从固体平台上跳起来?还要考虑平台状态的枚举,因为我现在无法真正说出它的含义。
  • 抱歉,无法编辑之前的评论,但我的意思是if (boxA.Top < boxB.Bottom && boxA.Top > boxB.Center.Y),因为中心是一个点。
  • 非常感谢,将 > 换成

标签: c#-4.0 xna


【解决方案1】:

如果 Gravity 符合我的假设,看起来你并没有明确设置玩家在撞击平台时的位置,我看到的是你切换你的 isInAir 标志,并应用重力......出于测试目的和解决你的问题,试试这样的伪代码:

if(dude is jumping & dude collides with platform){
   set the top of dudes head to be at position under the platform;
}

希望这会有所帮助。 :)

不要打死马或做驴子,而是在重新发明轮子。看看那里的一些物理引擎。我一直在玩 Farseer 3+,非常棒。在第一次弄清楚 World Body Fixture 模式时有一个轻微的学习曲线,但是一旦你顿悟了,就可以在你的 body/fixture 上设置一些属性并启动 OnCollision 方法。

Farseer 是 .NET 的 Box2D 物理引擎端口,它是开源的,一旦你完成了学习曲线,它就会令人惊叹。

快速浏览一下this farseer doc,您可能会喜欢您所看到的。 :) 即使您不喜欢它,它也是开源的,并且可以为您提供一些关于如何*咳嗽*复制*以您自己的方式实现某些功能的想法。

如果你想要的只是简单的跳跃、对象状态和交互功能,你不需要实现引擎的所有有趣的复杂功能,这些都很好地封装在 Farseer 中。

【讨论】:

【解决方案2】:

if (boxA.Top > boxB.Bottom) - 如果boxA.Intersects(boxB),则此条件永远不会为真。你是说if (boxA.Top < boxB.Bottom && boxA.Top > boxB.Center.Y)吗?

只是重新发布我的评论探索作为将来参考的答案。由于我有回答空间而不是评论空间,因此我还可以解释一些事情。

显然,Rectangle.Intersects(Rectangle) 只有在它们以某种方式重叠时才会成立。诀窍是,在解释这一点时,我们需要记住屏幕上的 Y 坐标实际上是从上到下移动的。 Y = 0 位于屏幕顶部,Y = 位于底部。如果您不熟悉 2D 游戏编程,这可能看起来有些倒退,但这正是图形适配器的工作方式。

所以,通过说 boxA 的顶部 > boxB 的底部,你真正的意思是 boxA 的顶部在屏幕上低于 boxB 的底部,这永远不会是真的,因为我们已经知道它们重叠.我转过条件并添加了一个额外的逻辑点,以提供所需的功能。 boxA.Top > boxB.Center.Y 表示您的 boxA 与 below boxB 特别相交。如果我将其保留为 boxA.Top < boxB.Bottom,则如果 boxA 从 above boxB 落下,则条件也为真,考虑到我们必须区分平台和实体块,我认为您不希望这样做逻辑涉及棋子下方的玩家,因此我们必须在代码中进行区分。当然,你的评论说//player is below it

最后,提一句调试建议:如果您发现某些行为没有发生,请在指示该行为的行上放置一个断点(在本例中为platformstatus[1] = true)。如果您从未遇到过该断点,那么您现在就知道为什么它没有发生了。现在只需在封闭的条件上放置一个断点。当它到达该断点时,手动查看值,将它们与预期值进行比较,并查看您是否使用了适当的逻辑。有时每个人都会在条件句中犯错,这是我个人的第一个弱点。

【讨论】:

    猜你喜欢
    • 2014-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2019-04-30
    • 1970-01-01
    相关资源
    最近更新 更多