当前位置: 首页 > 知识库问答 >
问题:

如何在基于 2D 图块的游戏中检测和解决碰撞问题?

楚宇
2023-03-14

我正在尝试用SFML 2.1为我的2D超级马里奥兄弟克隆包碰撞。我尝试了很多不同的解决方案和想法,但我无法让任何东西正常工作。
我有一个播放器,它目前在自己的更新()中检查碰撞(如下所示)

当前:
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()函数有三个参数:
-level:是map-camera:返回从地图中显示的分片,在屏幕上-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;
}

和碰撞响应功能

void Player::CollisionResponse(void)
{

}

如果我错过了任何有用的信息,请在下面发表评论。

地图由不同的方块组成,这些方块由坐标保存,而不是它们实际所在的位置,而是它们在数组中的位置,因此示例地图看起来像这样:< br> 0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
碰撞函数然后检查与玩家周围的这些方块相关的碰撞。

我尝试过的:
有很多不同的碰撞方法来同时解决x和y碰撞。
碰撞响应将玩家移回最后一个位置。
碰撞响应将玩家移回相交矩形的大小(这在y轴上有效,但在x轴上无效)。当我的头感觉不像融化的奶酪时,我会写更多。

共有2个答案

陆昕
2023-03-14

对于我的游戏(在java和Libgdx中),我也使用了AABB冲突检测。有2种不同的方法可以检测和处理冲突:

    < li >移动前计算新位置。如果有物体不要动。要进行滑行运动,请检查x方向的碰撞,如果有碰撞,请不要移动。如果没有碰撞,同样检查y轴。如果有碰撞,不要在y轴上移动。仍然没有碰撞检查x轴和y轴上的碰撞(你真正的新位置)。如果发生碰撞,停止两个动作。 < li >移动到新位置。如果你在那里碰撞,在x方向重置x移动,如果你在y方向碰撞,重置y移动,在两个方向碰撞,都重置。

当您使用基于图块的地图时,您不需要使用“交集”测试。相反,您可以存储角色的4个角点,四舍五入到他所在的图块(如果每个图块都有一个单位大,并且角色的脚在P(0.5; 0.5)上,您需要检查图块(0; 0))。
玩家的位置是他的左下角(通常),所以他的其他3个点是P2(player.position.x.player.width;player.position.y)P2(player.position.x.player.width;player.position.yplayer.height)P3(player.position.x;player.position.yplayer.height),总是向下舍入到Tile的位置。

希望有帮助。

邵宜年
2023-03-14

将播放器移回到最后一个已知的正确位置会导致您正在经历的行为;玩家将与他要碰撞的物体保持一段距离。举个例子:如果你的角色以300像素/秒的速度移动,而他们离墙有5个像素,下一次碰撞发生在1/60秒内。如果您的帧速率为60FPS,将在下一帧中检测到碰撞,并且角色将移动到距离碰撞发生前他所在的墙壁5个像素的位置。肯定不受欢迎。

只要正确计算数量,您所使用的方法应该有效(按相交矩形的大小将播放器向后移动)。分离轴定理对此很有用(在那篇文章中,具体参见第7节“寻找MTV”)。

你可以尝试另一种方法,不涉及计算:在碰撞时,以小的时间步长(甚至像素一像素一像素)向后移动玩家,直到他停止与墙碰撞。然后,你就会知道一个离墙更近的地方,在那里可以安全地安置他。效率较低,但易于实施。

还有一种方法是连续冲突检测。它本质上有点复杂。你应该能够通过简单地四处搜索“连续冲突”来找到一些信息,但基本思想是:

  1. 弄清楚下一次碰撞将在何时何地发生。
  2. 如果下一次碰撞将在当前时间步内发生,则将对象移动到发生碰撞的位置。
  3. 如果下一次碰撞没有在当前时间步内发生,只需将对象向前移动其当前移动速度。
 类似资料:
  • 我正在尝试制作我的第一个Pacman游戏,但我遇到了一堵我自己似乎无法打破的墙:( 这是关于如何在我的游戏中检测碰撞,所以步行者不能穿过障碍物/墙壁。我已经使它不能去屏幕外与此代码: ,但如果我在屏幕中间的电路板上有一个矩形,我不知道如何编程,这样它就会在墙前停止。 我需要阻止我的pacman移动到竞技场内的墙上,如你所见(左上方的矩形) 我的Board类代码: 希望有人能告诉我该怎么做...似乎

  • 我已经和LWJGL一起开发这个游戏几个星期了。自从我增加了跳跃的能力后,向上的碰撞给我带来了很多问题。 这个游戏是一个基于2D瓷砖的侧翻游戏。总的来说,除了玩家跳跃时,碰撞几乎是完美的。起初我想“哦,也许我只需要改变跳跃机制”,但后来我意识到只有当玩家通过某个x坐标时才会发生这种情况。 现在,对于实际问题本身:如果玩家在传递某个x坐标时跳转,他们将通过平铺,并测试顶部碰撞返回false。 这是整个

  • 我计划一个独立游戏项目已经有一段时间了。我会为你总结一下,这样我就可以直接回答这个问题。 它是通过Visual Studio完全使用最新版本的XNA完成的。希望将其放在360和PC上,但目前我只是在真正寻找面向PC的解决方案。 这是一个2D侧向滚动射击游戏(想想大都会风格,甚至是Terraria)。它最终将包括一个游戏中的地图编辑器,地图是基于图块的(16x16)。会有向上和向下滚动。我希望在开发

  • 问题内容: 我正在尝试制作一个Python游戏,其中红龟追逐蓝龟。当红色乌龟抓到蓝色乌龟时,我希望它在屏幕上说“碰撞”,但它不起作用。当它碰撞时,什么也没有发生,并且给我一个错误“ Turtle”对象不可调用”。 问题答案: 与实际编程相比,这段代码似乎更让人想不到: 乌龟没有方法。您不能使用此语句简单地将方法添加到现有类。没有和功能。每次运动后,如果需要,该碰撞测试将只执行一次。让我们尝试挽救我

  • 我正在做一个2d平板游戏。到目前为止,我已经做了一些事情。我正在使用libgdx的矩形进行基本的碰撞检测,所以考虑到我现在只有草块,我用Java制作了一个单块世界(文件读取器还没有准备好),问题是我的检测只在第一次工作,换句话说,如果我产生碰撞到一个块,它会检测到碰撞并这样做。虽然如果我在没有碰撞的情况下,让我的球员在方块顶部出现,球员将永远摔倒。 这是代码=

  • 我想创建一个二维游戏与瓷砖为基础的地图。我的主要问题是碰撞。如果有一棵树挡住了我的路,我怎么才能让我的精灵不穿过这棵树呢?