UnrealScript 函數(function)與狀態(State)的理解
作者:華文廣 日期:2011/9/22
1、在UDK下開發,function與event兩種函數聲明形式是一樣的,只有C++源代碼授權下用到native編碼時這兩個關鍵字才有所不同。因此在UDK下開發,建議統一用function來聲明函數,避免混淆。
2、在子類的函數中如果要調用父類的同名函數,使用super關鍵字。Super.functionname([parameters]),如:
function int FunCall()
{
`Log('in sub call!');
super.FunCall();
}
3、函數聲明時可以用Private,Protected,Public,Static,Final等關鍵定來限定其它類對本函數的訪問權限,這個和C++的定義是差不多的。當你需要在其它類中訪
問本類的公有函數時,要先對本類進行實例化。如:
class A extends Actor;
public function int Z(int D, int E)
{
return D + E;
}
//-----------------------------------------------------
class B extends Actor;
var A a_obj; //這裏是A類的變量聲明,在沒有實例化的時候,它相當於C++的一個空指針,是無效的。
private function G()
{
a_obj = Spawn(class'A'); // 生成一個A類實例對像。
a_obj.Z(3,4); //調用A類中的公有函數Z()
}
4、UnrealScript中使用了“狀態機”編程思想,每個Actor在某一時刻必定會處於某一個狀態之中。我們可以自定義Actor的狀態。我們可以在不同的狀態中定義相
同名字的函數。當我們在外部調用該Actor的同名函數時,UDK會根據Actor當前的狀態中所定義的那個函數,如:
class A extends Actor;
public function int Z(int D, int E) //函數1
{
return D * E;
}
state Add // 加狀態
{
public function int Z(int D, int E) //函數2
{
return D + E;
}
}
state Sub // 減狀態
{
public function int Z(int D, int E) //函數3
{
return D - E;
}
}
//-------------------------------------------------------------------
class B extends Actor;
var A obj;
private function G()
{
local int v;
obj = Spawn(class'A'); // 生成一個A類實例對像。
v = obj.Z(3,4); //函數1 v = 3*4;
obj.GotoState('Add'); //進入加狀態
v = obj.Z(3,4); //函數2 v = 3+4;
obj.GotoState('Sub'); //進入減狀態
v = obj.Z(3,4); //函數2 v = 3-4;
}
5、函數(function)及狀態(State)
初學UDK的時候,對函數(function)及狀態(State)這兩者之間的關係都十分困惑。
State,狀態。在UnrealScript裏面,它長得像一個結構體,但它的功能卻又像一個函數。State它有自已的代碼,可以在函數中調用,它也可以調用函數。
State和Function兩者到底有什麼區別呢?
既然State與Function的功能差不多,那什麼時候用State,什麼時候用function呢?爲什麼要用State呢?
要完全解答這些問題,我們首先要來理解一個非常關鍵的思想,那就是:“狀態(State)是每個Actor內部的一個獨立的線程”。這句話怎麼理解呢,就是說,UDK在遊戲啓動之後,它有一個主線程,主線程會在每幀刷新的時候,去調用場景中每個Actor的Tick()函數,我們可以在這個函數中做一些更新操作,如物理運算之類的。而每個Actor它都可以有一個自已內部的獨立線程,我們把這個線程叫做狀態線程。狀態線程就是用來運行State代碼的,它與主線程並行工作。如下圖所示。
我們來看一段代碼:
class CountNumActor extends Ator;
Var int SheepNum; //數綿羊個數
Var int StarNum; //數星星個數
event Tick (float DeltaTime)
{
StarNum++;
`Log(StarNum@“個星星”);
}
Auto State CountSheep
{
//好無聊呀,繼續數綿羊
Begin:
SheepNum++;
`Log(SheepNum@“個綿羊”);
Goto(‘Begin’);
}
這段代碼裏面的CountNumActor是一個深度失眠的Actor,主線程在數星星,狀態線程在數綿羊。在狀態線程中,我們用了一個goto(‘Begin’),其實就是一個不斷死循環的代碼,但它不會影響主線程的數星星,因爲兩個是並行的線程。
當我們能領會到“狀態是每個Actor內部的一個獨立的線程”這一中心思想後,面對前面的一些困惑,一下只也就豁然開朗了。
爲什麼在State裏可以運行代碼呢?那是爲了降低代碼偶合,更好在體現面向對像思想,一種“各人自掃門前雪”的指導思想,要求“自已的事情自已做”,比如說AI,它能在狀態線程中自動在不斷地去搜尋敵人,找到敵人後自動開火射擊。又比如說一些Actor要用到TCP網絡通信來傳輸大塊數據。在網絡擁堵的時候響應可能很慢,這時我們就可以用State線程來慢慢等待,而不會影響主線程的更新速度,從而保證遊戲整體畫面的流暢性。
當然,上面說的是爲什麼State能像函數一樣運行自已的代碼,但當你更深入地去了解UnrealScript的時候,你會發現,很多State內沒有在執行代碼,其實State最核心的作用,就是用來記錄Actor當前正處於哪一個狀態之中,在這種狀態之下,這個Actor能做什麼和不能做什麼,我們都可以在State裏進行約束,另外,每個State裏面都有這兩個函數BeginState(),EndState(),前者是在我們每次進入這個狀態的時候自動運行,後者是在我們退出這個狀態的時候自動運行。這樣我們可以在每個State裏繼承和覆蓋這兩個函數,從而實現一些在進入狀態時候的初始化工作及退出狀態時候的清理工作。
這裏主要是理清一下Function與State的兩者之間的關係,關於狀態(State)及狀態機,其它還有很多更深入的應用,網上有很多資料,這裏不打算深入去討論。
E-MAIL: [email protected]
================================================================================================================================