初めに
この記事はUnity初学者が学習の備忘録として書いたものです.誤っている点もあるかと思いますので,ご指摘いただけると幸いです.
(Unity2020.3を使用)
完成イメージ
Unity公式チュートリアル"Roll-a-ball"に追加機能として実装しました.
https://learn.unity.com/project/roll-a-ball
利用した機能
プレーヤーの接近検知にはOnTrigger・OnCollisionメソッドを利用しました.
接触イベント
上記の記事で説明されているように,Colliderコンポーネントが取り付けられたGameObjectでは他のColliderとの接触時に実行したい処理を,OnTrigger・OnCollisionメソッドで指定しておくことができます.
※少なくともどちらかのGameObjectにRigidbodyコンポーネントも必要です.
OnTrigger・OnCollisionの違い
これらは接触イベントの対象となるColliderのTrigger状態(※すり抜ける否か)によって使い分けます.
今回はプレイヤー側にTriggerあり(すり抜ける)のSpher Clliderを取り付け,これを探索範囲としてTriggerなし(すり抜けない)の壁への近接判定を行います.よって上図の対応からOnTriggerに処理を記述します.
3種類のOnTrigger
また,OnTriggerには呼び出されるタイミングが異なる3種類が用意されています.これによってflagやstateなどのあるタイミングで状態を切り変える処理や,接触が起きている間に繰り返し呼び出したい処理をそれぞれ設定することができます.
メソッド | 機能 |
---|---|
OnTriggerEnter() | Triggerオブジェクトに侵入した瞬間に呼び出される |
OnTriggerStay() | Triggerオブジェクトに侵入している間呼び出され続ける |
OnTriggerExit() | Triggerオブジェクトから脱出した瞬間に呼び出される |
実装したコンポーネント(スクリプト)
今回は「プレイヤーが一定の距離まで近づいたら,距離に応じた透明度を設定する」という実装にしたいためOnTriggerStay()を使用しました.※透明度はMeshコンポーネントのmaterial.colorのalpha値で設定
また,接触相手のGameObjectが透明な壁かどうかは透明度の制御スクリプト(InvisibleObjectコンポーネント)がアタッチされているかで判定しています.
[RequireComponent(typeof(SphereCollider))]
public class PlayerSearchArea : MonoBehaviour {
private SphereCollider area; // 探索エリアとして扱うClollider
private float areaRadius = 5; // SphereColliderの半径
void Start() {
area = GetComponent<SphereCollider>();
area.radius = areaRadius;
}
// ↓ 他のColliderが探索エリア内にいる限り呼ばれ続ける
private void OnTriggerStay(Collider other) {
// 相手が不可視オブジェクトの場合,
if (other.gameObject.TryGetComponent<InvisibleObject>(out var obj)) {
// 距離に応じてalpha値を設定
var distance = (transform.position - other.transform.position).magnitude;
var aipha = Mathf.Clamp01(1 - distance / areaRadius);
obj.SetVisibility(true, aipha); // InvisibleObjectクラスの透明度設定メソッド
}
}
こちらが相手側にアタッチしておくスクリプトです.Meshマテリアルの透明度を設定するメソッドをpublicで用意しておき,初期化時に見えないようにしておきます.
※今回の機能には不要なプロパティ(IsVisible)が含まれています.
[RequireComponent(typeof(MeshRenderer))]
public class InvisibleObject : MonoBehaviour{
// 制御対象
private MeshRenderer mesh;
// 透明かどうか
public bool IsVisible { get; private set; } = false;
//
void Start() {
mesh = GetComponent<MeshRenderer>();
SetVisibility(false); // 可視性に対応したalpha値を適用
}
// 可視性を設定し,見える場合はalpah値を指定可能
public void SetVisibility(bool visibility, float alpha=1f) {
IsVisible = visibility;
SetMeshAlpha(IsVisible ? alpha : 0f);
}
}