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

Unity任务系统中System.Action事件参数传递问题

解决Unity任务系统事件传参问题

一、带参数的System.Action正确实现

如果之前用System.Action没拿到参数,大概率是Action定义没带参数,或者订阅的方法签名不匹配。以下是正确的实现步骤:

1. 定义带参数的全局事件类

// QuestActions.cs
using System;

public static class QuestActions
{
    // 击杀敌人事件:传递被击杀的Enemy对象(可换成你需要的参数类型,比如敌人ID、枚举类型)
    public static Action<Enemy> OnEnemyKilled;
    // 空格键按下事件:传递累计按下次数
    public static Action<int> OnSpacebarPressed;
}

2. 触发事件时传入参数

// SpacebarPresser.cs
using UnityEngine;

public class SpacebarPresser : MonoBehaviour
{
    private int _pressCount = 0;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _pressCount++;
            // 调用事件时传入参数,用?.避免空引用
            QuestActions.OnSpacebarPressed?.Invoke(_pressCount);
        }
    }
}

3. 监听事件并接收参数

// QuestTracker.cs
using UnityEngine;

public class QuestTracker : MonoBehaviour
{
    void OnEnable()
    {
        // 订阅事件,方法签名必须和Action完全匹配
        QuestActions.OnSpacebarPressed += HandleSpacebarPress;
        QuestActions.OnEnemyKilled += HandleEnemyKill;
    }

    void OnDisable()
    {
        // 必须取消订阅,防止内存泄漏
        QuestActions.OnSpacebarPressed -= HandleSpacebarPress;
        QuestActions.OnEnemyKilled -= HandleEnemyKill;
    }

    // 处理空格键事件:接收传入的按下次数
    private void HandleSpacebarPress(int pressCount)
    {
        Debug.Log($"任务系统收到空格键按下{pressCount}次,更新任务进度");
        // 这里编写任务进度推进逻辑,比如累计次数达标后完成任务
    }

    // 处理敌人击杀事件:接收被击杀的敌人对象
    private void HandleEnemyKill(Enemy killedEnemy)
    {
        Debug.Log($"任务系统确认击杀敌人:{killedEnemy.enemyName}");
        // 比如判断敌人类型是否符合任务要求,再推进进度
    }
}

二、Scriptable Object事件(带参数)的正确实现

如果之前用SO事件没拿到参数,问题通常出在SO没有定义带参数的事件类型。以下是可行的实现:

1. 创建带参数的SO事件类

// EnemyKilledEventSO.cs
using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(fileName = "EnemyKilledEvent", menuName = "Events/Enemy Killed Event")]
public class EnemyKilledEventSO : ScriptableObject
{
    // 定义带Enemy参数的UnityEvent
    public UnityEvent<Enemy> OnEventTriggered;

    public void TriggerEvent(Enemy targetEnemy)
    {
        OnEventTriggered?.Invoke(targetEnemy);
    }
}

2. 在敌人脚本中触发事件

// Enemy.cs
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public string enemyName;
    // 在Inspector中拖入创建好的EnemyKilledEventSO实例
    public EnemyKilledEventSO enemyKilledEvent;

    public void TakeDamage(float damage)
    {
        // 假设血量归零后触发死亡
        if (GetComponent<Health>().CurrentHealth <= 0)
        {
            enemyKilledEvent.TriggerEvent(this);
            Destroy(gameObject);
        }
    }
}

3. 在任务追踪器中监听SO事件

// QuestTracker.cs
using UnityEngine;

public class QuestTracker : MonoBehaviour
{
    // 在Inspector中拖入对应的SO事件实例
    public EnemyKilledEventSO enemyKilledEvent;

    void OnEnable()
    {
        enemyKilledEvent.OnEventTriggered += HandleEnemyKill;
    }

    void OnDisable()
    {
        enemyKilledEvent.OnEventTriggered -= HandleEnemyKill;
    }

    private void HandleEnemyKill(Enemy killedEnemy)
    {
        Debug.Log($"任务系统检测到击杀:{killedEnemy.enemyName}");
        // 任务进度逻辑
    }
}

三、常见问题排查

  • 事件定义不匹配:确保Action/UnityEvent包含你需要传递的参数类型,比如Action<int>而非Action。
  • 方法签名错误:监听方法的参数数量、类型必须和事件完全一致,比如事件传Enemy,方法必须接收Enemy类型参数。
  • 调用时未传参:触发事件时必须传入对应参数,比如Invoke(pressCount)而不是空的Invoke()。
  • 订阅时机问题:尽量在OnEnable中订阅,OnDisable中取消订阅,避免对象激活顺序导致的订阅延迟。

内容的提问来源于stack exchange,提问作者Mavis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:04:52