碰撞检测的边界框重叠并引发问题
本文关键字:问题 重叠 边界 碰撞检测 | 更新日期: 2023-09-27 18:22:33
下面的代码是我试图阻止PC(玩家角色)穿过NPC。
- "if"语句检查两个矩形(BoundingBox)是否相交
- collisionBox定义重叠边界框的区域
- 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
{
}
}
我如何做到当电脑触摸NPC时,电脑停止向该方向移动,但可以自由移动其他三个方向中的任何一个?
我尝试过的代码:
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;
}
^这样可以将电脑锁定到位,防止任何移动。
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;
}
^这也会将电脑锁定到位。
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的边缘,但防止重叠。不幸的是,有一半的时间电脑卡在原地。
合并两个
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;
}
^这个几乎工作得很好,但当电脑靠在NPC上并垂直于它所接触的NPC转动时,电脑会跳到一边。同样,大约有一半的时间。
受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)
}
}
我再问一次:我该如何做到当电脑触摸NPC时,电脑停止向该方向移动,但可以自由移动其他三个方向中的任何一个?
或者,用更通用的术语来说,如何使一个矩形与另一个矩形相交,在不阻碍其向任何其他方向移动的情况下,失去向相交矩形移动的能力?
在这种情况下我所做的是:
- 正常执行位移(即将角色的运动矢量添加到其位置)
- 检查所有障碍物是否发生碰撞。如果发生碰撞,将角色"传送"到远离障碍物的地方,比如一个像素。继续执行此操作,直到不再发生碰撞
这可能不是运行最快的解决方案,但它可以完成任务。当有许多动态的东西也可能发生碰撞时,效果很好。
经过多次戴头巾和酗酒,我终于想出了一个解决方案。我甚至把它放在一个班级里,这样其他人就可以用它来帮助他们解决类似的问题。
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坐标)、要用来改变或阻止其移动的矢量,以及物体移动的速度(每帧像素)
我希望这能像帮助我一样帮助其他人。