Torque脚本中的面向对象技术

来源:互联网 发布:动态血压仪数据怎么看 编辑:程序博客网 时间:2024/05/17 23:49

转自:http://blog.csdn.net/ybt631/archive/2007/07/17/1694348.aspx

 

.基本语法不同

1.    字符串的比较.                                                                 

C++中可以通过重载运算符实现比较,Torque Script则直接用$=!$=进行比较,或者通过脚本内置函数strcmp进行比较.

 

2.    变量表示

脚本中没有类型(实际上都是c++的字符串),即无须声明即可使用,并且变量的命名并不区分大小写.%var1%vaR1是一个变量.

变量有3种写法,分别是%前缀表示局部变量,只能在局部使用.$前缀表示全局变量,可以在任何地方使用.还有一种没有前缀的,类似于全局变量的使用,实际上在引用该变量的时候也可以加引号来表示.如下例子中的myClientConnection, myClientConnection是一回事.

 

new GameConnection(myClientConnection);

       if($JoinGameAddress!$="")

        myClientConnection.connect($JoinGameAddress);

    //等同于”myClientConnection”.connect($JoinGameAddress);

       else

myClientConnection.connectLocal();

这个例子new了一个GameConnection对象,然后调用他的方法connect连接到服务器.

 

还有一种标记字符串,如下例子可以说明它与一般字符串的不同之处.

              $testN='nihao'; //TGE会给标记符号和它的唯一标示数字

echo($testN);

$testN=StripMLControlChars($testN);

//这里可以去掉标记符号.

echo($testN);

          后面我们也会看到它的应用

 

3.字符串相加

Script中字符串相加用@, 例如:%myName@”你好

 

.脚本中的面向对象支持

这里主要通过OO的三个基本要素阐述脚本对于OO的支持程度.

1.    封装:

脚本支持在内置对象基础上添加成员变量和函数.但是并不支持自定义类

类似c++中 class myClass{};之类的声明是不存在的.

如下例中,AiPlayer的成员变量path和函数spawn(相对于c++中的类静态函数)

followPath(类成员函数)

function AIPlayer::spawn(%name,%spawnPoint)

{

        // Create the demo player object

        %player=new AiPlayer() {

                    dataBlock = DemoPlayer;

                   path ="";

              };

%player.followPath("MissionGroup/Paths/Path1",-1);

        MissionCleanup.add(%player);

        %player.setShapeName(%name);

        %player.setTransform(%spawnPoint);

        return%player;

}

 

function AIPlayer::followPath(%this,%path,%node)

{

           // Start the player following a path

        %this.stopThread(0);

        if (!isObject(%path)) {

                %this.path ="";

                return;

           }

        if (%node>%path.getCount() -1)

            %this.targetNode =%path.getCount() -1;

        else

            %this.targetNode =%node;

        if (%this.path $=%path)

            this.moveToNode(%this.currentNode);

       else {

            %this.path =%path;

            %this.moveToNode(0);

        }

}

 

脚本中有一个特殊的关键字,datablock,它类似与c++中的struct,当脚本被加载之后,

就会为该数据块分配内存,client连接到服务器的时候,所有的datablock都被发送到客户端.

 

2.   继承: 

脚本通过activatePackagedeactivatePackage实现了类似继承的机制.

最先加载的package作为父类接口.随后加载的作为其子类.以此类推.

在调用时,首先调用最底层的package.具体例子可以在demo工程中搜索activatePackage.

当一个被加载的脚本中,一个函数有多个实现时,会调用离最后被加载的那个函数实现.

 

3.   多态

脚本并不支持于c++多态类似的语法和功能.

 

.脚本重要函数和类介绍

1. commandToServercommandToClient函数

服务器和客户端通信的接口.其中前者是向服务器发包,后者是向客户端发.

如下例子:

commandToClient(%client, ‘sendMsg’, %text);

客户端负责接收clientCmdSendMsg(%text);

服务器端需要在前端加标示符serverCmd.

或者

commandToClient(%client, ‘sendMsg’, “%1:%2”, %userName, %msg);

类似于c中的sprintf语法.

2.exec(filename)

编译,执行函数,给变量赋值,加载程序包和数据块.

 

 

 

3.GameConnection

游戏连接类,UDP发包.类成员函数可以参考 开发大全书上的介绍.这里说一下它的脚本回调函数(通过引擎里面的Con::executef去调用).

C结尾的表示用于客户端回调,其他用于服务器回调

onConnectionTimedOut //C

onConnectionAccepted //C

onConnect

onConnectRequestTimedOut

onConnectionDropped //C

onConnectRequestRejected

onConnectRequest

onConnectionError //C

onDrop

initialControlSet //C

onDataBlocksDone

 

书写回调的一般格式如下:

function GameConnection::onConnectionTimedOut(%this)

{

   // Called when an established connection times out

   disconnectedCleanup();

   MessageBoxOK( "TIMED OUT", "The server connection has timed out.");

}

具体回调函数的参数,可以在引擎代码中进行查询.

 

.脚本基本实现原理

相关的宏定义:

DECLARE_CONOBJECT(myClass);    脚本类定义

IMPLEMENT_CONOBJECT(myClass); 脚本类声明

ConsoleMethod                                         脚本类方法定义.

 

ConsoleFunction                                       脚本全局函数定义

这里简单介绍一下c++实现脚本的二个重要方式:

 

1.   根据函数名调用c++中的函数:

关键宏:

#define ConsoleFunction(name,returnType,minArgs,maxArgs,usage1)                         /

static returnType c##name(SimObject *, S32, const char **argv);            /

static ConsoleConstructor g##name##obj                                  /         (NULL,#name,c##name,usage1,minArgs,maxArgs);                            /

static returnType c##name(SimObject *, S32 argc, const char **argv)

所有的函数都被简化成 returnValue scriptFun(SimObject *obj,int argc, char* argv[]);

根据不同的函数值定义不同的函数指针.主要以下5个函数指针的定义:

typedef const char * (*StringCallback)(SimObject *obj, S32 argc, const char *argv[]);

typedef S32           (*IntCallback)(SimObject *obj, S32 argc, const char *argv[]);

typedef F32         (*FloatCallback)(SimObject *obj, S32 argc, const char *argv[]);

typedef void         (*VoidCallback)(SimObject *obj, S32 argc, const char *argv[]);

typedef bool         (*BoolCallback)(SimObject *obj, S32 argc, const char *argv[]);

如果定义的是脚本全局函数,第一个参数为NULL.

 

ConsoleConstructor::first会把所有的对象通过一个链表串起来.根据函数名字找到相对应的函数指针,调用即可.

 

2.   根据类名new相应的类,mfc的机制类似.

关键宏

#define IMPLEMENT_CONOBJECT(className)                                         /

   AbstractClassRep* className::getClassRep() const                           /

{ return &className::dynClassRep; }                                        /

   AbstractClassRep* className::getStaticClassRep()                             /

{ return &dynClassRep; }                                                                   /

   AbstractClassRep* className::getParentStaticClassRep()                    /

{ return Parent::getStaticClassRep(); }                                          /

   ConcreteClassRep<className> className::dynClassRep                 /

(#className, 0, -1, 0, className::getParentStaticClassRep())

这个宏建立了一个类的层次.通过在构造函数中建立类之链表.

链表头定义如下:

AbstractClassRep *                 AbstractClassRep::classLinkList = NULL;

动态创建只需要一个个匹配,相等则调用create函数..

virtual AbstractClassRep* getClassRep() const得到该类的所有信息,比如类id,类名和子类,父类的AbstractClassRep.

通过构造ConcreteClassRep<T>类实现AbstractClassRep之相关接口.

通过virtual ConsoleObject*     create      () const = 0;去根据串名动态的创建对象.

 

原创粉丝点击