如何在2D平铺游戏中检测和解决碰撞? 我试图用C++的SFML 2.1来为我的2D超级马里奥兄弟克隆做碰撞。我尝试了很多不同的解决方案和想法,但我无法让任何东西正常工作。 我有一个播放器,它当前在自己的更新()中检查冲突(如下所示)
当前:如何在2D平铺游戏中检测和解决碰撞? 我试图用C++的SFML 2.1来为我的2D超级马里奥兄弟克隆做碰撞。我尝试了很多不同的解决方案和想法,但我无法让任何东西正常工作。 我有一个播放器,它当前在自己的更新()中检查冲突(如下所示),c++,collision-detection,sfml,C++,Collision Detection,Sfml,当前: 1.我的碰撞检测到碰撞稍微偏移。如果您能发现任何明显的错误,我很乐意知道。 2.我不确定这是否是一个足够好的解决方案,因为我需要检测4个方向的碰撞(跳跃、头部撞到障碍物上、摔倒在障碍物上以及左/右碰撞) 3.当我检测到碰撞时,我不知道如何纠正玩家的正确方向 我已经清理了所有不必要的代码,并删除了下面不起作用的代码 void Player::Update(Camera& camera, Level& level, sf::RenderWindow& window)
1.我的碰撞检测到碰撞稍微偏移。如果您能发现任何明显的错误,我很乐意知道。
2.我不确定这是否是一个足够好的解决方案,因为我需要检测4个方向的碰撞(跳跃、头部撞到障碍物上、摔倒在障碍物上以及左/右碰撞)
3.当我检测到碰撞时,我不知道如何纠正玩家的正确方向 我已经清理了所有不必要的代码,并删除了下面不起作用的代码
void Player::Update(Camera& camera, Level& level, sf::RenderWindow& window)
{
input.Update(*this); // Read input logic
physics.update(*this, level, camera, window); // Update physics (movement, gravity)
drawing.update(*this); // Update animation ( does NOT draw player )
if(Collision(level, camera, getPosition())) // Check for collision
{
CollisionResponse(); // If we had collision, do something about it
}
}
Collision()
函数接受三个参数:-关卡:这是地图吗 -照相机:返回屏幕上从地图显示的瓷砖 -getPosition():仅显示播放器在窗口中的位置 函数如下所示:
bool Player::Collision(Level& level, const Camera& camera, const sf::Vector2f& position)
{
// Rectangle surrounding player
sf::FloatRect playerRectangle = sprite.getGlobalBounds();
int tileSize = 32;
Tile* tile;
// smallBounds is the area on the screen where we check collision.
// We dont check the whole screen, only tiles that CAN collide with player.
sf::IntRect smallBounds = sf::IntRect(
(position.x / tileSize) + camera.GetTileBounds(tileSize).left,
position.y / tileSize,
((position.x + tileSize) / tileSize) + camera.GetTileBounds(tileSize).left,
(position.y + tileSize) / tileSize);
// Loop through all tiles
for (int y = smallBounds.top; y < smallBounds.height; y++)
{
for (int x = smallBounds.left; x < smallBounds.width; x++)
{
// Get the tile we are drawing
tile = level.GetTile(x, y);
if(tile && !tile->GetWalkable())
{
sf::FloatRect tileRectangle(tile->GetSprite().getPosition().x,
tile->GetSprite().getPosition().y,
tileSize,
tileSize);
tileRect = tileRectangle;
if(Intersect(playerRectangle, tileRectangle))
{
// Woah, collision detected!
return true;
}
}
}
}
return false;
}
如果我遗漏了任何有用的信息,请在下面留下评论
地图由不同的分片组成,分片保存的坐标不是它们实际所在的位置,而是它们在阵列中的位置,因此示例地图如下所示:0,0,10,2
1,01,11,2
2,02,12,2
碰撞功能然后检查与播放器周围的那些瓷砖相关的碰撞 我的尝试:
有很多不同的碰撞方法可以同时解决x和y碰撞。
碰撞响应将玩家移回最后位置。
碰撞响应,按相交矩形的大小将播放器向后移动(这在y轴有效,但在x轴无效)。
当我的头感觉不到融化的奶酪时,我会写更多的东西。将玩家移回最后一个已知的好位置将导致你所经历的行为;球员将与他要碰撞的物体保持一定距离。举个例子:如果您的角色以300像素/秒的速度移动,并且距离墙5像素,则下一次碰撞将在1/60秒后发生。如果帧速率为60FPS,将在下一帧中检测到碰撞,并且角色将移回距离碰撞发生前的墙5像素的位置。当然不可取 只要正确计算数量,您使用的方法(将播放器向后移动相交矩形的大小)应该是有效的。这一点很好(在这篇文章中,具体参见第7节“寻找MTV”) 你可以尝试另一种不涉及计算的方法:在碰撞时,将玩家向后移动一小段时间(甚至是逐像素移动),直到他停止与墙壁碰撞。然后,你会知道一个离墙更近的地方,在那里可以安全地安置他。效率较低,但易于实施 另一种方法是连续碰撞检测。这在本质上有点复杂。您只需四处搜索“连续碰撞”,就可以找到有关它的一些信息,但基本思想是:
- 移动前计算新位置。如果有物体,不要移动。要在x方向进行滑动运动检查碰撞,如果发生碰撞,请不要移动。如果没有碰撞,请检查y的碰撞。如果发生碰撞,不要在y方向移动。仍然没有对x和y(您真正的新位置)上的碰撞进行碰撞检查。如果发生碰撞,停止两个移动
- 移动到新位置。如果在那里碰撞,在x方向重置x移动,如果在y方向碰撞重置y移动,在两个方向碰撞,重置两者
相反,您可以存储角色的4个角点,四舍五入到角色所在的
磁贴上(如果每个磁贴都有一个单位大,并且角色的脚在P(0.5;0.5)上,您需要检查磁贴(0;0))。
玩家的位置
是他的左下角(正常情况下),因此他的其他3点是P2(玩家位置x+玩家宽度;玩家位置y)
,P2(玩家位置x+玩家宽度;玩家位置y+玩家高度)
,P3(玩家位置x;玩家位置y+玩家高度)
,始终向下舍入到平铺
s位置
希望能有所帮助。我没有阅读所有内容,尤其是代码(c++不是我最喜欢的语言^^^),但我有几个问题:要检测碰撞的字符是由什么形状组成的?他们能高速移动吗(一次更新超过一个瓷砖)?我使用的是矩形(我相信是AABB),他们的移动速度不够快,无法解决“子弹穿过纸张”的问题。我将尝试实现其中的每一个。我可能会学到一些东西。但在第二种“低效”的方法中,我怎么知道他是从哪个方向被击中的?x、 -x,y,-y?另外,第三个备选方案听起来很好学,但对这个游戏来说可能太高级了。当我取得进展时,我会再次联系。谢谢:Dre:第二种方法,只需沿角色移动方向的相反方向移动即可。如果他移动+x,将他向后移动-x。如果他移动+y,移动他-y。如果他在移动-x和+y,那么移动他+x和-y。
void Player::CollisionResponse(void)
{
}