简体   繁体   English

如何在 Unity/C# 中传递要添加到事件的函数?

[英]How do I pass a function to be added to an event in Unity/C#?

I am trying to create some inheritance class structures.我正在尝试创建一些继承类结构。 After learning about events, I wanted to use them in some way.在了解事件之后,我想以某种方式使用它们。 My intent is to have an abstract class that requires child classes to implement an OnDeath UnityEvent.我的意图是有一个抽象类,它需要子类来实现 OnDeath UnityEvent。 I have tried using System.Func and Delegates, but neither have worked for me.我曾尝试使用 System.Func 和 Delegates,但都没有为我工作。 I have included what I have tried, and the errors I received from trying those.我已经包括了我尝试过的内容,以及我在尝试这些内容时收到的错误。 Is there a way to have an abstracted function that lets me add a function to the event invoker?有没有办法让抽象函数让我向事件调用程序添加函数? Am I just overcomplicating the process?我只是让这个过程过于复杂吗?

To clarify: I am aware of the differing types, and why the types are resulting in this error.澄清:我知道不同的类型,以及为什么这些类型会导致此错误。 My question comes lies in what type I should be going with here.我的问题在于我应该在这里使用什么类型。 I have no idea what a Unity Action is, or how to even define such an object if I wanted to use it.我不知道 Unity Action 是什么,或者如果我想使用它,甚至如何定义这样的对象。

Using Delegates使用委托

EntityManager.cs with delegate

using UnityEngine;
using UnityEngine.Events;
using System;

public abstract class EntityManager : MonoBehaviour
{
    public EntityManager()
    {
        if (OnDeathEvent == null)
        {
            OnDeathEvent = new UnityEvent();
        }
        OnDeathEvent.AddListener(OnDeath);
    }
    public abstract bool IsAlive();
    public delegate void Function();
    public abstract void AddOnDeathListener(Function f);
    public abstract void OnDeath();
    public UnityEvent OnDeathEvent;
}
EnemyManager.cs with delegate

using System;

public class EnemyManager : EntityManager
{
    private Enemy _enemy;
    public Enemy Enemy { get => _enemy; set => _enemy = value; }

    private void Awake()
    {
        _enemy = new Enemy();

    }

    public override bool IsAlive()
    {
        return Enemy.IsAlive();
    }

    public void NextEnemy()
    {
        Enemy = new Enemy();
    }

    public override void OnDeath()
    {
        NextEnemy();
    }

    public override void AddOnDeathListener(Function f)
    {
        OnDeathEvent.AddListener(f);
        // cannot convert from 'EntityManager.Function' to 'UnityEngine.Events.UnityAction'
    }
}

Using Func使用功能

EntityManager.cs with Func

    public abstract void AddOnDeathListener(Func<object> f);

EnemyManager.cs with Func

    public override void AddOnDeathListener(Func<object> f)
    {
        OnDeathEvent.AddListener(f);
        // cannot convert from 'System.Func<object>' to 'UnityEngine.Events.UnityAction'
    }

Edit: Normal functions in Unity seem to create UnityAction objects, rather than generic Func objects, which is an extremely essential distinction to be made.编辑: Unity 中的普通函数似乎创建了 UnityAction 对象,而不是通用的 Func 对象,这是一个非常重要的区别。 By reframing the question through this lens, the accepted answer makes a lot of sense.通过这个镜头重新定义问题,公认的答案很有意义。

You should change the AddOnDeathListener method to take a UnityAction instead of a Func or anything else, because the AddListener method of the UnityEvent class takes a UnityAction delegate as an argument.您应该将AddOnDeathListener方法更改为采用UnityAction而不是Func或其他任何东西,因为UnityEvent类的AddListener方法采用UnityAction委托作为参数。

Your code in the abstract class should look like this:您在抽象类中的代码应如下所示:

 public abstract void AddOnDeathListener(UnityAction f);

   

UnityEvents are not the same thing as C# Events in the System namespace, and UnityAction are not the same thing as C# Actions in the System namespace. UnityEvents 与 System 命名空间中的 C# Events 不同,UnityAction 与 System 命名空间中的 C# Actions 不同。 But in your code you are mixing the two, with OnDeathEvent being in the UnityEngine.Events namespace and Func being in System .但是在您的代码中,您将两者混合在一起, OnDeathEventUnityEngine.Events命名空间中,而FuncSystem The reason you're having a compiler issue is that the UnityEvent.AddListener method takes a UnityAction argument, not a System.Func .您遇到编译器问题的原因是UnityEvent.AddListener方法采用UnityAction参数,而不是System.Func

To fix, you will either need to switch your OnDeathEvent to being a C# event, or change your AddOnDeathListener to take UnityAction as an argument.要修复,您需要将OnDeathEvent切换为 C# 事件,或者更改AddOnDeathListener以将UnityAction作为参数。

References:参考:

https://docs.unity3d.com/ScriptReference/Events.UnityEvent.AddListener.html https://www.jacksondunstan.com/articles/3335 https://docs.unity3d.com/ScriptReference/Events.UnityEvent.AddListener.html https://www.jacksondunstan.com/articles/3335

Code Sample:代码示例:

public class CoolAbstract : TestMeAbstract
{
    UnityEvent SomeKindOfEvent;

    private void Start()
    {
        SomeKindOfEvent = new UnityEvent();

        AddOnDeathListener(() => { Debug.Log("Cool Abstraction"); });
    }

    private void Update()
    {
        if(Input.GetKeyDown(KeyCode.A))
        {
            SomeKindOfEvent.Invoke();
        }
    }

    public override void AddOnDeathListener(UnityAction ua)
    {
        SomeKindOfEvent.AddListener(ua);
    }
}
public abstract class TestMeAbstract : MonoBehaviour
{
    public abstract void AddOnDeathListener(UnityAction ua);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM