SFML (C++) 中的正确碰撞
Proper collision in SFML (C++)
因此,我进行了一项测试,以了解碰撞在 SFML 中的运作方式。我制作了这段代码:
if (floor.getGlobalBounds().intersects(SuperMario.getGlobalBounds())) // Floor
{
SuperMario.setPosition(SuperMario.getPosition().x, floor.getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
如代码所示,马里奥在接触地板物体时会改变位置,并传送到地板上方。
但是,这会产生以下副作用,如下图所示。
请注意,"green box" 是我之前提到的地板对象。另外,忽略图1中的"left"这个词,我的意思是"right".
当然,这种行为是有意为之(即不是错误),但它是不需要的。
所以我的问题是:如何消除这个 "side-effect"?我的意思是,我怎样才能修改我的代码,使马里奥在接触地板两侧时不会传送到地板上方(使平台工作像适当的平台一样)?我想让马里奥被盒子挡住,而不是被传送。
更新:所以现在,我有这个:
for (unsigned int i = 0; i <= solidObjects.size() - 1; i++)
{
if (solidObjects[i].getGlobalBounds().intersects(SuperMario.getGlobalBounds()))
{
if (SuperMario.getPosition().x - solidObjects[i].getPosition().x < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getPosition().x - SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
else if (SuperMario.getPosition().y - solidObjects[i].getPosition().y < SuperMario.getPosition().x - solidObjects[i].getPosition().x)
{
SuperMario.setPosition(SuperMario.getPosition().x, solidObjects[i].getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
else if (SuperMario.getPosition().x - solidObjects[i].getTextureRect().width < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getTextureRect().width + SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
}
else
{
IsTouching = false;
}
}
但是,有一个问题。当马里奥接触到地板的两侧时,他会粘在地板上,这意味着他无法向右移动。
如果我不够清楚,请指出我应该补充或澄清的内容。
这感觉真的很奇怪,因为您通常会定义实心区域,而不是玩家可以在其中行走的区域。毕竟你会希望你的玩家跳起来,而不是让他们粘在地上。
剩下的就很简单了:
- 遍历所有实体对象并确定播放器和实体矩形是否重叠。
- 如果是,请确定哪个距离更小(x 或 y)。这使您可以确定移动玩家的轴。
- 确定玩家离开实体区域的哪个方向更快,即向哪个方向推动玩家。
- 将播放器推向计算的方向并重复检查。
根据您的地图复杂性,这可能会变得相当复杂,因此您很可能需要一些 sorting/spatialisation 来减少比较次数(例如,跳过检查 impossible/far 离开形状)。
因此,我进行了一项测试,以了解碰撞在 SFML 中的运作方式。我制作了这段代码:
if (floor.getGlobalBounds().intersects(SuperMario.getGlobalBounds())) // Floor
{
SuperMario.setPosition(SuperMario.getPosition().x, floor.getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
如代码所示,马里奥在接触地板物体时会改变位置,并传送到地板上方。
但是,这会产生以下副作用,如下图所示。
请注意,"green box" 是我之前提到的地板对象。另外,忽略图1中的"left"这个词,我的意思是"right".
当然,这种行为是有意为之(即不是错误),但它是不需要的。
所以我的问题是:如何消除这个 "side-effect"?我的意思是,我怎样才能修改我的代码,使马里奥在接触地板两侧时不会传送到地板上方(使平台工作像适当的平台一样)?我想让马里奥被盒子挡住,而不是被传送。
更新:所以现在,我有这个:
for (unsigned int i = 0; i <= solidObjects.size() - 1; i++)
{
if (solidObjects[i].getGlobalBounds().intersects(SuperMario.getGlobalBounds()))
{
if (SuperMario.getPosition().x - solidObjects[i].getPosition().x < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getPosition().x - SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
else if (SuperMario.getPosition().y - solidObjects[i].getPosition().y < SuperMario.getPosition().x - solidObjects[i].getPosition().x)
{
SuperMario.setPosition(SuperMario.getPosition().x, solidObjects[i].getPosition().y - SuperMario.getOrigin().y);
IsTouching = true;
}
else if (SuperMario.getPosition().x - solidObjects[i].getTextureRect().width < SuperMario.getPosition().y - solidObjects[i].getPosition().y)
{
SuperMario.setPosition(solidObjects[i].getTextureRect().width + SuperMario.getOrigin().x, SuperMario.getPosition().y);
IsTouching = false;
}
}
else
{
IsTouching = false;
}
}
但是,有一个问题。当马里奥接触到地板的两侧时,他会粘在地板上,这意味着他无法向右移动。
如果我不够清楚,请指出我应该补充或澄清的内容。
这感觉真的很奇怪,因为您通常会定义实心区域,而不是玩家可以在其中行走的区域。毕竟你会希望你的玩家跳起来,而不是让他们粘在地上。
剩下的就很简单了:
- 遍历所有实体对象并确定播放器和实体矩形是否重叠。
- 如果是,请确定哪个距离更小(x 或 y)。这使您可以确定移动玩家的轴。
- 确定玩家离开实体区域的哪个方向更快,即向哪个方向推动玩家。
- 将播放器推向计算的方向并重复检查。
根据您的地图复杂性,这可能会变得相当复杂,因此您很可能需要一些 sorting/spatialisation 来减少比较次数(例如,跳过检查 impossible/far 离开形状)。