回答:
更新:マップレンダリングアルゴリズムの修正、イラストの追加、書式の変更。
おそらく、タイルを画面にマッピングする「ジグザグ」手法の利点は、タイルの座標x
とy
座標が垂直軸と水平軸上にあると言えます。
「ひし形で描く」アプローチ:
「ひし形で描画」を使用してアイソメマップを描画することによりfor
、次の例のように、2次元配列上でネストされたループを使用してマップをレンダリングするだけだと思います。
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
すべてのタイル全体で一貫して機能する、かなり単純なロジックを持つ単純な入れ子のループであることです。
不利益:
そのアプローチの1つの欠点は、マップ上のタイルのx
およびy
座標が対角線で増加するため、画面上の場所を配列として表されたマップに視覚的にマッピングすることがより困難になる可能性があることです。
ただし、上記のサンプルコードの実装には落とし穴があります-レンダリング順序により、特定のタイルの背後にあるはずのタイルが前面のタイルの上に描画されます。
この問題を修正するには、内部for
ループの順序を逆にする必要があります-最高値から始めて、低値に向かってレンダリングします。
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)
)
上記の修正により、マップのレンダリングが修正されます。
「ジグザグ」アプローチ:
利点:
おそらく、「ジグザグ」アプローチの利点は、レンダリングされたマップが「ダイヤモンド」アプローチよりも少し垂直方向にコンパクトに見える場合があることです。
不利益:
ジグザグ手法を実装しようとすると、デメリットとして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
)
また、表示順序がずれているため、タイルの座標を把握するのが少し難しい場合があります。
注:この回答に含まれているイラストは、タイルレンダリングコードの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_width
とtile_height
タイルは、タイルを表す画像内のグラウンドタイルの幅と高さを参照しています。
画像の寸法とタイルの寸法が一致している限り、画像の寸法を使用できます。そうしないと、タイルマップがタイル間のギャップでレンダリングされる可能性があります。
j = (2 * x - 4 * y) / tilewidth * 0.5; i = (p.x * 2 / tilewidth) - j;
。
どちらの方法でも仕事が完了します。ジグザグとは、次のような意味だと思います:(数字はレンダリングの順序です)
.. .. 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...
..234..
.56789.
..abc..
...d...
クーバードの答えは正しい、完全なものです。しかし、私は彼のヒントを別のサイトのヒントと組み合わせて、私のアプリ(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;
}
正しくない点を除いて、視聴者の最も高く、最も近い点からのユークリッド距離を使用できます。その結果、球状のソート順になります。遠くから見るとそれをまっすぐにすることができます。さらに離れると、曲率は平らになります。したがって、x、y、zの各コンポーネントに「1000」を追加するだけで、x '、y'、z 'が得られます。x '* x' + y '* y' + z '* z'での並べ替え。