2

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

  • “if”语句检查两个矩形(BoundingBox)是否相交。
  • 碰撞框定义重叠边界框的区域
  • moveDir 定义了在 if 语句之后 PC 将经历的矢量变化(例如:如果 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 停止向那个方向移动,但可以自由移动其他三个方向中的任何一个?

我试过的代码:

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 锁定到位,防止任何和所有移动。

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 锁定到位。

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 卡在了原地。

将两者结合

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 会跳到一侧。再次,大约一半的时间。

受 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 停止朝那个方向移动,但可以自由移动其他三个方向中的任何一个?

或者,用更通用的术语来说,我如何使一个与另一个 Rectangle 相交的 Rectangle 失去向它相交的 Rectangle 移动的能力,而不会妨碍它在任何其他方向上的移动?

4

2 回答 2

1

我在这种情况下所做的是:

  • 正常进行位移(即把角色的运动向量加到他的位置上)
  • 检查所有障碍物是否有碰撞。如果发生碰撞,将角色“传送”离开障碍物,例如一个像素。继续这样做,直到不再有碰撞。

它可能不是运行速度最快的解决方案,但它可以完成工作。当有许多动态事物也可能发生碰撞时,效果很好。

于 2013-07-16T01:25:02.120 回答
0

在[i]很多[/i]头撞和饮酒之后,我终于想出了一个解决方案。我什至把它放到一个班级里,这样其他人就可以用它来帮助他们解决类似的问题。

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 坐标)、您希望用来改变或阻止其移动的矢量以及物体移动的速度(每帧像素数)

我希望这对其他人有帮助,就像对我有帮助一样

于 2013-07-17T23:36:11.947 回答