绘制等距游戏世界
在 2D 游戏中绘制等角图块的正确方法是什么?
我已阅读参考文献(例如 这个)建议以锯齿形方式呈现图块,使地图的 2D 数组表示中的每一列呈锯齿状。 我想它们应该更多地以菱形方式绘制,其中绘制到屏幕上的内容与 2D 阵列的外观更密切相关,只是旋转了一点。
这两种方法都有优点或缺点吗?
What is the correct way to draw isometric tiles in a 2D game?
I've read references (such as this one) that suggest the tiles be rendered in a way that will zig-zag each column in the 2D array representation of the map. I imagine that they should be drawn more in a diamond fashion, where what gets drawn to the screen relates more closely to what the 2D array would look like, just rotated a little.
Are there advantages or disadvantages to either method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
更新:更正了地图渲染算法,添加了更多插图,更改了格式。
也许将图块映射到屏幕的“zig-zag”技术的优势可以说是图块的
x< /code> 和
y
坐标位于垂直轴和水平轴上。“绘制菱形”方法:
通过使用“绘制菱形”绘制等距地图,我相信这指的是仅使用嵌套的
for
来渲染地图 -循环二维数组,例如以下示例:优点:
该方法的优点是它是一个简单的嵌套
for
循环,具有相当直接的逻辑:在所有瓷砖上一致地工作。缺点:
该方法的一个缺点是地图上图块的
x
和y
坐标将以对角线形式增加,这可能会使将屏幕上的位置直观地映射到以数组表示的地图更加困难:然而,实现上述示例代码会遇到一个陷阱——渲染顺序会导致图块应该位于某些图块后面,以绘制在前面的图块之上:
为了修正此问题,必须颠倒内部
for
循环的顺序-- 从最高值开始,向较低值渲染:通过上述修复,应该更正地图的渲染:
“之字形”方法:
优点:
也许“zig-zag”方法的优点是渲染的地图可能看起来比“菱形”方法在垂直方向上更紧凑:
缺点:
从尝试实现 zig-zag 技术来看,缺点可能是编写渲染代码有点困难,因为它不能像嵌套 < 那样简单地编写code>for - 数组中每个元素的循环:
此外,由于渲染顺序的交错性质,尝试找出图块的坐标可能有点困难:
注意:此答案中包含的插图是使用所提供的图块渲染代码的 Java 实现创建的,并使用以下
int
数组作为地图:图块图像为:
tileImage[0] ->
一个盒子,里面有一个盒子。tileImage[1] ->
一个黑盒子。tileImage[2] ->
一个白框。tileImage[3] ->
一个盒子,里面有一个高大的灰色物体。关于图块宽度和高度的说明
上述代码示例中使用的变量
tile_width
和tile_height
指的是地面的宽度和高度代表图块的图像中的图块:只要图像尺寸和图块尺寸匹配,就可以使用图像的尺寸。 否则,瓦片地图可能会在瓦片之间呈现间隙。
Update: Corrected map rendering algorithm, added more illustrations, changed formating.
Perhaps the advantage for the "zig-zag" technique for mapping the tiles to the screen can be said that the tile's
x
andy
coordinates are on the vertical and horizontal axes."Drawing in a diamond" approach:
By drawing an isometric map using "drawing in a diamond", which I believe refers to just rendering the map by using a nested
for
-loop over the two-dimensional array, such as this example:Advantage:
The advantage to the approach is that it is a simple nested
for
-loop with fairly straight forward logic that works consistently throughout all tiles.Disadvantage:
One downside to that approach is that the
x
andy
coordinates of the tiles on the map will increase in diagonal lines, which might make it more difficult to visually map the location on the screen to the map represented as an array:However, there is going to be a pitfall to implementing the above example code -- the rendering order will cause tiles that are supposed to be behind certain tiles to be drawn on top of the tiles in front:
In order to amend this problem, the inner
for
-loop's order must be reversed -- starting from the highest value, and rendering toward the lower value:With the above fix, the rendering of the map should be corrected:
"Zig-zag" approach:
Advantage:
Perhaps the advantage of the "zig-zag" approach is that the rendered map may appear to be a little more vertically compact than the "diamond" approach:
Disadvantage:
From trying to implement the zig-zag technique, the disadvantage may be that it is a little bit harder to write the rendering code because it cannot be written as simple as a nested
for
-loop over each element in an array:Also, it may be a little bit difficult to try to figure out the coordinate of a tile due to the staggered nature of the rendering order:
Note: The illustrations included in this answer were created with a Java implementation of the tile rendering code presented, with the following
int
array as the map:The tile images are:
tileImage[0] ->
A box with a box inside.tileImage[1] ->
A black box.tileImage[2] ->
A white box.tileImage[3] ->
A box with a tall gray object in it.A Note on Tile Widths and Heights
The variables
tile_width
andtile_height
which are used in the above code examples refer to the width and height of the ground tile in the image representing the tile:Using the dimensions of the image will work, as long as the image dimensions and the tile dimensions match. Otherwise, the tile map could be rendered with gaps between the tiles.
无论哪种方式都能完成工作。 我假设锯齿形你的意思是这样的:(数字是渲染的顺序)
而菱形你的意思是:
第一种方法需要渲染更多的图块,以便绘制全屏,但你可以轻松地进行边界检查并跳过任何完全平铺在屏幕外。 两种方法都需要进行一些数字运算才能找出图块 01 的位置。最终,两种方法在一定效率水平所需的数学方面大致相同。
Either way gets the job done. I assume that by zigzag you mean something like this: (numbers are order of rendering)
And by diamond you mean:
The first method needs more tiles rendered so that the full screen is drawn, but you can easily make a boundary check and skip any tiles fully off-screen. Both methods will require some number crunching to find out what is the location of tile 01. In the end, both methods are roughly equal in terms of math required for a certain level of efficiency.
如果您有一些超出菱形边界的图块,我建议按深度顺序绘制:
If you have some tiles that exceed the bounds of your diamond, I recommend drawing in depth order:
Coobird 的答案是正确、完整的。 然而,我将他的提示与其他站点的提示结合起来,创建了可在我的应用程序(iOS/Objective-C)中运行的代码,我想与来这里寻找此类东西的任何人分享。 如果您喜欢/赞成这个答案,请对原始答案进行同样的操作; 我所做的只是“站在巨人的肩膀上”。
至于排序顺序,我的技术是改进的画家算法:每个对象都有 (a) 底部的高度(我称之为“水平”)和 (b) 其“底部”或“脚”的 X/Y图像(例如:头像的底座在他的脚下;树的底座在它的根部;飞机的底座在中心图像等)然后我只是从最低到最高级别排序,然后从最低(屏幕上最高)到最高底座排序 - Y,然后是最低(最左边)到最高的 X 基数。 这会按照人们期望的方式呈现瓷砖。
将屏幕(点)转换为图块(单元格)并返回的代码:
Coobird's answer is the correct, complete one. However, I combined his hints with those from another site to create code that works in my app (iOS/Objective-C), which I wanted to share with anyone who comes here looking for such a thing. Please, if you like/up-vote this answer, do the same for the originals; all I did was "stand on the shoulders of giants."
As for sort-order, my technique is a modified painter's algorithm: each object has (a) an altitude of the base (I call "level") and (b) an X/Y for the "base" or "foot" of the image (examples: avatar's base is at his feet; tree's base is at it's roots; airplane's base is center-image, etc.) Then I just sort lowest to highest level, then lowest (highest on-screen) to highest base-Y, then lowest (left-most) to highest base-X. This renders the tiles the way one would expect.
Code to convert screen (point) to tile (cell) and back:
您可以使用距观察者最近的最高点的欧几里得距离,但这不太正确。 它会产生球形排序顺序。 您可以通过从更远的地方观察来理清这一点。 距离更远,曲率变得平坦。 因此,只需将 1000 添加到每个 x、y 和 z 分量即可得到 x'、y' 和 z'。 对 x'*x'+y'*y'+z'*z' 进行排序。
You could use euclidean distance from the point highest and nearest the viewer, except that is not quite right. It results in spherical sort order. You can straighten that out by looking from further away. Further away the curvature becomes flattened out. So just add say 1000 to each of the x,y and z components to give x',y' and z'. The sort on x'*x'+y'*y'+z'*z'.
真正的问题是当您需要绘制一些与两个或多个其他图块相交/跨越的图块/精灵时。
经过两个月(艰难)的个人问题分析,我终于为我的新 cocos2d-js 游戏找到并实现了“正确的渲染绘图”。
解决方案包括对每个图块(敏感的)进行映射,其中精灵是“前面、后面、顶部和后面”。
一旦这样做,您就可以按照“递归逻辑”绘制它们。
Real problem is when you need draw some tile/sprites intersecting/spanning two or more other tiles.
After 2 (hard) months of personal analisys of problem I finally found and implemented a "correct render drawing" for my new cocos2d-js game.
Solution consists in mapping, for each tile (susceptible), which sprites are "front, back, top and behind".
Once doing that you can draw them following a "recursive logic".