碰撞检测的边界框重叠并导致问题 [英] BoundingBoxes for Collision Detection overlapping and causing issues

查看:20
本文介绍了碰撞检测的边界框重叠并导致问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码是我阻止 PC(玩家角色)穿过 NPC 的尝试.

The following code is my attempt at stopping the PC (player character) from walking through an NPC.

  • if"语句检查两个矩形(BoundingBox)是否相交.
  • collisionBox 定义了重叠 BoundingBox 的区域
  • moveDir 定义了在 if 语句之后 PC 将经历的 Vector 变化(例如:如果 moveDir=(2,0) PC 将向右移动两个像素)
  • currentSpeed 根据键盘输入(上、下、左、右)定义分配给 moveDir.X 或 moveDir.Y 的值

代码:

if (PC.charSprite.BoundingBox.Intersects(npc.charSprite.BoundingBox))       
{        
    Rectangle collisionBox = Rectangle.Intersect(PC.charSprite.BoundingBox, npc.charSprite.BoundingBox);

    if (PC.moveDir.X > 0) //Moving Right
    {
        //Unknown Code Goes Here
    }
    else if (PC.moveDir.X < 0) //Moving Left
    {

    }
    else if (PC.moveDir.Y > 0) //Moving Down
    {

    }
    else if (PC.moveDir.Y < 0) //Moving Up
    {

    }
}

如何让 PC 接触 NPC 时,PC 停止向该方向移动,但可以自由移动其他三个方向中的任何一个?

How do I make it so that when the PC touches an NPC, the PC stops moving in that direction but is free to move any of the other three directions?

我尝试过的代码:

if (PC.moveDir.X > 0) //Moving Right
{
    PC.moveDir = Vector2.Zero;
}
else if (PC.moveDir.X < 0) //Moving Left
{
    PC.moveDir = Vector2.Zero;
}
else if (PC.moveDir.Y > 0) //Moving Down
{
    PC.moveDir = Vector2.Zero;
}
else if (PC.moveDir.Y < 0) //Moving Up
{
    PC.moveDir = Vector2.Zero;
}

^这会将 PC 锁定到位,防止任何和所有移动.

^This locks the PC in place, preventing any and all movement.

if (PC.moveDir.X > 0) //Moving Right
{
    PC.moveDir.X = 0;
}
else if (PC.moveDir.X < 0) //Moving Left
{
    PC.moveDir.X = 0;
}
else if (PC.moveDir.Y > 0) //Moving Down
{
    PC.moveDir.Y = 0;
}
else if (PC.moveDir.Y < 0) //Moving Up
{
    PC.moveDir.Y = 0;
}

^这也将 PC 锁定到位.

^This, also, locks the PC in place.

if (PC.moveDir.X > 0) //Moving Right
{
    PC.moveDir.X = -currentspeed;
}
else if (PC.moveDir.X < 0) //Moving Left
{
    PC.moveDir.X = currentspeed;
}
else if (PC.moveDir.Y > 0) //Moving Down
{
    PC.moveDir.Y = -currentspeed;
}
else if (PC.moveDir.Y < 0) //Moving Up
{
    PC.moveDir.Y = currentspeed;
}

^这在非常间歇性的基础上工作.我曾希望通过将 moveDir 更改为与其重叠(或更大)的相反方向,可以将 PC 保持在 NPC 的边缘,但防止重叠.不幸的是,有一半的时间 PC 会卡在原地.

^This works on a terribly intermittent basis. I had hoped that by changing moveDir into the opposite direction of how much it had overlapped by (or greater) would keep the PC at the edge of the NPC but prevent overlap. Unfortunately, half the time the PC gets stuck in place.

两者结合

if (PC.moveDir.X > 0) //Moving Right
{
    PC.moveDir.X = -currentspeed;
    PC.moveDir.X = 0;
}
else if (PC.moveDir.X < 0) //Moving Left
{
    PC.moveDir.X = currentspeed;
    PC.moveDir.X = 0;
}
else if (PC.moveDir.Y > 0) //Moving Down
{
    PC.moveDir.Y = -currentspeed;
    PC.moveDir.Y = 0;
}
else if (PC.moveDir.Y < 0) //Moving Up
{
    PC.moveDir.Y = currentspeed;
    PC.moveDir.Y = 0;
}

只会导致整体锁定.

if (PC.moveDir.X > 0) //Moving Right
{
    PC.moveDir.X = -collisionBox.Width;
}
else if (PC.moveDir.X < 0) //Moving Left
{
    PC.moveDir.X = collisionBox.Width;
}
else if (PC.moveDir.Y > 0) //Moving Down
{
    PC.moveDir.Y = -collisionBox.Height;
}
else if (PC.moveDir.Y < 0) //Moving Up
{
    PC.moveDir.Y = collisionBox.Height;
}

^这几乎完美运行,但是当 PC 靠在 NPC 上并垂直于它接触的 NPC 时,PC 会跳到一侧.同样,大约一半的时间.

^This almost works perfectly, but when the PC is up against the NPC and turns perpendicular to the NPC it is touching, the PC jumps to one side. Again, about half the time.

受 CSJ 评论启发的尝试:

Attempt inspired from comment by CSJ:

if (PC.charSprite.BoundingBox.Intersects(npc.charSprite.BoundingBox))
{
    Rectangle collisionBox = Rectangle.Intersect(PC.charSprite.BoundingBox, npc.charSprite.BoundingBox);
    if (PC.moveDir.X > 0) //Moving Right
    {
        PC.charSprite.Position = new Vector2(npc.charSprite.BoundingBox.Left - 34, PC.charSprite.Position.Y);
    }
    else if (PC.moveDir.X < 0) //Moving Left
    {
        PC.charSprite.Position = new Vector2(npc.charSprite.BoundingBox.Right + 2, PC.charSprite.Position.Y);
    }
    else if (PC.moveDir.Y > 0) //Moving Down
    {
        PC.charSprite.Position = new Vector2(PC.charSprite.Position.X, npc.charSprite.BoundingBox.Top - 34);
    }
    else if (PC.moveDir.Y < 0) //Moving Up
    {
        PC.charSprite.Position = new Vector2(PC.charSprite.Position.X, npc.charSprite.BoundingBox.Bottom + 2)
    }
}

我再问一次:如何让 PC 接触 NPC 时,PC 停止向该方向移动,但可以自由移动其他三个方向中的任何一个?

I ask again: How do I make it so that when the PC touches an NPC, the PC stops moving in that direction but is free to move any of the other three directions?

或者,更笼统地说,我如何让一个与另一个矩形相交的矩形失去向它相交的矩形移动的能力,而不会妨碍它向任何其他方向的移动?

Or, in more generic terms, how do I make one Rectangle intersecting with another Rectangle lose its ability to move towards the Rectangle it is intersecting without impeding its movement in any other direction?

推荐答案

在[i]很多[/i]头撞和喝酒之后,我终于想出了一个解决方案.我什至把它放到了一个类中,以便其他人可以用它来帮助他们解决类似的问题.

After [i]much[/i] headbanging and alcohol drinking, I finally came up with a solution. I even placed it into a class so that others may use it to help them with similar problems.

class Collision
{
    #region Declarations
    private Rectangle rectangle1;
    private Rectangle rectangle2;
    private Rectangle collisionZone;
    #endregion

    #region Constructors
    public Collision(Rectangle R1, Rectangle R2)
    {
        rectangle1 = R1;
        rectangle2 = R2;
        if(AreColliding())
        {
            collisionZone = Rectangle.Intersect(rectangle1, rectangle2);
        }
        else
        {
            collisionZone = Rectangle.Empty;
        }
    }
    #endregion

    #region Properties
    /// <summary>
    /// Returns the x-axis value of the top-left corner of R1
    /// </summary>
    public int TopLeftR1X
    {
        get { return rectangle1.X; }
    }

    /// <summary>
    /// Returns the y-axis value of the top-left corner of R1
    /// </summary>
    public int TopLeftR1Y
    {
        get { return rectangle1.Y; }
    }

    /// <summary>
    /// Returns the x-axis value of the top-right corner of R1
    /// </summary>
    public int TopRightR1X
    {
        get { return rectangle1.X + rectangle1.Width; }
    }

    /// <summary>
    /// Returns the y-axis value of the top-right corner of R1
    /// </summary>
    public int TopRightR1Y
    {
        get { return rectangle1.Y; }
    }

    /// <summary>
    /// Returns the x-axis value of the bottom-left corner of R1
    /// </summary>
    public int BottomLeftR1X
    {
        get { return rectangle1.X; }
    }

    /// <summary>
    /// Returns the y-axis value of the bottom-left corner of R1
    /// </summary>
    public int BottomLeftR1Y
    {
        get { return rectangle1.Y + rectangle1.Height; }
    }

    /// <summary>
    /// Returns the x-axis value of the bottom-right corner of R1
    /// </summary>
    public int BottomRightR1X
    {
        get { return rectangle1.X + rectangle1.Width; }
    }

    /// <summary>
    /// Returns the y-axis value of the bottom-right corner of R1
    /// </summary>
    public int BottomRightR1Y
    {
        get { return rectangle1.Y + rectangle1.Height; }
    }

    /// <summary>
    /// Returns the x-axis value of the top-left corner of R2
    /// </summary>
    public int TopLeftR2X
    {
        get { return rectangle2.X; }
    }

    /// <summary>
    /// Returns the y-axis value of the top-left corner of R2
    /// </summary>
    public int TopLeftR2Y
    {
        get { return rectangle2.Y; }
    }

    /// <summary>
    /// Returns the x-axis value of the top-right corner of R2
    /// </summary>
    public int TopRightR2X
    {
        get { return rectangle2.X + rectangle2.Width; }
    }

    /// <summary>
    /// Returns the y-axis value of the top-right corner of R2
    /// </summary>
    public int TopRightR2Y
    {
        get { return rectangle2.Y; }
    }

    /// <summary>
    /// Returns the x-axis value of the bottom-left corner of R2
    /// </summary>
    public int BottomLeftR2X
    {
        get { return rectangle2.X; }
    }

    /// <summary>
    /// Returns the y-axis value of the bottom-left corner of R2
    /// </summary>
    public int BottomLeftR2Y
    {
        get { return rectangle2.Y + rectangle2.Height; }
    }

    /// <summary>
    /// Returns the x-axis value of the bottom-right corner of R2
    /// </summary>
    public int BottomRightR2X
    {
        get { return rectangle2.X + rectangle2.Width; }
    }

    /// <summary>
    /// Returns the y-axis value of the bottom-right corner of R2
    /// </summary>
    public int BottomRightR2Y
    {
        get { return rectangle2.Y + rectangle2.Height; }
    }

    /// <summary>
    /// Returns the rectangle formed by how much the rectangles overlap.
    /// </summary>
    public Rectangle Overlap
    {
        get { return collisionZone; }
    }

    #endregion

    #region Methods

    public bool AreColliding()
    {
        if (rectangle1.Intersects(rectangle2))
        {
            return true;
        }
        else
        {
            return false;
        }

    }

    public Vector2 StopOnCollision(Vector2 position, Vector2 moveDir, int currentspeed)
    {
        if (Overlap.Width < Overlap.Height)
        {
            if (position.X < rectangle2.Left)
            {
                if (moveDir.X > 0) //Moving Right
                {
                    moveDir = Vector2.Zero;
                }
                else
                {
                    moveDir.X = -currentspeed;
                    moveDir.Y = 0;
                }
            }
            //else if ((position.X + 33) > rectangle2.Right)
            else if (position.X < rectangle2.Right)
            {
                if (moveDir.X < 0) //Moving Left
                {
                    moveDir = Vector2.Zero;
                }
                else
                {
                    moveDir.X = currentspeed;
                    moveDir.Y = 0;
                }
            }
        }
        else
        {
            if (Overlap.Y == rectangle2.Top)

            {
                if (moveDir.Y > 0) //Moving Down
                {
                    moveDir = Vector2.Zero;
                }
                else
                {
                    moveDir.Y = -currentspeed;
                    moveDir.X = 0;
                }
            }

            else
            {
                if (moveDir.Y < 0) //Moving Up
                {
                    moveDir = Vector2.Zero;
                }
                else
                {
                    moveDir.Y = currentspeed;
                    moveDir.X = 0;
                }
            }
        }

        return moveDir;
    }

    #endregion
}

有点简单:- 使用正在检查的两个碰撞框(矩形)实例化类.- 您可以检查以确保它们实际上正在发生碰撞.- 要使用 StopOnCollision,您需要输入正在移动的物体的位置(参考的 x,y 坐标)、您希望用来改变或阻止其移动的矢量以及物体移动的速度(每帧像素数))

It's somewhat simple: - You instantiate the class with the two collision boxes (rectangles) you are checking. - You can check to make sure that they, in fact, are colliding. - To use StopOnCollision, you input the position of whatever is moving (the x,y coordinate of reference), the vector that you wish to use to alter or impede its movement, and the speed at which the object is moving (pixels per frame)

我希望这对其他人的帮助和对我的帮助一样多

I hope this helps everyone else as much as it helped me

这篇关于碰撞检测的边界框重叠并导致问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆