我有一个2D平台程序,当前可以处理100 x 100的块,块坐标存储为long,因此这是地图的唯一限制(maxlong * maxlong)。所有实体位置等都与块相关,因此没有限制。
我遇到的问题是如何在没有成千上万个文件的情况下存储和访问这些块。有什么想法可以实现快速低成本的高清存档格式,而无需一次打开所有内容?
long
是64位的C#(因此maxlong为Int64.MaxValue
)。
我有一个2D平台程序,当前可以处理100 x 100的块,块坐标存储为long,因此这是地图的唯一限制(maxlong * maxlong)。所有实体位置等都与块相关,因此没有限制。
我遇到的问题是如何在没有成千上万个文件的情况下存储和访问这些块。有什么想法可以实现快速低成本的高清存档格式,而无需一次打开所有内容?
long
是64位的C#(因此maxlong为Int64.MaxValue
)。
Answers:
为您的游戏创建自定义地图格式。它比您想象的要容易。只需使用BinaryWriter类。首先将标题写成几个int或uint。标头中包含的信息:
而且(这是性能关键部分
使用上述方法,您可以(并且应该)创建文件内容的索引,其中包含某种描述(用户为区域/块指定的名称,或者仅是坐标),并将文件中的位置作为第二个值。
然后,当您要加载特定的块时,只需在索引内部进行搜索。找到位置后,只需设置fileStream.Position = PositionOfChunkFromIndex即可加载它。
这与文件格式的设计有关,其中标题最有效地描述了文件的内容。
只需使用组成的自定义扩展名保存文件即可。
奖励:将BZip2压缩添加到文件的特定区域/整个内容(而不是标头!),因此您可以从文件中解压缩特定的块,从而占用很小的内存。
我遇到了类似的问题,并决定创建自己的结构来处理数据。它松散地基于四叉树,但是在所有方向上都具有无限的(至少与Int一样大)可扩展性。它旨在处理从中心点扩展的基于网格的数据,就像现在的Minecraft一样。它在内存中节省空间,而且速度非常快。
您可以为每个节点指定最小大小(大小为7,即128x128),一旦任何节点填充了指定百分比的子节点,它就会自动将其自身展平为二维数组。这意味着人口非常稠密的部分(例如,完全被勘探的大陆)将具有阵列的性能(非常快),但是人口稀疏的部分(例如,有人在上而下徘徊但未探索内陆的海岸线)将具有性能。具有良好的性能和较低的内存使用率。
我的代码可以在这里找到。该代码是完整的,经过测试的(单元测试和负载测试),并且经过了优化。但是,内部工作方式还没有得到很好的记录,但是所有公共方法都可以使用。如果有人决定尝试,请随时向我提出问题或评论。
我还没有用它来将数据存储到文件中,但这是一个有趣的问题,接下来我可能会解决。
您可以改用数据库-PostgreSQL具有一些特殊的索引功能,这些索引功能针对通过X和Y坐标定位的此类数据进行了优化。您还可以指定返回的数据在一定半径内,而不是在正方形或长方形区域内。
PostgreSQL(免费和开放原始码)
http://www.postgresql.org/
还有其他数据库,对于客户端,您可能会发现某些类型更适合此类型,因为它们可以独立运行(由您的游戏客户端应用程序启动),也可以作为代码库的一部分包含在内您可以“随便使用”。好处是您不必设计索引方案,因为大多数SQL数据库引擎已经很好地做到了这一点。
数据库方法的一个优势是您可以使块变小(或完全摆脱块并直接使用图块,但是根据设计的不同,至少使用许多图块的小块/组可能更有效),然后使用SQL查询带来比可见区域更大的区域。通过预加载以重叠附近的不可见区域,可以在玩家移动角色之前准备好磁贴,从而带来更好(希望更平滑)的游戏体验。
我注意到有些游戏在第一次获取后在本地硬盘上保留了地图数据的“缓存”(这无疑是减少网络I / O),例如Ashen Empires:
灰烬帝国(免费游戏,精美的2D实现)
http://www.ashenempires.com/
跟踪每个块/小块的“最新更新”时间戳也将有所帮助,因为对于可获得本地存储数据的地方,SQL查询可能包括附加的“ WHERE timestamp_column> $ local_timestamp”子句,以便仅获取更新的块/小块下载(这样节省带宽的两个好处是降低了连接成本,并减少了播放器的延迟,当您的游戏流行时,延迟将变得更加明显)。
屏幕截图来自《灰烬帝国》(几个角色在当地一家银行,从地板上那些骨头的外观看来,好像有几个骷髅怪兽一定已经流连了,很可能被当地城镇的守卫杀了):