You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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");
    }
}

问题原因

  1. 事件实例不匹配:ScoreLoader只监听了Player对象的Health组件中的SE事件,但敌人死亡时调用的是敌人自身Health组件的SE事件,这是两个完全独立的事件实例,自然无法触发Player那边的监听逻辑。
  2. 赋值顺序错误:即使解决了事件监听问题,当前代码中先调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:10:23