2009-05-21 87 views
166

在2D游戏中绘制等角拼图的正确方法是什么?绘图等距游戏世界

我已阅读过参考文献(如this one),这些参考文献建议以在地图的二维数组表示中对每列进行锯齿形的方式呈现切片。我想他们应该更多地以钻石的方式画出来,画在屏幕上的东西更接近于二维数组的外观,只是旋转一点而已。

两种方法都有优缺点吗?

回答

470

更新:更正了地图渲染算法,增加了更多的插图,改变了格式。

也许优势用于映射瓦片到屏幕的“之字形”技术,可以说是瓦片的xy坐标上的垂直和水平轴。

“图中的钻石”的方法:

通过绘制使用“菱形绘图”的轴测图,我相信是指只用嵌套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具有相当直接的逻辑,可以在所有瓷砖中始终如一地工作。

缺点:

一个缺点这种方法是在地图上的瓷砖xy坐标将在斜线增加,这可能使其更难以在屏幕上的可视化映射位置到表示为阵列的图谱:

Image of tile map

然而,存在将是一个缺陷,以实现上述示例代码 - 渲染顺序将导致瓦片应该是某些瓷砖背后是在前面的瓷砖之上得出:

Resulting image from incorrect rendering order

为了修正这个问题,内for -loop的订单必须扭转 - 从最高值开始并朝向较低的值渲染:

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) 
     ) 

通过上述修正,在地图的呈现应当纠正:​​

Resulting image from correct rendering order

“Z形”的方法:

优势:

也许“锯齿形”的方法的优点是呈现的映像可能会出现要多一些垂直紧凑比“钻石” 的方法:

Zig-zag approach to rendering seems compact

缺点:

从试图实现锯齿形技术的缺点可能是,编写渲染代码有点困难,因为它不能像嵌套的那样简单,只是嵌套for - 对数组中的每个元素进行循环:

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 
     ) 

而且,它可能是一个有点难以揣摩瓷砖的坐标由于渲染顺序的交错性质:

Coordinates on a zig-zag order rendering

注:包含的插图在这里的答案用的Java实现呈现的瓦片呈现代码的创建,具有以下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] ->一个盒子里面有一个高大的灰色物体。

上瓷砖宽度的注记和高地

变量tile_widthtile_height其在上面的代码示例中使用指代表区块中的图像中的地砖的宽度和高度:

Image showing the tile width and height

使用图像的尺寸将工作,只要图像尺寸和瓷砖尺寸的匹配。否则,瓦片贴图可以用瓦片之间的间隙来渲染。

+124

你甚至画了照片。这是努力。 – zaratustra 2009-05-25 17:58:21

+0

干杯coobird。我正在使用钻石方法来开发我正在开发的当前游戏,并且它正在努力工作。再次感谢。 – 2009-05-27 10:42:23

10

无论哪种方式完成工作。我认为通过曲折你的意思是这样的:(数字呈现的顺序)

.. .. 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的位置。最后,两种方法在达到一定效率所需的数学方面大致相等。

1

如果你有一些瓦片超过你的钻石的界限,我在深度顺序绘制推荐:

...1... 
..234.. 
.56789. 
..abc.. 
...d... 
0

Coobird的答案是正确的,完整的一个。然而,我将他的提示与另一个网站的提示结合起来,创建可在我的应用程序(iOS/Objective-C)中工作的代码,我想与任何来到这里寻找此类事物的人分享。请,如果你喜欢/提出这个答案,对原件做同样的事情;我所做的只是“站在巨人的肩膀上。”对于排序顺序,我的技术是修改过的画家算法:每个对象都有(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; 
} 
0

真正的问题是,当你需要画一些瓷砖/精灵相交/跨越两个或更多其他瓷砖。

经过2个月(硬)个人问题分析后,我终于找到并实施了一个“正确的渲染图”,用于我的新cocos2d-js游戏。 解决方案包括为每个贴图(易感)映射哪些贴图为“前,后,上,后”。 一旦你这样做,你可以按照“递归逻辑”来绘制它们。