これについてはすでに多くのリソースがあることはわかっていますが、自分の座標系に一致するリソースが見つからないため、これらのソリューションを自分のニーズに合わせるのに非常に苦労しています。私が学んだことは、これを行う最良の方法は変換行列を使用することです。それを実装することは問題ありませんが、座標空間をどのように変換する必要があるのかわかりません。
これが私の座標系を示す画像です:
画面上の点をこの座標系に変換するにはどうすればよいですか?
これについてはすでに多くのリソースがあることはわかっていますが、自分の座標系に一致するリソースが見つからないため、これらのソリューションを自分のニーズに合わせるのに非常に苦労しています。私が学んだことは、これを行う最良の方法は変換行列を使用することです。それを実装することは問題ありませんが、座標空間をどのように変換する必要があるのかわかりません。
これが私の座標系を示す画像です:
画面上の点をこの座標系に変換するにはどうすればよいですか?
回答:
まず、これがコードです。説明は次のとおりです。
/*
* tw, th contain the tile width and height.
*
* hitTest contains a single channel taken from a tile-shaped hit-test
* image. Data was extracted with getImageData()
*/
worldToTilePos = function(x, y) {
var eventilex = Math.floor(x%tw);
var eventiley = Math.floor(y%th);
if (hitTest[eventilex + eventiley * tw] !== 255) {
/* On even tile */
return {
x: Math.floor((x + tw) / tw) - 1,
y: 2 * (Math.floor((y + th) / th) - 1)
};
} else {
/* On odd tile */
return {
x: Math.floor((x + tw / 2) / tw) - 1,
y: 2 * (Math.floor((y + th / 2) / th)) - 1
};
}
};
このコードは、質問に示されているマップのボックスでは機能しません。これは、奇数のタイルが左にオフセットされているのに対し、奇数のタイルは通常、右にオフセットされているためです(タイルマップエディターの場合と同様)。奇数タイルの場合に返されるx値を微調整することで、これを簡単に修正できるはずです。
説明
これは、このタスクを達成するためのやや強引な方法のように思えるかもしれませんが、少なくともピクセルが完全であり、わずかに柔軟性があるという利点があります。
トリックは、マップを1つの千鳥格子としてではなく、2つのグリッドを重ねて表示することです。奇数行グリッドと偶数行グリッドがありますが、代わりにそれらを赤と緑と呼び、きれいな図を作成できるようにします...
その画像の右側にある点に紫色の点を付けたことに注意してください。これは、元のタイル空間で見つけようとするポイントの例です。
世界のどの点についても注意すべき点は、それが常に正確に2つの領域にあるということです-赤と緑の領域(エッジ上にある場合を除き、とにかくギザギザのエッジ境界内でクリッピングされる可能性があります)。それらの地域を見つけましょう...
次に、2つの領域のどちらが正しいかを選択します。常に1つの答えがあります。
ここから、いくつかのより簡単な計算を行い、サンプルポイントから2つの領域の各中心点までの距離の2乗を計算できます。どちらが最も近いかが私たちの答えになります。
ただし、別の方法があります。テスト領域ごとに、タイルの正確な形状と一致するビットマップをサンプリングします。その単一タイルのローカル座標に変換されたポイントでそれをサンプリングします。この例では、次のようになります。
左側の1つは、緑の領域をチェックしてヒット(黒のピクセル)を取得します。右側では、赤い領域をテストして、ミス(白いピクセル)を取得しています。2番目のテストは、常にどちらか一方のみであり、両方ではないため、もちろん冗長です。
次に、奇数のタイルが1,1にヒットしたという結論に達します。この座標は、奇数行と偶数行に異なる変換を使用して、元のタイル座標に簡単にマッピングできます。
このメソッドでは、ピクセルテストビットマップでピクセルごとの単純なプロパティを使用することもできます。たとえば、白はオフタイル、黒はヒット、青は水、赤は固体です。
あなたが抱えている問題はあなたの座標空間にあると思います。タイルに指定した座標は、実際には等角投影ではありません。xAxisを右下斜めに、yAxisを左下斜めに(またはその変形)と考える必要があります。
現在、図の座標軸に沿って移動すると、「タイルスペース」で対角線方向に移動するため、正方形は最終的にひし形になります(すべてがより複雑になります)。
あなたが探している変換行列は、それらのx軸とy軸から構築されたものです。実質的には以下の計算と同じです。
screenOffsetXY = screenPointXY - tileOriginXY;
tileX = dot(screenOffsetXY, xAxis) / tileWidth;
tileY = dot(screenOffsetXY, yAxis) / tileWidth;
編集:私はちょうど同じような質問に遭遇しました(しかし、私が話していた座標系について)、誰かがここではるかに完全な答えを出しました:
基本的に、イベントリスナーを使用してウィンドウ内のマウスの位置を取得するには、ウィンドウ内のキャンバス位置のオフセットをマウス位置から削除する必要があります。これにより、マウス位置はキャンバスに相対的になります。
function mouseTwoGridPosition(e){
var mousex = e.pageX; //mouse position x
var mouseY = e.pageY; //mouse position y
var canvas_width = 1000; //pixels
var offset_left = 100; //offset of canvas to window in pixels
var offset_top = 150; //offset of canvas to window in pixels
var isotile = 64; //if iso tile is 64 by 64
//get mouse position relative to canvas rather than window
var x = mousex - canvas_width/2 - offset_left;
var y = mousey - offset_top;
//convert to isometric grid
var tx = Math.round( (x + y * 2) / isotile) - 1;
var ty = Math.round((y * 2 - x) / isotile) - 1;
//because your grid starts at 0/0 not 1/1 we subtract 1
// this is optional based on what grid number you want to start at
return [tx,ty];
}
マウスムーブのキャンバスでイベントリスニングを行う方法を知っていると想定します。それ以外の場合は、アイソメトリックゲームデザインを検討する前にJSについてさらに学習することをお勧めします。D
座標空間を変えることで解決しました。これは最初の行にオフセットなしで開始され、そのために少し調整できる実際の例を見つけました。
hWidth = this.tileset.tileSize.width / 2;
hHeight = this.tileset.tileSize.height / 2;
pX = point.x - halfWidth;
pY = point.y - halfHeight;
x = Math.floor((pX + (pY - hHeight) * 2) / this.tileset.tileSize.width);
y = Math.floor((pY - (pX - hWidth) * 0.5) / this.tileset.tileSize.height);
tx = Math.floor((x - y) / 2) + 1 + this.camera.x;
ty = y + x + 2 + this.camera.y;