1つの GameObject に複数の当たり判定をつけたい場面があると思います。いくつか方法がありますが、当サイトでは、「当たり判定の数だけ子オブジェクトを作成する」方法を推奨します。この方法でなければ、(複数の当たり判定を持っている側が)自分の当たり判定の中で、相手がどれに当たったのか識別することができないためです。
目次
想定している場面
プレイヤーと敵が地面(重力あり)の上で対峙しているような状況です。よくあるパターンとして、次のようなものがあります。
①プレイヤーが敵の頭を踏めば、敵の負け
②プレイヤーが敵の体部分に触れると、プレイヤーの負け
動画で確認しておきましょう。
敵のどこに触れたかで、挙動が異なります。それではこれをどのように作成するか解説していきます。
考え方
① 物理的な当たり判定(地面に当たったら止まる、敵に当たったら跳ね返る、など)をつけます。プレイヤーや敵、地面など、物体としてゲーム中に存在するものには全てつけます。
② 敵の頭の当たり判定のために子オブジェクト「ColliderHead」を作成します。
③ 作成した子オブジェクトに、当たり判定をつけます。また、プレイヤーが何に当たったのか識別できるように、タグ「ColliderEnemyHead」をつけます。
同様に、敵の体に対しても当たり判定やタグ名をつけます。
このように、複数の当たり判定をもつ場合は、その数だけゲームオブジェクトを作成します。こうすることで、プレイヤーも敵も、どの当たり判定に当たったのか容易に判別することができます。
準備:Unity での設定
STEP1:物理的な当たり判定をつける
敵の形に合わせた当たり判定(Collider)をつけます。
STEP2:子オブジェクトを作成する
左図のように、「敵」のゲームオブジェクトを右クリックして、「空のオブジェクトを作成」を選びます。これで「子オブジェクト」が作成できます。
頭との当たり判定用に「ColliderHead」、体との当たり判定用に「ColliderBody」を作成します(上図)。
STEP3:子オブジェクトに当たり判定とタグをつける
子オブジェクトに、当たり判定とタグをつけます。左図は、頭の当たり判定の例です。
「トリガーにする」にチェックを入れます。こうすることで物理的な衝突処理を無効化します。物理的な当たり判定は親オブジェクトで設定しています。
STEP4:子オブジェクトにスクリプトをアタッチする(必要に応じて実施)
プレイヤーとの接触時に、処理が必要な場合はスクリプトをアタッチします。
今回は、スライムは頭を踏まれると負けます。負けるときに点滅しながら消えるようにしたいので「頭」の子オブジェクトにはスクリプトをアタッチしました。
スライムの「体」のオブジェクトはプレイヤーと当たっても変化はなしのままとしたので、スクリプトは不要でした。
以上で、Unity 側での設定は終了です。
プログラミング(子オブジェクト側のスクリプト:スライムの頭が踏まれたとき)
SlimeColliderHeadController.cs
using UnityEngine;
public class SlimeColliderHeadController : MonoBehaviour
{
private SlimeController slimeController;
private void Start()
{
GameObject slimeObj = transform.parent.gameObject;
slimeController = slimeObj.GetComponent<SlimeController>();
}
private void Update()
{
}
private void OnTriggerEnter2D(Collider2D collider)
{
var player = collider.gameObject.GetComponent<PlayerController>();
if (player != null)
{
slimeController.Dead();
}
}
}
■17行目:OnTriggerEnter2D(メソッド)
頭の当たり判定に何かが入ってきたら実行されます。
■20行目:入ってきたのがプレイヤーかどうか調べています。プレイヤーの場合は頭を踏まれたということなので、22行目を実行します。
■22行目:slimeController.Dead()
親のオブジェクトのスクリプト Dead メソッドを実行します。
負けた時は地面の下に落ちていくようにします。親の重力の当たり判定を無効化する必要があるので親のメソッドを実行しています。
SlimeController.cs
using UnityEngine;
public class SlimeController : MonoBehaviour
{
[SerializeField]
private SpriteRenderer slimeRenderer;
private const float BlinkingCycle = 0.5f;
private const float DestroyTime = 1.5f;
private double elapsedTime;
private EnemiesState State = EnemiesState.Idle;
private void Start()
{
}
private void Update()
{
}
private void FixedUpdate()
{
if (State == EnemiesState.Dead)
{
elapsedTime += Time.deltaTime;
Dying();
}
}
public void Dead()
{
State = EnemiesState.Dead;
elapsedTime = 0;
Destroy(gameObject, DestroyTime);
}
private void Dying()
{
float cos = Mathf.Cos((float)(2 * Mathf.PI * elapsedTime / BlinkingCycle));
Color color = slimeRenderer.color;
color.a = cos;
slimeRenderer.color = color;
}
}
■34行目:Dead(メソッド)
子オブジェクトのスクリプトから呼び出されます。
「SlimeColliderHeadController.cs」の 22行目
■36行目:State(変数)
状態を Dead にします。また、Destroy というメソッドを実行して、DestroyTime 秒後にオブジェクトを消すようにしています。
■25行目:FixedUpdate(メソッド内)
状態が Dead の場合、Dying(負ける演出)を実行します。
■41行目:Dying(メソッド)
チカチカと点滅するようにしています。
プログラミング(プレイヤー側のスクリプト:スライムの体に触れた時)
PlayerController.cs(一部のみ)
private void FixedUpdate()
{
if (nowState == PlayerState.Dead && oldState != PlayerState.Dead)
{
GetComponent<CapsuleCollider2D>().enabled = false;
rbody2D.AddForce(new Vector2(0, 5), ForceMode2D.Impulse);
animator.Play(PlayerState.Fall.ToString());
oldState = PlayerState.Dead;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag.Equals(GameObjectTags.ColliderEnemyBody.ToString()))
{
nowState = PlayerState.Dead;
}
}
■12行目:OnTriggerEnter2D(メソッド)
「トリガーにする」が設定されている当たり判定と当たったときに実行されます。
■14行目
当たった相手のタグ名が「ColliderEnemyBody」の場合、16行目を実行します。負けのフラグのように使っています。
■5~8行目
負けのフラグ(状態が Dead)になっているとき実行されます。5行目で物理的な当たり判定を無効化しています(地面の下に落ちていくようにするため)。
6行目は少し上に飛び上がるように上向きの力を加えています。
以上で、複数の当たり判定を設定する方法についての解説を終わります。