はじめに
ゲーム制作でマップエディターなどを作っているときに、座標をグリッドサイズに合わせてスナップしたいときがあるとおもいます。
この記事ではスナップするときの考え方を紹介します。
特定の言語やゲームエンジンによらずに、どんなときでも使える共通の考え方です!
2025-05-15
ゲーム制作でマップエディターなどを作っているときに、座標をグリッドサイズに合わせてスナップしたいときがあるとおもいます。
この記事ではスナップするときの考え方を紹介します。
特定の言語やゲームエンジンによらずに、どんなときでも使える共通の考え方です!
スナップとは、最も近いグリッドに移動させることです。
例えば、グリッドサイズが1.0のグリッドがあったとします。
マウスクリックした座標のX座標が、0.7だったとしましょう。
このとき、クリックした座標は0.7ですが、実際に配置したいのはグリッドに沿った座標、つまり0.0~1.0のグリッド(赤背景の四角)です。
![0.0~1.0にスナップする]/assets/image/uploads/articles/image_32_2.png
マウスクリックした座標に配置するのではなく、グリッドに沿って吸着させて配置することを「スナップ」といいます!
先に結論を伝えると、スナップをするコードは以下のようになります。(C++で書いています)
Vec3 MapEditor::snapToGrid(const Vec3& pos, double gridSize) const
{
return Vec3{
std::floor(pos.x / gridSize) * gridSize,
0.0,
std::floor(pos.z / gridSize) * gridSize
};
}
コードはC++で書いていますが、重要なポイントは以下の部分です。
std::floor(pos.x / gridSize) * gridSize
pos.xはクリックした座標です。 「グリッドサイズで割った後に」floorで切り捨て、その後グリッドサイズをかけます。 こうすることで、マウスの座標に対して手前のマスに吸着します。 具体的には、0.0~1.0の間をクリックしたら0.0のグリッドに配置され、1.0~2.0なら1.0のグリッドに配置されます。
この計算式をみて、なぜstd::floor(pos.x)だけではないの?と思いませんでしたか? 実は、ただ切り捨てるだけだと、グリッドからずれた場所にスナップされます。 実際に計算してみましょう。
今回、分かりやすいように GridSize = 2.0 で考えてみます。 このとき、クリックしたX座標が3.7だったとします。 つまり、下の画像のような状況です。
このとき理想的なスナップは、2.0~4.0の部分に色が塗られることです。 では、std::floorだけの場合と正しい場合を見比べてみましょう。
std::floor(3.7)
→ 3.0
結果は3.0です。
2の倍数ではない、ずれた位置にスナップすることになりますね。
画像で見ると一目瞭然です。
std::floor(3.7 / 2.0) * 2.0
→ std::floor(1.85) * 2.0
→ 1.0 * 2.0
→ 2.0
結果が2.0になっています。
最初に「グリッドサイズを単位とした値で割った」ことがポイントです!
これにより、グリッドサイズの大きさに影響されない値が算出できます。
あとは、floorで切り捨てた後に元のグリッドサイズのスケールに戻せば問題ありません。
画像で見ても、2.0~4.0のところにスナップしていますね。
グリッドサイズのスナップについて考え方を説明しました。
一度分かればいろいろなところに応用できる考え方だと思います。
ぜひ自分の制作に役立ててください!