从单个图像生成游戏地图的算法
我正在设计要在浏览器中玩的游戏。
游戏是一个太空主题,我需要生成" Galaxy"地图。
地图的基本概念如下:
游戏地图http://www.oglehq.com/map.png
该地图是一个网格,每个网格扇区都可以包含一个行星/系统,并且每个都有与多个相邻网格的链接。
为了生成地图,我认为我将有一组代表网格元素的图像。因此,在上述示例的情况下,每个正方形都是单独的图形。
要创建新地图,我会将图像"编织"在一起。
地图元素图像上已经有行星及其链接,因此,我需要将地图缝合在一起,以使每个图像都与相应的对应位置对齐=>,因此底角处的图像必须具有正确连接起来的左侧和对角线左侧。
我们将如何创建代码来知道将图像放置在哪里?
有没有比使用图像更好的方法?
目前,不应该考虑性能和/或者负载(如果我需要生成已预先配置而不是实时进行映射的映射,我不在乎)。
如果有所作为,我将使用HTML,CSS和JavaScript,并由Ruby on Rails应用程序支持。
解决方案
我建议使用图形库绘制地图。如果这样做,我们将不会遇到上述问题,并且最终会得到更简洁的代码。某些选项包括SVG,画布和Flash / Flex。
我个人只是在游戏中渲染链接,而单元格图形仅提供背景。这为我们提供了更大的灵活性,使我们可以更轻松地增加单元之间的链接方式,并且通常具有更大的可扩展性。
否则,我们将需要考虑单元链接的所有可能方式,即使考虑了旋转和镜像对称性,这也很多。
有两个非常不错的基于浏览器的矢量/ JavaScript可操作图形包,它们实际上是通用的:SVG和VML。它们通常产生具有低带宽的高质量基于矢量的图像。
Firefox,Opera,Safari和chrome支持SVG技术上仅支持部分规范,但出于实际目的,我们应该能够执行所需的操作。 w3schools对于学习/使用svg有很好的参考。
VML是Microsoft对SVG的解决方案,并且IE本身支持(惊奇),尽管SVG不受支持。 MSDN是vml的最佳参考。
尽管还有更多工作要做,但是我们可以为这两种技术编写两个相似/有点集成的代码库。真正的好处是,用户无需安装任何东西就可以在线玩游戏,它可以正常工作,占所有用户的99.9%。
顺便说一句,我们说的是我们要的是算法,我正在提供技术(如果这是SVG / VML的正确术语)。如果我们可以弄清输入/输出规范以及可能是哪一部分提出了挑战(例如哪个天真的实现将不起作用以及为什么),那么就可以弄清楚问题并提供更集中的答案。
附录除著名的IE之外,canvas标签正得到越来越广泛的支持。这可能是将图形元素嵌入html的更干净的方法。
有用的画布内容:Opera的画布教程| Mozilla的画布教程| canvas-in-IE的部分实现
哦,我们也可以只包含少量具有透明性的tile png文件,并使用css定位的div将它们重叠以形成类似于示例的图片,如果足够的话。
上次我检查时,IE的较旧版本对图像文件的透明度没有很好的支持。任何人都可以对其进行编辑以提供有关透明度支持的更好信息吗?
只要链接的最大长度不会太长,那么每个单元格就不会有太多不同的可能图像。我们需要对图像单元的种类进行排序。例如,一个整数,其中每个位指示存在或者不存在图像分量。
Bit 0 : Has planet Bit 1 : Has line from planet going north Bit 2 : Has line from planet going northwest ... Bit 8 : Has line from planet going northeast
好的,现在创建512张图像。许多语言都有可让我们编辑图像并将其写入磁盘的库。如果我们喜欢Ruby,请尝试以下操作:http://raa.ruby-lang.org/project/ruby-gd
我不知道我们打算如何存储描述行星和链接图的数据结构。邻接矩阵可以使生成地图变得容易,尽管它并不是到目前为止的最小表示。然后,很容易将html吐出来(对于2x2网格):
<table border="0" cellspace="0" cellpadding="0"> <tr> <td><img src="cell_X.gif"></td> <td><img src="cell_X.gif"></td> </tr> <tr> <td><img src="cell_X.gif"></td> <td><img src="cell_X.gif"></td> </tr> </table>
当然,用与描述单元格外观的位组合相对应的适当数字替换每个X。如果使用邻接矩阵,则将各个位放在一起非常简单-只需查看"当前"单元周围的单元即可。
唔。如果每个框只能链接到它的8个邻居,则我们只有2 ^ 8 = 256个图块类型。如果我们限制来自任何一个图块的可能链接的数量,则更少。
我们可以使用8个字符的文件名对图像中存在的链接进行编码:
11000010.jpeg
或者保存一些字节并将其转换为十进制或者十六进制
196.jpg
然后是代码。我们可以选择多种方式来内部表示地图。一种方法是为每个行星都有一个对象。行星对象知道其自身在网格中的位置以及其链接的行星的位置。因此,它具有足够的信息来选择适当的文件。
或者拥有2D阵列。要确定要显示每个阵列项目的图像,请查看8个相邻的阵列项目。如果这样做,可以通过使数组在两个轴上都变大两个,并在边缘周围留空的"边界"来避免对边界进行编码。这样省去了检查相邻数组项是否在数组之外的麻烦。
有两种表示地图的方法。
一种方法是将其表示为正方形网格,其中每个正方形都可以包含或者不包含行星/系统。然后,我们可以指定,如果在八个方向(NW,N,NE,W,E,SW,S,SE)中的任何一个方格相距一个邻居,则该邻居存在连接。但是请注意,在示例图中,中心系统未连接至系统的北/东,因此这可能不是我们想要的表示形式。但是它可以用来建立另一个表示
第二种方法是将每个正方形表示为具有八个位,定义是否沿着相同的八个方向中的每个方向与邻居建立连接。假设如果只有一个连接,则正方形内部有一个系统,否则,如果没有连接,则为空白。
因此,在示例3x3网格中,数据为:
Tile Connections nw n ne w e sw s se nw 0 0 0 0 0 0 0 0 n 0 0 0 0 1 0 1 0 ne 0 0 0 1 0 0 0 0 w 0 0 0 0 0 0 0 0 center 0 1 0 0 0 0 1 1 e 0 0 0 0 0 0 0 0 se 0 0 0 0 0 0 0 0 s 0 1 0 0 1 0 0 0 sw 1 0 0 1 0 0 0 0
我们可以将这些连接表示为八个布尔值的数组,或者更紧凑地表示为八位整数。
然后可以很容易地使用八个布尔值(或者八个位整数)来形成要为该网格正方形加载的位图的文件名。例如,使用此方案的中心磁贴可以称为" Bitmap01000011.png"(仅使用布尔值),也可以称为" Bitmap43.png"(使用八位整数的十六进制值表示较短的文件名,该二进制模式)。
由于我们有256种可能的组合,因此将需要256个位图。
我们还可以将数据减少到每个图块四个布尔值/位,因为例如"北"连接意味着向北的图块具有"南"连接,但是这会使选择位图更加困难,但是我们可以工作如果你想要的话。
或者,我们可以在每个正方形中将零(空)和九(完全连接+系统圆)位图之间分层。我们只需要使用透明的.png即可将它们组合在一起。缺点是浏览器绘制每个正方形(特别是完全连接的正方形)的速度可能很慢。这样做的好处是,我们创建的数据更少,要从网站加载的数据更少。
我们可以将地图本身表示为表格,并根据需要将位图作为图像链接添加到每个单元格。
要映射的伪代码为:
draw_map(connection_map): For each grid_square in connection_map connection_data = connection_map[grid_square] filenames = bitmap_filenames_from(connection_data) insert_image_references_into_table(grid_square,filenames) # For each square having one of 256 bitmaps: bitmap_filenames_from(connection_data): filename="Bitmap" for each bit in connection_data: filename += bit ? "1" : 0 return [filename,] # For each square having zero through nine bitmaps: bitmap_filename_from(connection_data): # Special case - square is empty if 1 not in connection_data: return [] filenames=[] for i in 0..7: if connection_data[i]: filenames.append("Bitmap"+i) filenames.append("BitmapSystem"); return filenames