老式游戏如何与墙壁,地板和天花板进行碰撞检测?

时间:2009-07-15 05:14:23

标签: collision-detection

我一直在阅读有关stackoverflow和其他网站上的游戏中的碰撞检测。他们中的很多人都在谈论BSP,限制边界,整合等等。然而,在NES上,他们设法在游戏中进行地板和墙壁碰撞检测,我发现很难相信他们做了很多计算来检测墙壁碰撞。

我想我的问题是,考虑到仅由瓷砖组成的水平,他们如何检测像Mario和Megaman这样几乎没有处理能力的游戏中与墙壁和地板的碰撞?

  • 他们是否遵循运动路径并确定最近的连接瓷砖? (有点搜索)(先验)
  • 他们是否确定了与地板的碰撞,然后找出调整角色的最佳方法? (后验)这对于可变的时间步长是有风险的,如果你足够快,你可以跳过一个瓦片。虽然我认为NES游戏的时间步长与电视的刷新率同步。
  • 当你在地上时,重力是否会影响你的角色?或者,当你决定在瓷砖上行走时,你会“关掉它”吗?当你走出悬崖边缘时呢?你需要某种方法来确定你下面的瓷砖。
  • 如果你与瓷砖相撞,你会找到该瓷砖的边缘并将你的角色移到它的侧面(取决于行进方向)吗?
  • 像在超级城市和马里奥那样的倾斜瓷砖怎么样?
  • 你可以跳过底部并降落在顶部的“平台”怎么样?如果你正在做'posteriori',你将如何处理与这些瓷砖的碰撞?

我写了一些基本上是'先验'的碰撞代码,因为它搜索你将在某个方向击中的第一个图块。我只是想知道是否有更好的方法。 (可能只是使用事后碰撞检测)

例如,用于检查向下移动的瓦片碰撞的代码(我检查垂直然后水平移动):

  def tile_search_down(self, char, level):
        y_off = char.vert_speed
        assert y_off > 0

        # t_ are tile coordintes
        # must be int.. since we're adding to it.
        t_upper_edge_y = int( math.ceil((char.y+char.h) / self.tile_height ) ) #lowest edge
        while (t_upper_edge_y*self.tile_height) < (char.y+char.h+y_off): # lowest edge + offset

            t_upper_edge_x = int( math.floor(char.x/self.tile_width) )
            while (t_upper_edge_x*self.tile_width) < (char.x+char.w):

                t_x = t_upper_edge_x
                t_y = t_upper_edge_y 
                if self.is_tile_top_solid(t_x, t_y, plane):
                    char.y = t_y*self.tile_height - char.h
                    char.vert_speed = 0.0
                    char.on_ground = True
                    return

                t_upper_edge_x += 1
            t_upper_edge_y += 1

        char.y += y_off

4 个答案:

答案 0 :(得分:19)

对于你所谈论的NES时代游戏的类型,一切都是2D。仅这一点就简化了很多事情。

那个时代的某些机器(特别是具有硬件精灵的机器,如Commodore 64)具有硬件碰撞检测功能。大多数不依赖于硬件冲突检测的游戏都会使用边界框或命中掩码(精灵的1位位图)。

无论哪种方式,碰撞检测通常都是“后验”,除了像世界边缘这样的特殊情况。有些游戏确实存在错误,当你击中某些东西时移动得太快可能会导致你通过它。 (事实上​​,对80年代早期游戏的评论通常会评论碰撞检测的准确程度。)

对于平台游戏,您通常会在应用重力之前检查角色是否“接地”。

单向平台的事情在事后并不太难以处理,因为你知道精灵的速度向量,所以你可以用它来确定碰撞是否应该注册。

答案 1 :(得分:14)

这里有一篇文章是深入研究任天堂娱乐系统(NES)“平台游戏”的编程。

我可能没有正确搜索,因为我之前没有偶然发现过这篇文章。

答案 2 :(得分:13)

对于超级马里奥世界(SNES)这样的游戏,游戏以一种内存格式存储关卡,以便轻松获取Mario的X / Y位置,将其转​​换为平铺地址,然后立即检查其周围的平铺地址。由于水平始终是固定宽度(尽管您可以查看的区域各不相同),因此它使寻址更容易管理,因为它总是与马里奥位置的固定偏移,例如地址+ 1表示马里奥旁边的图块,地址+ 0x300表示他下面的图块等等。

答案 3 :(得分:1)

在较老的游戏中,碰撞检测通常不尽人意,以牺牲性能为代价。

例如,在《超级马里奥兄弟》中,仅每隔一帧检查一次与敌人的碰撞。每27帧仅与级别末尾标志杆进行一次碰撞。碰撞检查对象的最大数量也有限制,著名的是,您可以在游戏结束时通过浏览器的一些攻击而不会死。

另一个示例是Gradius的PC引擎端口。它不是使用更昂贵的边界框命中检测,而是使用了切片系统。每个对象都减少为一个图块编号,该图块编号由X和Y位置四舍五入为8的倍数,并串联成一个数字。如果两个对象占据相同的8x8瓦片,则视为它们已碰撞。它的准确性较差,但会偏向于播放器,因此是一种可以接受且有趣的折衷方案。