绘制等距的游戏世界
什么是在2D游戏中绘制等angular拼图的正确方法?
我已经阅读过参考文献(比如这个 ),这些参考文献提出了这样一种方式,即在地图的二维数组表示中以锯齿形方式呈现这些图块。 我想他们应该更多地以钻石的方式画出来,画在屏幕上的东西更接近二维数组的外观,只是旋转了一下。
两种方法都有优点还是缺点?
更新:更正了地图渲染algorithm,增加了更多的插图,改变了格式。
或许,将拼图映射到屏幕上的“之字形”技术的优点可以说是拼块的x
和y
坐标在垂直和水平轴上。
“钻入钻石”方法:
通过使用“在钻石中绘制”绘制等轴测图,我相信这是指通过在二维数组上使用嵌套for
-loop来渲染地图,例如:
tile_map[][] = [[...],...] for (cellY = 0; cellY < tile_map.size; cellY++): for (cellX = 0; cellX < tile_map[cellY].size cellX++): draw( tile_map[cellX][cellY], screenX = (cellX * tile_width / 2) + (cellY * tile_width / 2) screenY = (cellY * tile_height / 2) - (cellX * tile_height / 2) )
优点:
这种方法的优点是它是一个简单的嵌套for
-loop,具有相当直接的逻辑,可以在所有的tile中一致地工作。
坏处:
这种方法的一个缺点就是地图上的图块的x
坐标和y
坐标在对angular线上会增加,这可能使得更难以将屏幕上的位置映射到以数组表示的地图:
但是,实现上述示例代码将会有一个缺陷 – 渲染顺序会导致应该在某些图块后面的图块被绘制在前面的图块顶部:
为了修正这个问题,内循环的顺序必须颠倒 – 从最高值开始,向低值渲染:
tile_map[][] = [[...],...] for (i = 0; i < tile_map.size; i++): for (j = tile_map[i].size; j >= 0; j--): // Changed loop condition here. draw( tile_map[i][j], x = (j * tile_width / 2) + (i * tile_width / 2) y = (i * tile_height / 2) - (j * tile_height / 2) )
通过上述修复,地图的渲染应该得到纠正:
“之字形”方法:
优点:
也许“之字形”方法的好处在于,渲染的地图可能看起来比“菱形”方法稍微垂直一些:
坏处:
从试图实现之字形技术的缺点可能是,编写渲染代码比较困难,因为它不能像嵌套在数组中的每个元素上一样简单:
tile_map[][] = [[...],...] for (i = 0; i < tile_map.size; i++): if i is odd: offset_x = tile_width / 2 else: offset_x = 0 for (j = 0; j < tile_map[i].size; j++): draw( tile_map[i][j], x = (j * tile_width) + offset_x, y = i * tile_height / 2 )
另外,由于渲染顺序的交错性质,试图找出拼贴的坐标可能有点困难:
注意:此答案中包含的插图是使用呈现的图块呈现代码的Java实现创build的,其中以下列int
数组作为映射:
tileMap = new int[][] { {0, 1, 2, 3}, {3, 2, 1, 0}, {0, 0, 1, 1}, {2, 2, 3, 3} };
平铺图像是:
-
tileImage[0] ->
一个盒子里面有一个盒子。 -
tileImage[1] ->
一个黑匣子。 -
tileImage[2] ->
一个白色框。 -
tileImage[3] ->
一个高灰色物体的盒子。
关于瓷砖宽度和高度的注意事项
上面的代码示例中使用的variablestile_width
和tile_height
指的是代表瓦片的图像中的地面瓦片的宽度和高度:
只要图像尺寸和瓦片尺寸相匹配,就可以使用图像的尺寸。 否则,瓦片贴图可以在瓦片之间以间隙呈现。
无论哪种方式完成工作。 我认为,通过曲折你的意思是这样的:(数字是渲染的顺序)
.. .. 01 .. .. .. 06 02 .. .. 11 07 03 .. 16 12 08 04 21 17 13 09 05 22 18 14 10 .. 23 19 15 .. .. 24 20 .. .. .. 25 .. ..
而通过钻石你的意思是:
.. .. .. .. .. 01 02 03 04 .. 05 06 07 .. 08 09 10 11 .. 12 13 14 .. 15 16 17 18 .. 19 20 21 .. 22 23 24 25 .. .. .. .. ..
第一种方法需要渲染更多的图块,以便全屏显示,但是您可以轻松地进行边界检查,并在屏幕外完全跳过任何图块。 这两种方法都需要进行一些数字处理,以找出瓦片01的位置。最后,两种方法在一定程度的效率所需的math方面大致相等。
如果您的某些瓷砖超出了您的钻石的范围,我build议您按照深度顺序绘制:
...1... ..234.. .56789. ..abc.. ...d...
Coobird的答案是正确的,完整的答案。 然而,我将他的提示与另一个网站的提示结合起来,创build了可以在我的应用程序(iOS / Objective-C)中使用的代码,我想与任何来这里寻找这种东西的人分享。 请,如果你喜欢/投票的这个答案,对原件做同样的事情; 我所做的只是“站在巨人的肩膀上”。
至于排列顺序,我的技术是一个修改过的画家algorithm:每个对象都有(a)底座高度(我称之为“高度”)和(b)X / Y为“底”或“足” (例如:头像的基地在他的脚下,树的基地在根,飞机的基地是中心图像等)然后,我从最低到最高级别,然后最低(屏幕上最高) Y,然后最低(最左边)到最高的基数-X。 这使得瓷砖按照人们所期望的方式呈现。
将屏幕(点)转换为平铺(单元格)并返回的代码:
typedef struct ASIntCell { // like CGPoint, but with int-s vice float-s int x; int y; } ASIntCell; // Cell-math helper here: // http://gamedevelopment.tutsplus.com/tutorials/creating-isometric-worlds-a-primer-for-game-developers--gamedev-6511 // Although we had to rotate the coordinates because... // X increases NE (not SE) // Y increases SE (not SW) + (ASIntCell) cellForPoint: (CGPoint) point { const float halfHeight = rfcRowHeight / 2.; ASIntCell cell; cell.x = ((point.x / rfcColWidth) - ((point.y - halfHeight) / rfcRowHeight)); cell.y = ((point.x / rfcColWidth) + ((point.y + halfHeight) / rfcRowHeight)); return cell; } // Cell-math helper here: // http://stackoverflow.com/questions/892811/drawing-isometric-game-worlds/893063 // X increases NE, // Y increases SE + (CGPoint) centerForCell: (ASIntCell) cell { CGPoint result; result.x = (cell.x * rfcColWidth / 2) + (cell.y * rfcColWidth / 2); result.y = (cell.y * rfcRowHeight / 2) - (cell.x * rfcRowHeight / 2); return result; }
真正的问题是,当你需要画一些瓦/精灵相交/跨越两个或更多的其他瓷砖。
经过2个月(硬)个人问题的分析,我终于find并实施了一个“正确的渲染图”为我的新的cocos2d – js游戏。 解决scheme包括映射,为每个瓷砖(易感),哪些精灵是“前,后,上,后”。 一旦这样做,你可以按照“recursion逻辑”来绘制它们。