我一直在阅读有关stackoverflow和其他网站上的游戏中的碰撞检测。他们中的很多人都在谈论BSP,限制边界,整合等等。然而,在NES上,他们设法在游戏中进行地板和墙壁碰撞检测,我发现很难相信他们做了很多计算来检测墙壁碰撞。
我想我的问题是,考虑到仅由瓷砖组成的水平,他们如何检测像Mario和Megaman这样几乎没有处理能力的游戏中与墙壁和地板的碰撞?
我写了一些基本上是'先验'的碰撞代码,因为它搜索你将在某个方向击中的第一个图块。我只是想知道是否有更好的方法。 (可能只是使用事后碰撞检测)
例如,用于检查向下移动的瓦片碰撞的代码(我检查垂直然后水平移动):
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
答案 0 :(得分:19)
对于你所谈论的NES时代游戏的类型,一切都是2D。仅这一点就简化了很多事情。
那个时代的某些机器(特别是具有硬件精灵的机器,如Commodore 64)具有硬件碰撞检测功能。大多数不依赖于硬件冲突检测的游戏都会使用边界框或命中掩码(精灵的1位位图)。
无论哪种方式,碰撞检测通常都是“后验”,除了像世界边缘这样的特殊情况。有些游戏确实存在错误,当你击中某些东西时移动得太快可能会导致你通过它。 (事实上,对80年代早期游戏的评论通常会评论碰撞检测的准确程度。)
对于平台游戏,您通常会在应用重力之前检查角色是否“接地”。
单向平台的事情在事后并不太难以处理,因为你知道精灵的速度向量,所以你可以用它来确定碰撞是否应该注册。
答案 1 :(得分:14)
答案 2 :(得分:13)
对于超级马里奥世界(SNES)这样的游戏,游戏以一种内存格式存储关卡,以便轻松获取Mario的X / Y位置,将其转换为平铺地址,然后立即检查其周围的平铺地址。由于水平始终是固定宽度(尽管您可以查看的区域各不相同),因此它使寻址更容易管理,因为它总是与马里奥位置的固定偏移,例如地址+ 1表示马里奥旁边的图块,地址+ 0x300表示他下面的图块等等。
答案 3 :(得分:1)
在较老的游戏中,碰撞检测通常不尽人意,以牺牲性能为代价。
例如,在《超级马里奥兄弟》中,仅每隔一帧检查一次与敌人的碰撞。每27帧仅与级别末尾标志杆进行一次碰撞。碰撞检查对象的最大数量也有限制,著名的是,您可以在游戏结束时通过浏览器的一些攻击而不会死。
另一个示例是Gradius的PC引擎端口。它不是使用更昂贵的边界框命中检测,而是使用了切片系统。每个对象都减少为一个图块编号,该图块编号由X和Y位置四舍五入为8的倍数,并串联成一个数字。如果两个对象占据相同的8x8瓦片,则视为它们已碰撞。它的准确性较差,但会偏向于播放器,因此是一种可以接受且有趣的折衷方案。