現在開発中の問題点パート2
どうも!前回の記事で記載した通り
壁にぶつかるオブジェクトの移動については
Rigidbodyでの移動がいいよっていうことで結論が出ました。
というのは分かったのですが新たな問題発生です。
簡単にいかんもんですねー。
今回やりたいこととその解決方法について記載していこうと思います!ではいきましょー
今回やりたいこと
鬼ごっこ的なものを作りたいのですが
今回やりたい敵の移動ロジックは以下になります。
1.ある一定範囲内にプレイヤーが「侵入」したらプレイヤーの位置に移動
2.プレイヤーと「衝突」したらプレイヤー消去(ゲームオーバー)
やりたいことはシンプルなのですが実装してみたら難しかったです。
何が問題だったのかとその解決方法を記載していきます。
今回の問題点(前提)
今回の問題点は敵という同一オブジェクトに
侵入用Colliderと衝突用Colliderの二つのColliderを
つけないといけないことです。
最初は何も考えずに以下のようにしてみました。
(親オブジェクト)
・Rigidbody2d(衝突判定用)
・Circle Collider(衝突判定用)
(子オブジェクト)
・Rigidbody2d(侵入判定用)
・Circle Collider(侵入判定用)
とりあえずこの構成を思いついたということです。
で侵入判定を行いたいのでCircle Collider(侵入判定用)の
isTriggerをオンにしました。
isTriggerについて
そもそもisTriggerってなんだよって話です。
isTriggerはColliderの項目なのですがこのチェックをオンにすると
衝突判定を行わなくなります。
Triggerを日本語にすると引き金とか、引き起こすとかって意味になります。
…日本語での意味と実際にやっていることが全然違うので
覚えにくいんですよ、isTriggerがなにしてるか。
isInvasionとかが妥当な項目名なんじゃないですかね?とか思いますが
英語喋れない人間が何言ってるんだって話ですね 笑
そもそもRigidbodyをアタッチしたゲームオブジェクトに
Colliderを取り付けると他のRigidbodyをアタッチしたゲームオブジェクトとの
Collider同士の表面が接触したら衝突が起きます。
つまりCollider同士がぶつかりお互いのColliderの中に進むことはできなくなります。
しかしisTriggerのチェックをオンにすると衝突が起きずに
Colliderの中に侵入できるようになります。
その上で「他のゲームオブジェクトが自分の設定したColliderの範囲内に侵入した」
ということを検知出来るんです。
今回の問題点(本題)
ということでこれでなにがいけなかったのかというと
自分自身が侵入したことになっちゃうんです。
つまり親オブジェクトのCircle Collider(衝突判定用)が
子オブジェクトのCircle Collider(侵入判定用)に
常に侵入してしまうんですよね。
考えれば当然なんですけどそこまで頭が回りませんでした…。
分かってからは「いや、そりゃそうなるやろ」って思うんですけどね 笑
解決方法(レイヤー別の衝突判定)
じゃぁどうすればいいの?って話なのですが
色々調べた結果、実はUnityにはレイヤー別の衝突判定を
設定できるんです。これで解決しました!
レイヤーって?
そもそもレイヤーってなに?ってところです。
Layer(レイヤー)を日本語にすると「層」になります。
個々のゲームオブジェクトはinspectorウィンドウ上で
レイヤーを設定できます。
ロールプレイングゲームでもRPGでもなんでもそうなのですが
背景があってその手前にプレイヤーがいますよね。
これがレイヤーです。
「背景」という層があってその手前に「プレイヤー」という層が表示されているわけです。
ゲーム上の位置としては同じ位置にいる(重なっている)のにお互いに干渉しあわない
っていう風に出来るのがレイヤーです。
ステップ1:レイヤーを分ける
ということで親オブジェクトと子オブジェクトのレイヤーを分ければいいわけです。
inspectorウィンドウの右上のレイヤーを親と子で別々に設定しましょう。
ステップ2:レイヤー別の衝突判定を設定する
レイヤーを分けることが出来たら終わり!ってわけではないんです。
実はこれだけ設定しても何も状況は変わりません。
Unityではレイヤー別の衝突判定を個別に設定できるんです。
どういうことかというと例えば
・レイヤー1
・レイヤー2
・レイヤー3
の3つのレイヤーがあったとして
レイヤー1とレイヤー2は衝突しない
レイヤー1とレイヤー3は衝突する
という風に設定出来るという訳です。
で、初期状態では全てのレイヤーはお互いに干渉しあうように設定されています。
ということで干渉しあわないレイヤーを設定してあげましょう。
今回は親オブジェクトのレイヤーと子オブジェクトのレイヤーが
干渉しあわないように設定します。
Edit→Project Setting→Physics 2D
にLayer Collision Matrixというのがあります。
見た目が複雑でめんどくさって思いがちですが結構簡単です。
縦と横で干渉させたくないレイヤーが交差するチェックボックスを
オフにすればいいだけです。
今回はcolliderというレイヤーを追加したのでDefaultとcolliderの交差するチェックボックスをオフにします。
最終的にできたもの
これで設定完了です。
プレイヤーと敵をどう作ったかまとめてみます。
両者ともほぼ同じ設定内容です。
(親オブジェクト)
レイヤー:Default
・Rigidbody2d(衝突判定用)
・Circle Collider 2D(衝突判定用)
(子オブジェクト)
レイヤー:invasion
・Rigidbody2d(侵入判定用)
・Circle Collider 2D(侵入判定用)
違いといえばCircle Collider 2D(侵入判定用)の
半径を変えているってことだけです。
また敵の親オブジェクトには衝突したことを識別する
CollisionControllerというスクリプトをアタッチします。
中身は単純に以下のようにしました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CollisionController : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collision)
{
Debug.Log("衝突!");
}
}
衝突したらログを出力するだけです。
また敵の子オブジェクトも侵入したことを識別する
TriggerControllerというスクリプトをアタッチします。
中身は以下にしました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerController : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D collision)
{
Debug.Log("侵入!");
}
}
こちらも侵入したらログを出力するだけですね。
ではこの状態で実行してみましょう。
結果が以下になります。
ちゃんと動作してくれました!
めでたし、めでたしです!
番外編
ちなみに子のRigidbodyのBody TypeをKinematicにしないと
追従してくれないようです。
以下は子の RigidbodyのBody TypeをDynamicにした場合の動作です。
敵の子オブジェクトが移動せずにその場に留まってしまうんです…。
これについては以下に対処法が記載されていました。