Unity中如何不使用static实现Action/Event跨脚本方法调用?
不用static也能在Unity中使用Action/C# Event的方法
首先明确:完全不需要借助public static就能实现跨脚本订阅Action或Event,你提供的代码示例其实已经是正确的非static实现方式,只是可能没完全理清其中逻辑。
核心逻辑
跨脚本订阅事件的关键是获取到目标脚本的实例引用,而非依赖static修饰符。只要能拿到目标对象的实例,就能直接订阅它的非static事件/Action。
你的代码解析
你写的代码已经是标准的非static事件通信实现:
Player脚本中定义了非static的public事件OnHitAction,全程没用到staticPlayerAnimator脚本在Awake中通过GetComponent<Player>()获取到Player组件的实例,随后订阅了该实例的OnHitAction事件
这种方式既实现了脚本间的事件通信,又比static更安全——static事件全局可访问,容易引发意外订阅或内存泄漏;而非static事件只有持有实例引用的对象才能操作,可控性更强。
其他获取实例的常用方式
除了GetComponent,还有几种场景适配的实例获取方法:
- 层级查找:用
transform.Find("Player").GetComponent<Player>()查找指定名称的子对象,或GetComponentInParent<Player>()/GetComponentInChildren<Player>()遍历父/子节点获取组件 - 单例模式:针对全局唯一的对象(比如玩家角色),可以通过单例快速获取实例(注意单例只是获取实例的方式,事件本身仍是非static的)
public class Player : MonoBehaviour { public static Player Instance; public event Action OnHitAction; private void Awake() { Instance = this; } public void TakeDamage(int damage) { OnHitAction?.Invoke(); } } // 订阅时直接调用:Player.Instance.OnHitAction += Hit; - Inspector手动赋值:在Unity编辑器中,把Player对象拖到PlayerAnimator脚本的public字段上,无需编写查找代码
public class PlayerAnimator : MonoBehaviour { public Player player; // 在Inspector面板拖入Player对象 private Animator _animator; private void Awake() { player.OnHitAction += Hit; _animator = GetComponent<Animator>(); } private void Hit() { _animator.SetTrigger("Hit"); } }
重要注意事项
- 记得在脚本销毁时取消订阅事件,避免内存泄漏:
private void OnDestroy() { if (_player != null) { _player.OnHitAction -= Hit; } } - 事件要定义成
public event Action而非public Action,这样外部只能进行订阅/取消订阅操作,无法直接触发事件,保证触发控制权在定义事件的脚本中,安全性更高。
内容的提问来源于stack exchange,提问作者user21403547
相关产品推荐
相关产品推荐

