簡體   English   中英

Unity ScriptableObject、UnityEvent 和 GenericObject 的使用

[英]Unity ScriptableObject, UnityEvent & GenericObject usage

我想將ScriptableObjectUnityEvent和 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添加到特定的游戲組件,我將能夠以與訪問它們相同的方式訪問gameEventresponse ,就像我為 int 類型定義 UnityEvent 一樣。 然而,現實是我無法通過編輯器查看/訪問gameEventresponse

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

根據EventTemplateUnityEvent具體實現,這至少減少了每個繼承者對這兩個字段的實現開銷。

最后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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM