UnityEvent一处可触发另一处失效求助(ScoreEvent调用异常)
问题描述
使用自定义UnityEvent(ScoreEvent,传递float类型参数),其余场景调用均正常,但敌人死亡时调用该事件却无响应。若将调用代码移至之前的if语句中则可正常运行。
相关代码
主脚本Health
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; [RequireComponent(typeof(TriggerEnter))] public class Health : MonoBehaviour { private ScriptableObjectLoader _sol; private TriggerEnter _te; public HealthbarEvent HE; public ScoreEvent SE; public float ObjectHealth; public float EnemyScore; private float _score; private bool _isDead; private void Awake() { if(_te == null) { _te = GetComponent<TriggerEnter>(); } if(HE == null) { HE = new HealthbarEvent(); } if(SE == null) { SE = new ScoreEvent(); } } void Start() { this._sol = GetComponent<ScriptableObjectLoader>(); _te.DE.AddListener(onChange); this.ObjectHealth = _sol.Health; this._score = _sol.Score; this._isDead = false; HE.Invoke(ObjectHealth); } void onChange(Damage damage){ ObjectHealth -= damage.damage; if(gameObject.tag == "Player") { HE.Invoke(ObjectHealth); // 放在这里可以正常触发 // SE.Invoke(EnemyScore); } if(ObjectHealth <= 0) { SE.Invoke(EnemyScore); // 这里无法触发监听逻辑 if(gameObject.tag == "Enemy") { EnemyScore = gameObject.GetComponent<Health>()._score; } Destroy(gameObject); } } } [System.Serializable] public class ScoreEvent : UnityEvent<float>{} public class HealthbarEvent : UnityEvent<float>{}
监听脚本ScoreLoader
using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; public class ScoreLoader : MonoBehaviour { private TMP_Text _tekst; private GameObject _player; private Health _h; void Awake() { _tekst = GetComponent<TMP_Text>(); } void Start() { _player = GameObject.Find("Player"); _h = _player.GetComponent<Health>(); _h.SE.AddListener(updateScore); _tekst.text = "0"; } void Update() { } void updateScore(float score) { Debug.Log("Primio sam ga. Jako"); } }
问题原因
- 事件实例不匹配:
ScoreLoader只监听了Player对象的Health组件中的SE事件,但敌人死亡时调用的是敌人自身Health组件的SE事件,这是两个完全独立的事件实例,自然无法触发Player那边的监听逻辑。 - 赋值顺序错误:即使解决了事件监听问题,当前代码中先调用
SE.Invoke(EnemyScore),之后才给EnemyScore赋值,传递的会是默认的0值,逻辑顺序完全颠倒。
解决方案
方案一:使用全局事件(推荐)
创建一个全局事件管理器,统一处理分数变更事件,避免对象间的耦合:
public static class EventManager { public static ScoreEvent OnScoreChanged = new ScoreEvent(); }
修改Health脚本的调用逻辑:
void onChange(Damage damage){ ObjectHealth -= damage.damage; if(gameObject.tag == "Player") { HE.Invoke(ObjectHealth); } if(ObjectHealth <= 0) { if(gameObject.tag == "Enemy") { EnemyScore = _score; // 直接用自身已赋值的_score,无需重复GetComponent } EventManager.OnScoreChanged.Invoke(EnemyScore); // 调用全局事件 Destroy(gameObject); } }
修改ScoreLoader的监听逻辑:
void Start() { _tekst = GetComponent<TMP_Text>(); EventManager.OnScoreChanged.AddListener(updateScore); _tekst.text = "0"; }
方案二:关联敌人与Player的事件(耦合性高,不推荐)
如果不想用全局事件,可在敌人的Health组件中找到Player的Health实例,将自身的SE事件触发逻辑绑定到Player的事件上,但这种方式会让敌人和Player的逻辑紧耦合,后期维护成本高。
必做修正:调整赋值顺序
无论采用哪种方案,都要先完成EnemyScore的赋值,再调用事件,确保传递的是正确的分数值。
内容的提问来源于stack exchange,提问作者mikloskristian
相关产品推荐
相关产品推荐

