【Unity】マス目状の床面に沿って、キャラを移動させたい

こんにちは。
相変わらずタイトルが意味不明な、ほげ子です。

目指したかったのは、私の大好きなアプリ「Monument Valley」のキャラ移動なんですよ。

キャラをNavmeshAgentで移動させたような感じではなくて、、、

私のゲーム画面でいうと、床面がマス目みたいになってるので、タップの検出はマス目単位で、移動もマス目に沿ってキチキチっと歩かせたいわけです。

tapmove1.png

いろいろ調べてはみたんだけど、情報が見つからなくて、またしても我流です。

こんなことで悩んでいるのは、私だけかもしれないけど、一応、簡単にメモしておきます。

ひとことで言ったら、
「地形を構成するブロック(平面、階段、スロープ)ごとに、床面部分にコライダーをつけました」
なんですけどね。。

ちなみに、床面のコライダーは、Planeでもいいと思います。
カメラの調整次第だろうけど、私のアプリでは、奥のフロアがタップしづらかったので、高さを持たせたコライダーにしました。

tapmove2.png

<実装方法>
1. 床面衝突用にレイヤ(Floor)を作成しておく。
ゲーム中の無駄な衝突判定は、避けたいので
mapmove3.png

2.地形を構成するブロック(平面とか、階段とか、スロープ)に持たせるブロック情報(BlockInfo.cs)を定義しとく。
BlockInfo.cs

public Vector3 floorCenter; // 床面の中心位置
// その他、いろいろ省略


3.ブロックに、Block.csをアタッチし、Floorレイヤを設定し、床面部分にコライダーを設定する。
プログラムで書くとこんな感じだけど、静的な部品なら手動で設定してください。
Block.cs

public BlockInfo blockInfo; // ブロック情報(ここに床面の中心位置など保持)

// ブロック生成処理
public static Block NewInstance(BlockInfo blockInfo){
// ゲームオブジェクト生成
GameObject blockObj = new GameObject(blockInfo.name);

// オブジェクトに、Block.csをアタッチ
Block block = blockObj.AddComponent< Block >();

// ブロック情報設定
block.blockInfo = blockInfo;

// レイヤに予め定義しておいたFloorを設定
blockObj.layer = LayerMask.NameToLayer("Floor");

// -----------------
// いろいろ(省略)
// -----------------

// 床面にコライダーをアタッチ
floorCollider = blockObj.AddComponent< BoxCollider >();
floorCollider.center = blockInfo.floorCenter + Vector3.down * height/2f;
floorCollider.size = new Vector3(scale, height, scale);

// -----------------
// いろいろ(省略)
// -----------------

return block;
}


4. 画面のイベントハンドラ(UIEventHandler.cs)で、床面タップを検出する。
UIEventHandler.cs

private int floorMask;
void Start () {
// 床面衝突用のFloorレイヤを取得し、レイヤマスクに変換
floorMask = 1 << LayerMask.NameToLayer("Floor");
}
void Update () {
// FloorレイヤにあるコライダーにRayを飛ばす
if (Physics.Raycast(ray, out hit, 100, floorMask)){
// ヒットしたオブジェクトからBlock情報取得
Block tappedBlock = hit.transform.gameObject.GetComponent< Block >();

Debug.Log( "タップしたブロックの中心位置:" + tappedBlock.blockInfo.floorCenter);
}
}


この先は、タップしたブロックまでのルート検索して、キャラクターを移動させます。
ルート検索処理では、BlockInfoの配列を返すようにしておけば、
blockInfoArray[i].floorCenterに向かって、ブロックをひとつずつ進んでいくだけで完成です!

この記事へのコメント