[英]Unity ScriptableObject, UnityEvent & GenericObject usage
我想將ScriptableObject
與UnityEvent
和 GenericObject 的用法結合起來。 我的最終目標是創建通用事件和偵聽器,然后使用 ScriptableObject 創建特定事件,例如 GameObject、int 等,並使用相應的偵聽器處理這些事件。 這是我到目前為止的代碼: EventTemplate.cs
using System.Collections.Generic;
using UnityEngine;
public class EventTemplate<T> : ScriptableObject {
private List<ListenerTemplate<T>> listeners = new List<ListenerTemplate<T>>();
public void Raise(T go) {
for (int i = listeners.Count - 1; i >= 0; i--) {
listeners[i].OnEventRaised(go);
}
}
public void RegisterListener(ListenerTemplate<T> listener) {
listeners.Add(listener);
}
public void UnregisterListener(ListenerTemplate<T> listener) {
listeners.Remove(listener);
}
}
監聽模板.cs
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class ResponseEvent<T> : UnityEvent<T> { }
public class ListenerTemplate<T> : MonoBehaviour {
//[SerializeField]
public EventTemplate<T> gameEvent;
//[SerializeField]
public ResponseEvent<T> response;
private void OnEnable() {
gameEvent.RegisterListener(this);
}
private void OnDisable() {
gameEvent.UnregisterListener(this);
}
public void OnEventRaised(T go) {
response.Invoke(go);
}
}
現在,當我擁有這兩種泛型類型時,我為int
類型創建了一個事件和一個偵聽器。 這是兩個文件:
EventInt.cs
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Event Template", menuName = "Stage Management/Event Templates/Event Int")]
public class EventInt : EventTemplate<int> {
}
和ListenerInt.cs
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class ResponseInt : ResponseEvent<int> { }
public class ListenerInt : ListenerTemplate<int> {
}
然后我的期望是,一旦我通過編輯器將ListenerInt.cs
添加到特定的游戲組件,我將能夠以與訪問它們相同的方式訪問gameEvent
和response
,就像我為 int 類型定義 UnityEvent 一樣。 然而,現實是我無法通過編輯器查看/訪問gameEvent
或response
。
Unity 序列化不適用於泛型T
。
您需要為要在 Inspector 中序列化的所有內容明確創建繼承的非泛型類型。 你需要例如一個
[Serializable] public class IntEvent : UnityEvent<T> { }
為了能夠序列化它。
為了做你想做的(有點)我會這樣做:
首先使用類似的interface
public interface IEventListener<in T>
{
void OnEventRaised(T value);
}
然后讓你的ListenerTemplate
public abstract class ListenerTemplate<T> : MonoBehaviour, IEventListener<T>
{
// These have to be provided by the inheritor
public abstract UnityEvent<T> unityEvent { get; }
public abstract EventTemplate<T> gameEvent { get; }
private void OnEnable()
{
gameEvent.RegisterListener(this);
}
private void OnDisable()
{
gameEvent.UnregisterListener(this);
}
public void OnEventRaised(T value)
{
unityEvent.Invoke(value);
}
}
正如您所看到的,任何從ListenerTemplate<T>
繼承的類都必須以某種方式同時提供UnityEvent<T>
和EventTemplate<T>
。
所以例如
// The specific scriptable object doesn't change it just inherits
[CreateAssetMenu(fileName = "New Event Template", menuName = "Stage Management/Event Templates/Event Int")]
public class EventInt : EventTemplate<int>{ }
和
// Specific override for the UnityEvent
[Serializable] public class IntUnityEvent : UnityEvent<int> { }
public class ListenerInt : ListenerTemplate<int>
{
[SerializeField] private EventInt eventInt;
[SerializeField] private IntUnityEvent intUnityEvent;
// override and populate the two abstract properties
// with the references from the serialized fields
public override UnityEvent<int> unityEvent => intUnityEvent;
public override EventTemplate<int> gameEvent => eventInt;
}
根據EventTemplate
和UnityEvent
具體實現,這至少減少了每個繼承者對這兩個字段的實現開銷。
最后EventTemplate<T>
只需要使用IEventListener
列表代替
public abstract class EventTemplate<TValue> : ScriptableObject
{
private readonly List<IEventListener<TValue>> listeners = new List<IEventListener<TValue>>();
public void Raise(TValue go)
{
// actually why iterate backwards?
for (int i = listeners.Count - 1; i >= 0; i--)
{
listeners[i].OnEventRaised(go);
}
}
public void RegisterListener(ListenerTemplate<TValue> listener)
{
listeners.Add(listener);
}
public void UnregisterListener(ListenerTemplate<TValue> listener)
{
listeners.Remove(listener);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.