前回、タイルマップのタイルの配置・表示設定が同じか判定するタイルマップ比較関数を作り、その関数が正しく判定できるか問題用プレハブと答えの bool 値を TestCase 属性で指定してテストも行いました。


今回は、その関数を使ってテストする予定の自作関数について紹介します。
この自作関数は、壁を配置したタイルマップを参照し、壁の影となるようにタイルの表示設定を変更します。
今回はその手順を紹介し、次回はその手順を手動で再現して、テストで照合するためのタイルマップを作りテストします。
※ Unity は 2021.3.14f1、Test Framework パッケージは Version 1.1.33、Visual Studio は Community 版 Version 17.2.5、 OS は Windows 10 です。
タイルマップの障害物・壁に影をつけるための方法
これは TopDownEngine の MMTilemapShadow が発想の起点になっています。
MMTilemapShadow で壁の影を作っている方法は、「TopDownEngine KoalaDungeon のマップの仕組み(4) | Compota-Soft-Press」で詳しく説明していますので、そちらをご覧ください。
簡単に手順を述べると、最初に壁だけのタイルマップ Walls を用意します。
そして MMTilemapShadow では自身の空のタイルマップ WallsShadow に Walls のタイルの配置をコピーし、タイルマップ全体を少し下にずらして表示します。
あとは、灰色で Sprite/Default シェーダーのマテリアルを影用タイルマップに設定することで、タイルが全体的に暗く影のよう表示されるようにします。

つまり、壁の影の正体は、コピーして下に少しずらしうす暗く表示した同じ壁のタイルということです。
自作関数でのアレンジ
TopDownEngine の MMTilemapShadow の処理を読み、少しアレンジしたものを作りました。
※マテリアルの色(albedo)は、わかりやすくするため黒色 (0, 0, 0) を選択しています。
影用タイルの表示を上下逆さまにする
影は壁とは上下さかさまのシルエットになるはずです。

そこで、影用タイルを垂直反転して上下さかさまに表示するアレンジを行いました。
影用タイルの拡大率を変更する
影は伸びたり縮んだりします。
ゲームによって影の伸縮具合は変わります。

そこで、Y 軸の拡大率を設定することで、伸びた影や短い影を表現できるようにしました。
オフセットの調整
影は壁の下側にぴったりとくっついて表示されないと不自然です。
拡大率やタイルの表示基準点を表す pivot によって、オフセット (Y 軸の移動) の量は異なります。
そこで、そのオフセットを自動的に調整する機能を追加しました。手動で設定することもできます。

pivot.y が既定の 0.5 の場合、拡大率を 1.0 から 0.5 に変えると、上側に 0.25 unit の隙間ができます。

pivot は回転や表示位置の基準点です。そのオブジェクトの座標を指定したとき、その座標と一致する点が pivot です。
オフセットの補正では、 pivot の Y 軸の座標と、スプライトを表示する際の拡大率を考慮する必要があります。

補正値 = (変形前のスプライトの縦幅 – pivot.y) * scale.y
です。全ての単位は 1 マスに対応する unit です。
pivot.y = 1.0 (Unity は左下原点のため。1.0 ならば基準点の Y 座標はマスの一番上の座標) で、拡大率 (scale.y) = 1.0 の場合ならば、タイルを 1.0 unit ずらすだけで良いはずですが、pivot.y と拡大率によって変わります。
.png)
今回の場合は pivot.y = 0.5 でスプライトの表示幅を 0.5 倍にしているので、先ほどの式
補正値 = (変形前のスプライトの縦幅 – pivot.y) * scale.y
に今回のパラメータを当てはめると
補正値 = (1.0 – 0.5) * 0.5 = 0.25 で
適切な Y 軸の移動量
1.0 – 0.25 (補正値) = 0.75
unit だけ下に移動させると壁の下側(つまり下の枠の上辺)にぴったりくっついて表示されます。
行列により垂直反転・拡大率・オフセットを同時に設定
前述した、垂直反転・拡大率・オフセットは、 Tilemap.SetTransformMatrix 関数で同時に設定できます。
筆者の苦手な行列を使わなくてはいけないのですが、サンプルなどを見て、次のように行列に各パラメータを設定しました。
Matrix の設定は以下のコードで行っています。
// 影用のマップチップの移動量と回転角度(Y軸反転固定)と拡大率を変更する行列を作成します。
Matrix4x4 matrixFlipY = Matrix4x4.TRS(
new Vector3(0f, translateY - correctInfo.CorrectionWithPivotYUnit, 0f),
new Quaternion(1f, 0f, 0f, 0f),
new Vector3(1f, scaleY, 1f));
// 行列をそのマスのタイルの表示設定に適用します。
@this.SetTransformMatrix(tilePosition, matrixFlipY);
コードの Matrix4x4.TRS 関数内の各項目の説明をします。
- translateY – correctInfo.CorrectionWithPivotYUnit
Y 軸のオフセットの設定です。この分タイルは Y 軸でずれて表示されます。
correctInfo.CorrectionWithPivotYUnit は拡大率や pivot を含めた補正値です。 - Quaternion(1f, 0f, 0f, 0f)
垂直反転を行います。 - scaleY
そのマスのタイル表示の Y 軸の拡大率です。
あとは Tilemap メンバ関数 SetTransformMatrix でマスの位置を指定して、作成した行列を適用します。これによりそのマスのタイルはパラメータの分だけ移動・回転・拡大して表示されます。
この際に、タイルマップのマスにロックがかけられていると行列を設定できないので、以下のコードでロックを解除しました。
これはコピー元のタイルマップとは独立した設定なので、コピー元のタイルマップのマスのロック状態には影響しません。
// フラグを確認し、TransformMatrix に関してロックされている場合は、そのマスのタイルのロックを解除します。
TileFlags tileFlags = @this.GetTileFlags(tilePosition);
if (tileFlags == TileFlags.LockAll)
{
// コピー先のマスのタイルのロックを解除
@this.RemoveTileFlags(tilePosition, TileFlags.LockAll);
}
if (tileFlags == TileFlags.LockTransform)
{
// コピー先のマスのタイルのロックを解除
@this.RemoveTileFlags(tilePosition, TileFlags.LockTransform);
}
今回はここまで
今回は Unity Tilemap で障害物・壁の影となるタイルマップを作成する関数の主要な処理手順について紹介しました。
次回は、今回紹介した関数と同様の手順で、答え合わせ用のタイルマップを GUI で作成します。
コメント