ExecuteEventsという、SendMessageの代わりになるシステムを使いました。
色々やり方あると思います。
Health.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using System; public class Health : MonoBehaviour,IAddDamage { public int HP; public void AddDamage(float damage) { //ダメージの処理 HP -= damage; } } public interface IAddDamage : IEventSystemHandler { void AddDamage(float damage); } |
Attack.cs
1 2 3 4 5 6 7 8 9 10 |
public class Attack : MonoBehaviour{ //コライダーを使って衝突したものにダメージを与える場合 private void OnCollisionEnter(Collision collision) { ExecuteEvents.Execute<IAddDamage>( collision.gameObject, null, (target, eventdata) => target.AddDamage(DamageValue)); } } |
プログラムの継承やinterfaceについて知っているとすんなり使えます。知らなくてもそれなりには使えるかもですが。
対象のゲームオブジェクトがnonactiveだと呼ばれないと思います。
ここから余談ですけど
以前は衝突したCollisionをGetComponentして体力を管理するコンポーネントを持っているかを確認して処理をしてました。
上の例だと
1 2 3 4 5 6 7 |
private void OnCollisionEnter(Collision collision) { Health health = collision.GetComponent<Health>(); if(health != null){ health.Damage(damageValue); } } |
みたいな感じで。
これだといちいちNullチェックをしないといけないし、GetComponentは少しだけ重い処理だっていう話をちらほら見るので、マシンガンとかレーザー系の武器みたいに頻繁にDamage処理をする場合だとちょっとどうなんだろうって思ってました。そうはいっても、実際にやったらAndroidでも普通に動きましたけど。
LayerMaskとかで、衝突するものを絞っても良いんですが、それでも衝突するものは壁だったりすることもあるだろうしで。
このExecuteEventだと相手が設定したinterfaceを持ってなくてもエラーとかになんないから、スクリプト書く時には楽な気がします。
持っているか確認したいときはExecuteEvents.CanHandleEvent<targetClass>でできるみたいです。
あと、こちらによるとSendMessageの代わりに実装されたそうなんですが、SendMessageに比べると処理が早いそうです。GetComponentとかと比べるとどうなのかまでわかりませんが。
ただ書くのがすっごく楽な気がするのでこっちの方が何かと使い勝手がいい気がします。VisualStudioのリファクタリングの名前変更の機能(ctrl+r×2回押し)使えば簡単に変更できますし。それはGetComponentでも変わらないですけど。
あと、このIeventSystemHandlerを持っているコンポーネントはインスペクタに表示もされるみたいです。