探索 Unity 中的事件驱动编程:ScriptableObjects 与 UnityEvents

探索 Unity 中的事件驱动编程:ScriptableObjects 与 UnityEvents

在这里插入图片描述

介绍:

Unity 为开发人员提供了多种工具,用于在其项目中实现事件驱动编程。这些工具包括 ScriptableObjects 和 UnityEvents,两者都有相似的用途,但提供独特的优势和用例。
在本文中,我们将探讨 ScriptableObjects 和 UnityEvents 之间的差异,并提供有关何时使用每种方法的指导。

探索 ScriptableObjects:

ScriptableObjects 是 Unity 中的资产,可以保存数据并可以在项目的不同部分之间轻松共享。它们提供了一种灵活且解耦的事件处理方法,允许更复杂的交互和更高的可重用性。
有关 ScriptableObjects 的更多信息,请检查:

执行:

假设您正在创建一个简单的游戏,玩家可以在其中收集硬币,并且您希望使用 SO 的事件驱动编程来处理不同游戏元素之间的交互。

1.定义您的活动:

让我们定义两个事件:一个是玩家收集硬币时的事件,另一个是玩家的健康状况发生变化时的事件。
using UnityEngine;
using UnityEngine.Events;

[CreateAssetMenu(fileName = "CoinCollectedEvent", menuName = "Events/Coin Collected Event")]
public class CoinCollectedEvent : ScriptableObject
{
    public UnityEvent OnCoinCollected;

    public void TriggerEvent()
    {
        OnCoinCollected.Invoke();
    }
}

[CreateAssetMenu(fileName = "HealthChangedEvent", menuName = "Events/Health Changed Event")]
public class HealthChangedEvent : ScriptableObject
{
    public UnityEvent<int> OnHealthChanged;

    public void TriggerEvent(int newHealth)
    {
        OnHealthChanged.Invoke(newHealth);
    }
}

2. 创建事件监听器:

创建将响应这些事件的事件侦听器组件。
using UnityEngine;

public class CoinCollectedListener : MonoBehaviour
{
    public CoinCollectedEvent coinCollectedEvent;

    private void OnEnable()
    {
        coinCollectedEvent.OnCoinCollected.AddListener(RespondToCoinCollected);
    }

    private void OnDisable()
    {
        coinCollectedEvent.OnCoinCollected.RemoveListener(RespondToCoinCollected);
    }

    private void RespondToCoinCollected()
    {
        Debug.Log("Coin collected!");
        // Increase player's score, update UI, etc.
    }
}

public class HealthChangedListener : MonoBehaviour
{
    public HealthChangedEvent healthChangedEvent;

    private void OnEnable()
    {
        healthChangedEvent.OnHealthChanged.AddListener(RespondToHealthChanged);
    }

    private void OnDisable()
    {
        healthChangedEvent.OnHealthChanged.RemoveListener(RespondToHealthChanged);
    }

    private void RespondToHealthChanged(int newHealth)
    {
        Debug.Log("Health changed to: " + newHealth);
        // Update UI, check for game over conditions, etc.
    }
}

3. 触发事件:

现在,让我们创建将触发这些事件的组件。
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public CoinCollectedEvent coinCollectedEvent;
    public HealthChangedEvent healthChangedEvent;

    private int health = 100;
    private int score = 0;

    // Called when the player collects a coin
    public void CollectCoin()
    {
        score += 10;
        coinCollectedEvent.TriggerEvent();
    }

    // Called when the player's health changes
    public void ChangeHealth(int amount)
    {
        health += amount;
        healthChangedEvent.TriggerEvent(health);
    }
}

4. 使用 ScriptableObjects :

将事件实例创建为 ScriptableObjects 并在 Unity 编辑器中配置它们。

5. 连接事件和监听器:

在 Unity 编辑器中将适当的事件和侦听器组件相互分配。
现在,每当玩家收集硬币或他们的健康状况发生变化时,就会触发相应的事件,并且任何监听这些事件的组件都会做出相应的响应。这种设置使您的游戏逻辑保持解耦和灵活。

Unity活动:

让我们回顾一下前面的简单游戏示例,其中玩家收集金币及其生命值变化,但这次使用 UnityEvents 而不是 ScriptableObjects。

1.定义您的活动:

在这种情况下,我们将直接在将使用 UnityEvent 变量的组件中定义它们。
using UnityEngine;
using UnityEngine.Events;

public class PlayerController : MonoBehaviour
{
    // Define UnityEvents for coin collected and health changed
    public UnityEvent onCoinCollected;
    public UnityEvent<int> onHealthChanged;  

    private int health = 100;
    private int score = 0;

    // Called when the player collects a coin
    public void CollectCoin()
    {
        score += 10;
        onCoinCollected.Invoke(); // Invoke the coin collected event
    }

    // Called when the player's health changes
    public void ChangeHealth(int amount)
    {
        health += amount;
        onHealthChanged.Invoke(health); // Invoke the health changed event with the new health value
    }
}

2. 创建事件监听器:

创建将响应这些事件的事件侦听器组件。
using UnityEngine;

public class GameController : MonoBehaviour
{
    private void OnEnable()
    {
        // Subscribe to the coin collected event
        FindObjectOfType<PlayerController>().onCoinCollected.AddListener(RespondToCoinCollected);
        // Subscribe to the healthchanged event
        FindObjectOfType<PlayerController>().onHealthChanged.AddListener(RespondToHealthChanged);

    }

    private void OnDisable()
    {
        // Unsubscribe from the coin collected event
        FindObjectOfType<PlayerController>().onCoinCollected.RemoveListener(RespondToCoinCollected);
        // Unsubscribe to the healthchanged event
        FindObjectOfType<PlayerController>().onHealthChanged.RemoveListener(RespondToHealthChanged);

    }

    private void RespondToCoinCollected()
    {
        Debug.Log("Coin collected!");
        // Increase player's score, update UI, etc.
    }
    private void RespondToHealthChanged(int newHealth)
    {
        Debug.Log("Health changed to: " + newHealth);
        // Update UI, check for game over conditions, etc.
    }
}

3. 触发事件:

现在,每当玩家收集硬币或他们的健康状况发生变化时,就会触发相应的事件,并且任何监听这些事件的组件都会做出相应的响应。
using UnityEngine;

public class Coin : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // Call the CollectCoin method of the PlayerController
            other.GetComponent<PlayerController>().CollectCoin();
            Destroy(gameObject); // Destroy the coin object
        }
    }
}

public class Enemy : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // Call the ChangeHealth method of the PlayerController
            other.GetComponent<PlayerController>().ChangeHealth(-10); // Decrease health by 10
            Destroy(gameObject); // Destroy the enemy object
        }
    }
}
在此实现中,我们直接在 PlayerController 组件中使用 UnityEvents,并在单独的侦听器组件中侦听这些事件。
虽然这种方法减少了创建和管理 ScriptableObjects 等其他资产的需求,但它也将事件定义和事件侦听器紧密耦合在特定组件内。
根据项目的复杂性和规模,直接使用 UnityEvents 可能更适合组件之间更简单的交互和更紧密的耦合。
使用 ScriptableObjects (SO) 和 UnityEvents 都有各自的优点和用例。
使用 ScriptableObjects 和常规 UnityEvents 之间的主要区别之一。
对于 ScriptableObjects,您需要在要使用它们的每个脚本中显式引用它们。这可能会涉及更多的设置开销,因为您需要创建 ScriptableObject 的实例并在 Unity 编辑器中分配它们。
另一方面,使用常规 UnityEvents,您可以直接在脚本中创建和调用事件,而无需在 Unity 编辑器中单独引用它们。这可以使 UnityEvents 对于更简单的场景或当您不需要 ScriptableObjects 提供的解耦和灵活性级别时更加方便。

选择哪一个?

对于紧密耦合的组件之间的简单交互,UnityEvents 可能更合适,因为它们简单且具有直接绑定功能。
对于解耦、灵活性和可重用性很重要的更复杂的系统(例如为更大的项目实现强大的事件系统),ScriptableObjects 可能是更好的选择。
在许多情况下,您可能会发现这两种方法的组合是有益的,使用 UnityEvents 进行简单的组件内通信,使用 ScriptableObjects 进行更复杂的组件间交互。

最终,选择取决于游戏项目的具体要求和架构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小云同志你好

谁能书阁下,白首太玄经

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值