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. I have tried using System.Func and Delegates, but neither have worked for me. 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?
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'
}
CodePudding user response:
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.
Your code in the abstract class should look like this:
public abstract void AddOnDeathListener(UnityAction f);
CodePudding user response:
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. But in your code you are mixing the two, with OnDeathEvent
being in the UnityEngine.Events
namespace and Func
being in System
. The reason you're having a compiler issue is that the UnityEvent.AddListener
method takes a UnityAction
argument, not a 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.
References:
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);
}