相信我,最好的文档是它引擎自带的Documentation
自带的Demo结构介绍:
Root Directory:
Root/generateAllProjects.bat:运行此文件将创建所有列举在allProjects.txt中的VC工程,在读取工程列表后,此文件将生成工程和解决方案并放到buildFiles文件夹下
Root/allProjects.txt:工程列表
Root/compileAllProjects.bat:运行此文件将编译allProjects.txt中的所有工程
Root/syncShrdConsts.bat:不清楚
Root/Documentation:文档
Root/Engine:包含了TGEA的核心源码,
../bin:包含对高级开发有用的可执行工具如doxygen,nasm assmebly.etc等
../lib:包含编译Torque工程所需要的库,如果要添加其它库可以添加到此文件夹
../Source:此文件夹包含了所有组成TGEA的源代码,以模块的形式组织起来
Root/GameExamples:此文件夹下面的每个文件夹包含一个独立的demo,第个示例都显示了TGEA的特性,你可以在这里创建工程
../AtlasDemo:
../TGEDemoAdvanced:
../Forge:
../Stronghold:一个FPS示例
../T3D:
进入一个Demo以后
/DeleteDSOs.bat:删除子文件夹中所有.dso文件
/DeletePrefs.bat:删除所有preference文件,这些文件通常包含一些如屏幕解析度,声音级别之类的信息
/generateProjects:
/source:
/buildFiles:包含的是工程和解决方案,你可以用VC将它们载入时行编译,也可使用compile.bat在命令行进行编译
/config:包含一些将被其他程序调用的配置信息,如engineDoc.conf是用于Doxygen来产生相关文档的。
/Game:包含了所有组成Game的内容包括脚本(scripts),GUIs,assets,editors
/Game/common:此文件夹与scriptsAndAssets相似,但是此文件夹中的内容是被所有的Game工程共享的,也就是说每个Game中都有这个文件夹且内容相同
/Game/profile:此文件夹中的脚本用于检查你的图形卡与引擎的兼容性
/Game/shaders:此文件夹将存储所有的hlsl文件,可以根据不同的功能建立子文件夹来分类不同的shaders
/Game/scriptsAndAssets:你的game的大部分内容将在这个文件夹中,通常这个文件夹分成client,server,data三个子文件夹
../client:你的客户端脚本和数据将存储在此,通常是逻辑方面和GUIs且不被多个玩家所共享的比如一个选择菜单,或者是动作脚本,在Stronghold中,脚本和输入绑定逻辑及任务被存储在文件夹“scripts”中,GUIs和图片存储在文件夹“ui”中
../data:与游戏场景相关的一切东西将在这里找到,如:3D模型,环境数据(天空,地形),声音文件等,其中,DTS文件用于呈现3D模型,存储在“shapes”文件夹,DIFF文件包含建筑和内景模型,存储在"interiors"文件夹中,OGG和WAV文件为音效文件存储在文件夹"sound"中,
../server:服务器端功能和脚本,
/Game/tools:你的GUI editor,debugger及其他工具,这些将影响到每一个玩家,在你的开发过程中将有大量的时间花在处理这个文件夹上,这个文件夹包含用于建立player,AI,weapon,network connection,core game logic等的脚本
建立自己的游戏工程,使用SetupNewProject.exe
SetupNewProject.exe打开后,只需要改动第一项工程名,后面两项不要改。
以前的toturial.base就是现在的scriptsAndAssets文件夹
MyGame.exe 必须与main.cs放在一起
TorqueScript的运行原理?
TorqueScript与c++工程如何配合工作?
TorqueScript将不同功能放到不同文件夹的cs文件中,然后通过exec加载,可将其理解为模块化设计,当需要添加某些功能模块时候,直接添加相关功能的程序保存在.cs文件中。
总是载入文件后执行其中的功能,载入的过程中遇到语句就执行遇到函数则"编译",后面可以调用
如有一个文件test.cs
内容为:
function ontest()
{
echo("hello world");
}
我想使用ontest函数,如下
exec("test.cs");//相对或绝对路径
ontest();
NL相当于/n
/*********************************************************************************************************/
看看scriptAndAssets的main.cs中做了些什么:
loadDir("common");
这个函数定义在root目录下的main.cs中:
执行顺序,先从root目录下的
main.cs
开始执行,经过一些 函数声明和变量赋值,执行到
loadMods($userMods);
执行exec(%token @ "/main.cs")实际上的参数是scriptAndAssets/main.cs,即加载了scriptAndAssets/main.cs
这样就遇到了loadDir("common"),而这个是在root/main.cs中定义的:
function loadDir(%dir)
{
setModPaths(pushback($userMods, %dir, ";"));
exec(%dir @ "/main.cs");
}
其中的exec(%dir @ "/main.cs")又加载了common/main.cs
回到loadMods又exec(%token @ "/main.cs"),加载了tools/main.cs,接着调用
parseArgs(),内容为空
属于root/main.cs中,分析命令行参数,接着调用
onStart(),内容为空
属于root/main.cs文件
脚本通过activatePackage和deactivatePackage实现了类似继承的机制.
最先加载的package作为父类接口.随后加载的作为其子类.以此类推.
在调用时,首先调用最底层的package.具体例子可以在demo工程中搜索activatePackage.
当一个被加载的脚本中,一个函数有多个实现时,会调用离最后被加载的那个函数实现
重新整理
首先是root/main.cs开始执行
接着是common的main.cs
接着是scriptAndAssets的main.cs
然后是tools/main.cs
调用结构为:
root/main.cs{
loadMods(){
loadMods{
exec("scriptAndAssets/main.cs"){
loadDir("common"){
exec("common/main.cs"){
}
}
}
}
exec("tools/main.cs");
}
}
接着执行parseArgs(),注意到前面的几个main.cs中又几个package并且activatePackage了,
根据“继承机制”,因此应该先调用最后加载的那个,应该是scriptAndAssets/main.cs中的parseArgs了,然后是common中的main.cs中的parseArgs
同理的还有OnStart()和onExit()等
其中的parent::代表的是前一个包,例如按照加载顺序,依次是/scriptAndAssets/main.cs,/common/main.cs,/root/main.cs,
因而/common/main.cs的parseArgs中的parent指的是scriptAndAssets/main.cs中的内容,以此类推
如OnStart(),先是调用/scriptAndAssets/main.cs中的OnStart,他的Parent指的是/common/main.cs,因此parent::OnStart调用的是/common/main.cs/OnStart,而他的Parent又指的是root/main.cs,因此又调用root/main.cs/OnStart
最终的执行顺序是root/main.cs/OnStart(),/common/main.cs/OnStart(),scriptAndAssets/main.cs/OnStart()
了解之后,看到的是parseArgs被调用
common/main.cs/parseArgs{
scriptAndAssets/main.cs/parseArgs{
root/main.cs/parseArgs{
//没有特别内容,只是对命令行参数进行判断,以对相关变量进行设置
}
}
}
接下来调用了OnStart(),此函数的调用顺序与前面的parseArgs相同
scriptAndAssets/main.cs/OnStart
{
common/main.cs/OnStart
{
root/main.cs/OnStart
{
//空
}
initDisplayDeviceInfo();
...
exec(common/gameScripts/common.cs);
initializeCommon();//这里面有不少内容
{
/**************************************/
if( $commonInitialized == true )return;
GlobalActionMap.bind(keyboard, tilde, toggleConsole);
GlobalActionMap.bind(keyboard, "ctrl p", doScreenShot);
GlobalActionMap.bindcmd(keyboard, "alt enter", "Canvas.toggleFullScreen();","");
GlobalActionMap.bindcmd(keyboard, "alt k", "cls();", "");
GlobalActionMap.bindCmd(keyboard, "escape", "", "handleEscape();");
exec("./audio.cs");exec("./canvas.cs");exec("./cursor.cs");exec("~/gui/profiles.cs");exec("~/gui/cursors.cs");
setRandomSeed();setNetPort(0);
initializeCanvas("Torque Game Engine Advanced");//这个要注意一下,canvas.cs中定义的
{
/**************************************/
if($canvasCreated)
{
error("Cannot instantiate more than one canvas!");
return;
}
if (!createCanvas(%windowName))//在root/main.cs中
{
error("Canvas creation failed. Shutting down.");
quit();
}
$canvasCreated = true;
/**************************************/
}
// Common Guis.
exec("~/gui/remap.gui");exec("~/gui/console.gui"); exec("~/gui/help.cs");exec("./screenshot.cs");
exec("./scriptDoc.cs");exec("./keybindings.cs"); exec("./helperfuncs.cs");
exec("~/clientScripts/metrics.cs"); exec("~/clientScripts/recordings.cs");
exec("~/clientScripts/shaders.cs"); exec("~/clientScripts/materials.cs");
Canvas.setCursor(DefaultCursor); loadKeybindings();
$commonInitialized = true;
}
/**************************************/
exec("common/unifiedShell/main.cs");
{
/**************************************/
exec("unifiedShell/profiles.cs");
exec("unifiedShell/MainMenuGui.cs");
exec("unifiedShell/OptionsGui.cs");
exec("unifiedShell/OptionsGui.gui");
exec("unifiedShell/GamepadButtonsGui.cs");
exec("unifiedShell/GamepadButtonsGui.gui");
exec("unifiedShell/ObjectPickerGui.cs");
exec("unifiedShell/ObjectPickerGui.gui");
/**************************************/
}
exec("common/clentScripts/client.cs");
exec("common/clentScripts/server.cs");
exec("common/gui/guiBreadcrumbsMenu.cs");
}//common/main.cs/OnStart
/*************Initializing MOD: FPS****************/
exec("scriptAndAssets/client/defaults.cs");//缺省配置
exec("scriptAndAssets/server/defaults.cs");
exec("scriptAndAssets/client/prefs.cs");//偏好配置
exec("scriptAndAssets/server/prefs.cs");
exec("scriptAndAssets/client/init.cs");//应该是加载初始化的内容
/*************函数名如下***************/
loadMaterials()
reloadMaterials()
initClient()
loadPlayerPickerData()
loadDefaultMission()
loadMainMenu
/**************************************/
exec("scriptAndAssets/server/init.cs");
/*************函数名如下***************/
initServer()
initDedicated()
/**************************************/
sfxStartup()//common中的,start up the audion system
initServer();
{
initBaseServer();//来自common/server.cs,加载了大量内容
exec("server/scripts/commands.cs");
{
serverCmdToggleCamera()
serverCmdDropPlayerAtCamera()
serverCmdDropCameraAtPlayer()
serverCmdSuicide()
serverCmdPlayCel()
serverCmdPlayDeath()
serverCmdSelectObject()
}
exec("server/scripts/game.cs");
{
//game相关控制,如游戏持续时间,结束所需分数参数设置和Functions that implement game-play
}
}
if ($Server::Dedicated)
initDedicated();
else
initClient();//客户端初始化,来自scriptAndAssets/client/init.cs
{
// The common module provides basic client functionality
initBaseClient();
// Use our prefs to configure our Canvas/Window
configureCanvas();//这个
//设置窗口标题
if (isObject(Canvas))
Canvas.setWindowTitle(getEngineName() @ " (" @ getVersionString() @ ") - " @ $appName);
/// Load client-side Audio Profiles/Descriptions
exec("./scripts/audioProfiles.cs");
}
}
Torquescript基础
Objects:
游戏世界的每个item都是对象,这些对象是用C++定义的但可以通过script访问
对象创建语法:
%var = new ObjectType(Name:CopySource,arg0,..,argn)
{
<datablock = DatablockIdentifier;>
[existing_field0 = InitialValue0;]
...
[existing_fieldM = InitialValueM;]
[dynamic_field0 = InitialValue0;]
...
[dynamic_fieldN = InitialValueN;]
}
%var: 用于存储对象句柄
ObjectType:任何定义在引擎或脚本中的从SimObject或者SimObject的子类,从simObject派生的成为游戏世界的物
CopySource:是这个对象的名字,它是个字符串而不是一个变量,不用&或%
arg0,...,argn:是构造函数的参数
datablock: 许多对象(从GameBase派生或GameBase的子类)需要一个datablocks来初始化相关属性
existing_fieldM datablock:相关值或对象的相关属性,existing_field0 = InitialValue0,也就是对这两种属性进行初始化
dynamic_fieldN:创建的新的属性(将只存在于脚本中)
句柄(handles)和名称(names):
每个对象都对应着唯一的句柄值,但对象名不一定唯一,如果你又多个对象拥有相同的名字,那么在你引用那个名字只能找到其中的一个
属性(fields)和命令(commands)
脚本中的fields和commands相当于c++中的对象成员和方法,访问成员使用"."运算符
TorqueScript允许创建动态属性,动态属性与一个对象的实例相联系,并且可以随意的添加和删除,添加一个动态属性是自动的,如果你试图读取一个不存在的属性将返回空,也没有动态属性被创建,然而当你试图写入一个不存在的属性时,一个匹配的动态属性将被创建,且被赋值
同样的,还支持函数的动态添加。
包(Packages)
创建语法
package package_name()
{
function function_definition0()
{
....
}
...
function function_definitionN()
{
...
}
}
需要注意的是:
一个函数可以再多个packages中被定义
一个packages中只能包含函数
datablocks不能包含在包中
用ActivatePackage(package_name)来激活包,用DeactivatePackage(package_name)来使包无效
命名空间(Namespaces)
可以在不同的空间定义相同的函数,引用时你将手动选择调用哪个命名空间的函数或者自动调用。
如果你使用::建立一个函数,这并不意味着这个函数属于某个命名空间,如果::前的表达式不是一个类名或空间名,你将创建的只是一个唯一的函数名