「緊急回避」とは、アクションゲームでよくある「前転時などに一定時間無敵になり、敵の攻撃回避を目的としたアクション」のことを指しています。 ほかにも良い方法があるかもしれませんが、お手軽さを優先して、対象のGameObjectのレイヤーを切り替える方法を取りました。「ダメージを受けてノックバックした時の無敵状態」の実現などにも使えます。
なお、私が作成しているゲームが2Dであるため、2Dを題材としています。
Layer Collision Matrixを設定する
Layer Collision Matrix とは
Layer Collision Matrix を使うことで、Colliderが衝突検知するか否かをLayerレベルで設定できます。Layer Collision Matrix の設定項目は、 Edit > Project Settings > Physics 2D で開かれる inspector に存在します。
Default, TransparentFX, ignore Raycast, Water, UI 5つは Built in なレイヤーです。レイヤー名の交点にあるチェックボックスは「衝突検知するか否か」を表しています。チェックが入っている場合に衝突を検知します。デフォルトではすべてチェックが入っているので、すべてのレイヤー間で衝突が検知されます。
雑な緊急回避を実装するにあたって、以下の2つのLayerを新たに作成しています。
- Damage Layer : ダメージを与える物体が存在するレイヤー
- Dodge Layer : 緊急回避時に一時的に切り替えるレイヤー
Layerの作成は、Game ObjectのInspector上にある Layerのドロップダウンリスト > Add Layer… からできます。
衝突回避の設定
衝突を検知したくないレイヤーの交点のチェックボックスを外します。今回は、緊急回避時のレイヤーとして「Dodge Layer」を使うので、「Dodge Layer」と「Damage Layer」の交点となるところのチェックを外します。これで下準備は終わりです。
コードからGameObjectのレイヤーを切り替える
以下のコードでレイヤーの切り替えは簡単にできます。レイヤーを切り替えたら元に戻すのを忘れずに。
// レイヤー番号を名前から取得し、GameObjectのlayerプロパティに指定する。 gameObject.layer = LayerMask.NameToLayer("DodgeLayer");
与えられた名前のレイヤーが見つからない場合、NameToLayerメソッドは -1 を返します。gameObject.layerに -1 が設定されると以下のエラーが吐かれます。
A game object can only be in one layer. The layer needs to be in the range [0...31] UnityEngine.GameObject:set_layer(Int32)
NameToLayerメソッドを使えば、うっかり名前を変えてしまった場合にすぐ気付けますし、なんらかの事情でレイヤーの順番を変更しなければならない場合にコードレベルの対応も必要ありません。
雑なサンプル
はじめにこんな感じで、プレイヤーにダメージを与えることのできるGameObjectのLayerを 「DamageLayer」 にしておきます。プレイヤーのLayerはDefaultのままです。
続いてコードです。単純にするために対応するキーを押した時にレイヤーが切り替わるようにしています。「Z」キーを押したらレイヤーが DodgeLayer に変わり、衝突が検知されなくなります。
public class Sample: MonoBehaviour { void Update() { GetComponent<Rigidbody2D>().velocity = new Vector2(Input.GetAxis("Horizontal") * 5, 0); if(Input.GetKeyUp(KeyCode.Z)) { // Zキーを押したら、DodgeLayerに切り替え gameObject.layer = LayerMask.NameToLayer("DodgeLayer"); Debug.Log(gameObject.layer); } else if (Input.GetKeyUp(KeyCode.X)) { // Xキーを押したら、DefaultLayerに戻す gameObject.layer = LayerMask. NameToLayer("Default"); Debug.Log(gameObject.layer); } } }
今回は単純化のためにキーを押した時にレイヤーを切り替えていますが、実際は「緊急回避」のアクション開始時と終了時に、レイヤーの切り替えを行うことになるかと思います。
まとめ
以上、Layer Collision Matrixを用いた雑な緊急回避の実現でした。
今回は、DamageLayerを用意しましたが、ダメージを与えうる全てのGameObjectにLayerを設定するのは骨が折れます。DamageLayerの代わりに、床、壁、天井などを表すFloorLayerを用意し、DefaultとDodgeLayerのチェックを外すという手もあります。どちらもLayer設定の手間はかかってしまいますが・・・。設定量が少なく済むようにすれば幸せになれそうです。
補足
Collider 2Dの基礎についてはこちらの記事に記載しています。