淺談Action

隨著熟練度,理解和實務應用上也會不同

在 Unity 遊戲開發中,可以使用 Action 和自定義 Delegate 來處理相同的事件或回調。下面將舉例說明如何使用這兩種方法來實現相同的功能,例如在角色進入觸發區域時觸發一個事件。

使用 Action

1. 定義 Action 並設置回調

首先,我們定義一個 Action 並設置回調方法:

using UnityEngine;
using System;

public class TriggerActionExample : MonoBehaviour
{
    // 定義一個 Action
    public Action OnPlayerEnter;

    private void Start()
    {
        // 設置回調方法
        OnPlayerEnter += PlayerEntered;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // 當玩家進入觸發區域時,調用 Action
            OnPlayerEnter?.Invoke();
        }
    }

    // 回調方法
    private void PlayerEntered()
    {
        Debug.Log("Player has entered the trigger area.");
    }
}

2. 使用 Action

將此腳本附加到有碰撞體(Collider)的遊戲物體上,並確保 Collider 被設置為 Is Trigger

使用自定義 Delegate

1. 定義委派和事件

首先,定義一個委派和一個事件,然後設置回調方法:

using UnityEngine;

public class TriggerDelegateExample : MonoBehaviour
{
    // 定義一個委派
    public delegate void PlayerEnterDelegate();

    // 定義一個事件,使用委派作為類型
    public event PlayerEnterDelegate OnPlayerEnter;

    private void Start()
    {
        // 設置回調方法
        OnPlayerEnter += PlayerEntered;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // 當玩家進入觸發區域時,觸發事件
            OnPlayerEnter?.Invoke();
        }
    }

    // 回調方法
    private void PlayerEntered()
    {
        Debug.Log("Player has entered the trigger area.");
    }
}

2. 使用自定義委派

將此腳本附加到有碰撞體(Collider)的遊戲物體上,並確保 Collider 被設置為 Is Trigger

總結

這兩個例子展示了如何在 Unity 中使用 Action 和自定義 Delegate 來實現相同的功能。在這兩種方法中,都使用了回調方法來處理玩家進入觸發區域的事件。Action 提供了一個更簡潔的方式來處理無返回值的回調,而自定義 Delegate 則提供了更多的靈活性,可以更好地描述特定的回調簽名。

在一些情況下,自定義委派(Delegate)比 Action 更靈活,因為它允許您描述更特定的回調簽名。例如,當您需要處理多個參數或返回特定類型的結果時,自定義委派能夠提供更強的類型安全和清晰度。以下是一個具體的例子來說明這種靈活性。

情況:需要處理多個參數並返回結果

假設我們正在開發一個角色扮演遊戲,需要在玩家撿起物品時觸發一個事件。這個事件需要傳遞物品的名稱和數量,並且返回一個布爾值,指示物品是否成功撿起。

使用 ActionFunc

在這種情況下,我們可以使用 Func 來處理多個參數並返回結果:

using UnityEngine;
using System;

public class PickupActionExample : MonoBehaviour
{
    // 定義一個 Func,接受兩個參數並返回一個布爾值
    public Func<string, int, bool> OnItemPickup;

    private void Start()
    {
        // 設置回調方法
        OnItemPickup += TryPickupItem;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // 當玩家進入觸發區域時,嘗試撿起物品
            bool success = OnItemPickup?.Invoke("Health Potion", 1) ?? false;
            if (success)
            {
                Debug.Log("Item successfully picked up.");
            }
            else
            {
                Debug.Log("Failed to pick up item.");
            }
        }
    }

    // 回調方法,嘗試撿起物品
    private bool TryPickupItem(string itemName, int quantity)
    {
        // 實際的物品撿起邏輯,例如檢查背包空間等
        Debug.Log($"Trying to pick up {quantity} of {itemName}.");
        return true;  // 假設物品總是能成功撿起
    }
}

使用自定義委派

現在,我們使用自定義委派來處理相同的場景。這樣可以提供更多的語義清晰度:

using UnityEngine;

public class PickupDelegateExample : MonoBehaviour
{
    // 定義一個委派,接受兩個參數並返回一個布爾值
    public delegate bool ItemPickupDelegate(string itemName, int quantity);

    // 定義一個事件,使用委派作為類型
    public event ItemPickupDelegate OnItemPickup;

    private void Start()
    {
        // 設置回調方法
        OnItemPickup += TryPickupItem;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            // 當玩家進入觸發區域時,嘗試撿起物品
            bool success = OnItemPickup?.Invoke("Health Potion", 1) ?? false;
            if (success)
            {
                Debug.Log("Item successfully picked up.");
            }
            else
            {
                Debug.Log("Failed to pick up item.");
            }
        }
    }

    // 回調方法,嘗試撿起物品
    private bool TryPickupItem(string itemName, int quantity)
    {
        // 實際的物品撿起邏輯,例如檢查背包空間等
        Debug.Log($"Trying to pick up {quantity} of {itemName}.");
        return true;  // 假設物品總是能成功撿起
    }
}

總結

  • ActionFunc:適用於大部分的情況,且代碼量較少。工作中遇到的案例完全使用Action來構建系統框架,我覺得是滿夠用的。
  • Delegate 自定義委派:在需要描述更具體的回調簽名的情況下提供更多靈活性和清晰度。自定義委派可以明確地命名和描述參數及返回類型,號稱使代碼更具可讀性。由於Delegate會使代碼量較多*2,為了減少代碼量,維持簡單易讀,使維護人員較為輕鬆,目前在 Unity專案中,比較少看到必需要用 Delegate的情況。

目前我負責維護的Unity遊戲,以使用Action居多。 下一篇將舉例 如何 使用 Action 實現跟 Func 相同的效果。

Tags: