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: huawenguang@sina.com
================================================================================================================================