我有一个2D瓷砖矩阵(现在是墙壁),每个墙上都会检查我的播放器下一个Rectangle
(下一个,如下所示它将在下一个框架)与该墙碰撞,如果是,我希望我的玩家站在它旁边,而不是进入它内部。
这是我提出的公式(这只适用于左右碰撞):
//*move entity
if (KState.Down(Keys.W)) en.AddForce(new Vector2(0, -10));
if (KState.Down(Keys.S)) en.AddForce(new Vector2(0, 10));
if (KState.Down(Keys.A)) en.AddForce(new Vector2(-10, 0));
if (KState.Down(Keys.D)) en.AddForce(new Vector2(10, 0));
foreach(Item i in map.Items)
{
//resolve left-right collision
if (en.NextBody(elapsedTime).Intersects(i.Body))
{
//check distance between top left corners
int distance = (int)Math.Abs(i.Position.X - en.Position.X);
//stop player in his horisontal movement
en.AddForce(new Vector2(-en.Force.X, 0));
//place player next to the wall his about to collide with
en.Position = new Vector2(en.Position.X - distance + i.Body.Width, en.Position.Y);
}
}
//stop player in place
if (KState.Clicked(Keys.Space)) en.AddForce(en.Force*-1);
en.Update(elapsedTime);
**
这给了我这个结果(注意fps不稳定,当前矩形是正方形32x32):
文字的最上面一行是Rectangle
,而下一页是玩家与上一次相撞的墙的Rectangle
。
现在,当岩石(玩家)向左移动时,我按住左键一段时间,当向右移动时,我按住右键一段时间。
问题:正如你在gif中看到的那样,当玩家离开时,他向左侧墙壁移动了1个像素。当他向右移动时,他会反弹一次,然后紧靠右墙。我不希望任何弹跳,但我不知道如何在我正在使用的逻辑中解决这个问题。
,如果您知道如何解决Rectangle
碰撞的良好逻辑,以便它们不会从任何一方交叉,我会擅长与我分享。
编辑1:我设法解决了碰撞问题。而不是上面的代码我已经把
int sign = Math.Sign(i.Position.X - en.Position.X);
en.AddForce(new Vector2(-en.Force.X, 0));
//wall is right and player is left
if (sign > 0) en.Position = new Vector2(i.Body.Left - en.Body.Width, en.Position.Y);
//wall is left and player is right
if (sign < 0) en.Position = new Vector2(i.Body.Right, en.Position.Y);
但左侧碰撞的问题是一样的。我试过了
if (sign < 0) en.Position = new Vector2(i.Body.Right + 1, en.Position.Y);
和if (sign < 0) en.Position = new Vector2(i.Body.Right - 1, en.Position.Y);
以防万一,但问题是相同的(在“...... - 1 ......”情况下,玩家陷入困境)。
编辑2:在@paste请求时,以下是来自玩家类的NextBody(float elapsedTime)
代码。
public Rectangle NextBody(float elapsedTime)
{ return new Rectangle((int)(force.X * elapsedTime) + body.X, (int)(force.Y * elapsedTime) + body.Y, body.Width, body.Height); }
答案 0 :(得分:1)
这就是发生的事情:
当岩石向左移动时,物体第一次碰撞,算法可以正常工作。它看到对象重叠,它将力设置为Vector2.Zero
,并移动en
以使其触及item
的右侧。好。您的对象已停在正确的位置。
下一帧会发生什么事情出错。您设置了力矢量,然后调用NextBody()
。我们来看看X坐标。它被设置为:
(int)(force.X * elapsedTime) + body.X
这对此有何评价? force.X
非零,elapsedTime
也非零,但它们小于1,因此当它们转换为int
时,结果为零。因此,您的body
与之前位于同一位置,这意味着Rectangle
重叠。这意味着您的碰撞响应代码被跳过,您的force
向量仍然不为零!
然后,再往下,您调用播放器的Update()
方法。我猜你在那段代码中更新了玩家的Position
和Body
。但由于force
不为零,并且Vector2
使用Position
,因此x坐标最终会变为31.841304...
而不是32
。如果您使用该数字计算新的Body
并在Draw
方法中使用它,则最终会在x = 31处绘制它。下次检查时,它会检测到碰撞,玩家将再次弹出。
有很多方法可以解决这个问题。我在碰撞代码中做的是先实际移动对象并记录它们在前一帧中的位置。这样,对它们位置的最后调整是当它们移出碰撞区域时。