天天看點

Unreal Engine 4 —— Multi-Cast Delegate與觀察者模式的實作

這篇部落格介紹了UE4中的Multi-Cast Delegate的使用方法以及如何使用Multi-Cast Delgate實作觀察者模式。

Delegate

Delegate所起的作用是把一個對象與其函數綁定起來,進而産生一個可以全局調用的函數。在C#中已經内置了這樣的功能,但是在C++ 11中似乎并沒有一個很官方的實作。針對于在C++ 11中實作Delegate,可以參考這兩篇文章:Implementation of Delegates in C++11,The Impossibly Fast C++ Delegates

UE4中的Delegate

UE4針對于Delegate做了封裝,目前是使用宏來實作的(可能是由于曆史包袱?),可以實作高達8個變量的設定。關于UE4中的Delegate,對應的文檔已經講的很清楚了,傳送門。

觀察者模式

觀察者模式是個很有用的設計模式。簡短概括來說,觀察者模式指的就是當被觀察者改動後,會觸發這個被觀察者的所有觀察者的一個操作。具體設計模式的介紹和實作可以參考Head First Design Patterns和Game Programming Patterns。

應該來說,Multi-Cast Delegate本來就是為了觀察者模式而設計的,可以通過以下的方式來設計對應的觀察者和被觀察者。

被觀察者(Subject)

首先需要聲明一個對應的

Multi-Cast Delegate

,用于管理觀察者的事件:

DECLARE_MULTICAST_DELEGATE_TwoParams(OnSomethingChanged, float previousHP, float currentHP);
           

需要注意的是,UE4中的Delegate的聲明是使用宏來實作的,是以OnSomethingChanged不需要引号或者

TEXT("OnSomethingChanged")

之類的操作。

之後就可以在類中聲明對應的Delegate變量了,以下的例子是用于當主角的生命值改變的Delegate:

class AMainPlayerState: public APlayerState
{
    ...
    OnSomethingChanged onHPChanged;
}
           

此外,還需要一個入口,用于當生命值改變時候進行觸發的操作:

void ChangeHP()
    {
        // Do something important
        onHPChanged.Broadcast(previousHP, currentHP);
    }
           

觀察者(Observer)

觀察者Observer可以是任何東西 —— 可以是一個類,可以是全局上下文。我們可以把其綁定到某個Object的函數,也可以将其綁定到某個全局靜态函數。

以下的例子是用于當玩家生命值改變時,針對血條UI的操作,首先,在

BeginPlay()

方法中,将其注冊為玩家血量的觀察者:

void UPlayerHPUserWidget::BeginPlay()
{
    Super::BeginPlay();
    hpDelegateHandle = _mainPlayerState->onHPChanged.AddUObject(this, &UPlayerHPUserWidget::ReceiveHPChanged);
}
           

這裡,

ReceiveHPChanged

是一個

UPlayerHPUserWidget

的函數,接受兩個

float

參數,類型為

void

此外,當該UI被銷毀的時候,需要将這個widget從觀察者清單裡删除掉:

void UPlayerHPUserWidget::Destroyed()
{
    mainPlayerState->onHPChanged.Remove(hpDelegateHandle);
}
           

由于觀察者清單采用的是連結清單的操作,是以

Remove()

操作的時間複雜度是 O(n) ,代碼注釋中提到原有的Delegates的先後觸發順序可能會改變,這裡需要注意一下。

後記

設計模式這個東西雖然從大三就開始看了,但是也是到了接觸商業項目之後才能真正開始體會到設計模式的神髓。C++也不像Java或者C#一樣在語言層就内置了各種設計模式,很多都得自己去實作。真真是學無止境啊~~~

<全文完>

繼續閱讀