在2D侧卷轴中表示水平的最佳方法是什么?

时间:2009-07-16 13:35:02

标签: data-structures

我没有游戏编程知识,并且不知道如何存储2D游戏中的级别,如Mario和Sonic(等)。

'存储',如何存储数据(地面,平台,按钮,升降机等)。

即。显然,马里奥的水平不是某种从左到右移动的非常宽的图像。

12 个答案:

答案 0 :(得分:23)

由于ROM黑客场景,超级马里奥世界的文件格式(我想象当时大多数其他流行的游戏)是众所周知的,基本上完全理解。还有一些文件将以痛苦的细节描述这一切。不幸的是,因为这意味着要访问不合法的网站,我无法为您提供任何工作链接,但如果您谷歌搜索.MWL文件扩展名和一个名为Lunar Magic的编辑应用程序,它可能会指向正确的方向

但基本原则相当简单。首先你需要你的图形,所以你可以制作一个带有瓷砖的单个图像,用于定义尺寸的景观 - 较小的是更高的内存效率,更大的图片可以提供更多的细节,所以假设我们的图像是32 X 32像素。所以你最终得到这样的东西(代表不同瓷砖的字符):

    ! " £ $ %
    ^ & * ( )

你可以为每个级别的“风格”制作一个标题集,这样火世界,冰世界,洞穴世界等等。这可以节省您在不打算使用的瓷砖中的加载。

接下来你需要一个关卡文件,它首先包含你要加载的图块集和代表每个图形的数​​字,如下所示:

   fireworld.img
   2 2 2 2 2 2 2 2
   3 3 2 2 2 2 3 3
   3 3 3 3 3 3 3 3

与上面的tileset合并(取决于你对瓷砖的编号)

   " " " " " " " "
   £ £ " " " " £ £
   £ £ £ £ £ £ £ £

显然,你需要在此基础上层叠更多信息:哪些图块是实心的,哪些是致命的等等。这可以在图像级别完成(3总是可靠的)或者,为了更灵活但更大的文件,在地图级别。位标志会做,第一个数字是实数,第二个是致命的:

   fireworld.img
   200 200 200 200 200 200 200 200
   310 310 200 200 200 200 310 310
   310 310 310 310 310 310 310 310

除此之外,您还需要使用起点和终点(几个坐标)和敌人(他们使用的图形,他们使用的AI例程,他们从哪里开始)为级别文件添加后缀。

完成所有这些后,您可以查看压缩。有很多方法可以节省空间,显然它现在和16和8位时代一样重要,但即便如此,我们上面的格式也非常浪费。

一如既往,这些只是基本原则。您的结果可能会有所不同......

答案 1 :(得分:9)

不是很相关,但是你知道马里奥的云是和灌木一样的精灵,只是调色板移了吗?那时记忆确实很贵!

实际上不可能知道它们是如何存储的,但可能采用网格对象方法,在这里只需要一些内存节省技巧。实施必然会因游戏而大不相同,而且完全取决于开发人员 - 实际上没有任何标准方法。


更新:我认为将整个级别表示为(非常宽)网格将是最好的方法。在每个网格框中,你都会放置一个带有属性的精灵(spawn,ground,wall,chest,baddie,spikes等)。然后引擎将精灵绘制在正确的位置,但也具有与之关联的属性。如果您连续放置10个楼层,则必须对引擎进行编码以识别连接,并在哪里放置正确的结束件等。显然,任何不是网格的东西都是天空!

你如何对这些信息进行编码在很大程度上取决于你,因为内存不再是一个大问题,效率并不重要。只是一个目标代码列表,x,y可能会这样做。

答案 2 :(得分:5)

所有那些声称马里奥游戏以某种2D阵列结构存储他们关卡的人方式关闭:除了前两个GB马里奥游戏(可能是第三个),超级马里奥游戏基于对象

每个级别分为几个屏幕,每个级别的总大小相同。每个屏幕都包含一个可变长度的对象列表,每个对象都有一个类型,位置和(取决于类型)其他属性。在关卡的开始处,解释第一个或两个屏幕并将其转换为用于绘制屏幕并进行交互的常规2D阵列结构。当水平滚动过去时,这个地图会在运行中重建,丢弃超出范围的部分。

这就是为什么敌人可以重新生成,如果你回溯,最明显的是在SMW的一个森林层面,你可以使用斗篷从一条毛虫到另一条毛虫来回跳三个屏幕。顺便说一句,因为你从不触摸地板,给了很多生命。

该系统的细节在游戏之间有所不同。

除此之外,马丁哈里斯是完全正确的。

答案 3 :(得分:3)

对于大多数2D游戏,我认为水平存储就像瓷砖的位图。

它的工作原理如下:

  • 首先,你有很多固定的瓷砖,比方说16x16像素。这些瓷砖就像一块拼图游戏。您可以通过各种方式将它们组合在一起以形成关卡。例如,这里是一个tileset,虽然这看起来是某种自上而下的游戏,原则是相同的:http://silveiraneto.net/wp-content/uploads/2009/04/free_tileset_version_9.png

  • 一旦您知道了一组瓷砖,就会为每个瓷砖提供一个数字。如果您有少于256个图块,则可以将此数字存储在一个字节中;如果您有更多图块,则可以将其存储在单词或双字节中。此时,为这些数字添加一些语义也很有用。比方说,例如,瓷砖1-100代表“障碍”,你无法通过。这将在以后派上用场。

  • 现在是时候定义地图了。我们可以通过将拼图块放在一个大网格上来做到这一点!我们定义地图的最大大小。对于侧面滚轮,让我们说地图是1000个瓷砖宽,50个瓷砖高。你可以选择你想要的任何东西。您现在可以将内存(以及磁盘上)的地图表示为width * height个数字的bix矩阵。网格中的每个“单元格”都包含一个数字,表示应该在该位置绘制的图块。

现在很容易绘制地图:

for (y = 0; y < height; y++) {
   for (x = 0; x < width; x++) {
      draw_tile(x * 16, y * 16, map[y][x]);
   }
} 

和其他东西一样。请记住,我们将瓷砖1-100定义为障碍物?我们可以使用地图来检测玩家是否有可能移动到某个位置:

bool moveable(int x, int y) {
   return map[y / 16][x / 16] > 100;
}

这是平铺地图的最基本解释。通过扩展这个简单的概念,你可以做更多花哨的事情。以下是一些想法:

  • 多个图层,用于表示背景上的对象
  • parallax scrolling用于炫酷的背景效果

我很确定大多数2D游戏都使用了平铺游戏地图技术的一些变体。

答案 4 :(得分:1)

作为stored data structures

问得太广泛的问题,得到过于宽泛的答案。 :)

答案 5 :(得分:1)

我使用Lua脚本为Physle games创建了级别。它们的加载速度不如二进制格式,但它使调试和与其他工具集成更容易。装载水平通常也不是速度真正得到任何回报的地方。

答案 6 :(得分:0)

这太宽泛了。

游戏级别的存储空间因引擎而异。

答案 7 :(得分:0)

通常采用游戏解析的某种自定义文件格式。

XML是纯文本文件的可能性。但是,尝试从您的某个游戏中打开一个关卡文件,您很可能会看到乱码文本。您需要找到有关游戏使用的特殊文件格式的文档。

查看游戏的改装网站,你会发现更多。

答案 8 :(得分:0)

对于你所提到的(可能是旧的和2D)Mario和Sonic游戏的情况,可能是一些神秘的压缩和优化格式,以解决他们制作的游戏机的存储和处理限制。

答案 9 :(得分:0)

我不知道像马里奥这样的东西会存储它的水平,而我自己也从未这样做过,但这就是我接近的方式。

我创建了一个可以基于XML的简单文件格式。在那里我可能会定义播放区域大小和其他元数据,如名称和时间限制。然后,我将有一个对象列表,这些对象将出现在播放区域中,它们的x / y坐标和对象的类型,例如,玩家开始位置,等级退出等等....)我甚至可能有一个部分存储游戏中发生事件的时间。

然后游戏引擎必须解释该文件并在它们进入视图时在屏幕上呈现相应的项目。我想像存储数据是一件容易的事,你用它做的事情会很棘手。

希望有所帮助。

答案 10 :(得分:0)

来自我们尊敬的领导者的一篇有点相关的博客文章是Why are the Microsoft Office file formats so complicated? (And some workarounds)

答案 11 :(得分:0)

我经常看到使用的数组,其值以地形/填充类型为主。这是来自Tony Pa的基于闪存平铺游戏创建的一个很好的教程:

Game Map storage

然后关卡创建者扫描并创建文件。在Kongregate上查看允许用户级创建的游戏;当你链接到游戏时,它们存储了作为POST变量提交的整个级别。这是一个透明的过程,通常不会编码,因此很容易学习(并且有许多游戏类型可以做到这一点)