24

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

我想我的问题是,给定一个仅由瓷砖组成的关卡,他们如何检测像马里奥和洛克曼这样的处理能力很小的游戏中与墙壁和地板的碰撞?

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

我已经编写了一些基本上是“先验”的碰撞代码,因为它会搜索您将朝某个方向撞到的第一块瓷砖。我只是想知道是否有更好的方法。(也许只是使用事后碰撞检测)

例如,检查瓷砖碰撞是否向下移动的代码(我检查垂直然后水平移动):

  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

4 回答 4

18

对于你所说的 NES 时代的游戏类型,一切都是 2D 的。仅此一项就简化了许多事情。

那个时代的一些机器(特别是带有硬件精灵的机器,比如 Commodore 64)有硬件碰撞检测。大多数不依赖硬件碰撞检测的游戏要么使用边界框,要么使用命中掩码(精灵的 1 位位图)。

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

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

单向平台的事情在事后并不难处理,因为您知道精灵的速度矢量,因此您可以使用它来确定是否应该记录碰撞。

于 2009-07-15T06:05:15.307 回答
14

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

I may not have been googling right because I haven't stumbled upon this article before.

于 2009-07-17T00:46:13.340 回答
13

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

于 2009-07-15T06:09:06.063 回答
1

In older games collision detection was often less than perfect, trading accuracy for performance.

For example, in Super Mario Bros. collision with enemies is only checked every other frame. Collision with the end-of-level flag pole is done only once every 27 frames. There is also a limit on the maximum number of objects checked for collisions, which famously allows you to pass through some of Browser's attacks at the end of the game without dying.

Another example is the PC Engine port of Gradius. Rather than using more expensive bounding box hit detection, it uses a tile system. Each object is reduced to a tile number, consisting of the X and Y position rounded to a multiple of 8 and concatenated into a single number. If two objects occupy the same 8x8 tile they are deemed to have collided. It's less accurate but tends to favour the player, so presents an acceptable and fun compromise.

于 2019-08-29T10:16:00.693 回答