Torque 3D 入门:引擎架构、启动流程与脚本调试

发布时间:2026/10/25 11:38:01
Torque 3D 入门:引擎架构、启动流程与脚本调试 简介《Torque3D规范及说明书》是一份面向Torque 3D游戏引擎初学者与进阶开发者的中文技术文档重点解决引擎框架理解、脚本入门与项目调试缺少系统参考的问题。文档从游戏服务器端、客户端及运行调用过程讲起涉及网络通信、状态同步、图形渲染和界面交互并延伸到UI编辑、世界地图编辑与游戏脚本编辑同时整理常用命令、语法规则、变量声明和物体定义等脚本基础适合原型开发、引擎学习与团队内部查阅。资源包共1个doc文件约442KB体量轻便便于本地保存和关键词检索。已有246人学习说明其在Torque3D中文资料中具备一定参考价值。读者可据此梳理引擎运行脉络理解服务端与客户端的分工并对照脚本语法、对象定义和模块说明建立较完整的学习框架减少初期摸索成本。1. 搜 Torque 3D 入门的人先别急着关掉网页搜 Torque 3D 入门的人十有八九点进官网之后会先愣三分钟下载页、文档页、论坛页全是英文不清楚该从哪看起甚至不确定自己下载的到底是不是一个完整的游戏引擎。其实可以先把它想成一套宜家柜子——板子切好了孔打好了螺丝配齐了图纸也附上了你要做的不是种树炼铁而是照图纸把柜子装起来。Torque 3D 就是一个把渲染、网络连接、碰撞判断、界面按钮这些底层活儿提前打好包的 3D 游戏引擎你上手写的是脚本描述“谁站在哪、按下某个键之后发生什么”。这份《Torque3D 规范及说明书》相当于那张图纸它把引擎拆成 UI 编辑、世界地图编辑、游戏脚本三块还专门写了一件事引擎启动时到底先读哪个文件。对零基础的人来说这一点很重要——很多教程上来就贴一堆代码却不说清楚这些代码该放进哪个目录、由谁调用照着抄也只能停在照抄。这份说明书没绕这个弯它先把框架摊开给你看再讲语法、变量、物体定义顺序正适合新手。2. 拆分引擎的两半服务器端六个模块和客户端七个模块新手看引擎架构图最容易犯的错是把它当成一份“背诵材料”想着一口气全记下来。真没必要。你只需要先建立一个大印象这个引擎跑起来有两半一半负责“算”一半负责“显示”。负责算的叫服务器端负责显示的叫客户端。哪怕你只打算做单机小 demo这两半也照样都在只是跑在同一台机器上而已。把这两半的分工弄明白后面写脚本时你才知道该把代码往哪个文件里放。2.1 服务器端那六个模块各管哪一摊Network Server 网络服务模块。它负责服务器与所有客户机之间的连接和数据传输也负责版本升级这类事务。把它想成小区门口的传达室所有进出的人、送来的包裹都得从这儿过一遍。你以后遇到“连不上”“延迟高”“版本对不上”这类问题第一个该怀疑的就是它。World Map 世界地图模块。服务器端也会载入一份地图镜像在服务器上模拟出一个跟客户端看起来差不多的场景。它的用途不是给玩家看而是用来算碰撞、判断谁撞到了谁。相当于裁判手里那套场地模型——球员看到的是球场裁判看的是同一块场地的尺寸和边界谁踩线了裁判说了算。这样做的好处是所有客户机看到的位置和时间能尽量保持一致。Database Connection 数据库连接模块。它负责让游戏内的数据和数据库保持同步与及时更新。你可以把它当账本玩家攒了多少金币、买了什么装备光存在内存里一关服就没了所以要写进数据库。ServerCommand 服务器执行命令。客户机发来的可执行命令比如移动、攻击最终都在这里被处理。玩家在客户端按了一下键服务器接收后执行对应动作这个模块就是执行动作的那个环节。Message 客户消息处理。它负责转发和记录客户机之间、客户机与服务器之间的消息聊天功能主要靠它。要是你想过“游戏里的聊天框是怎么实现的”答案就在这儿。Object Data 对象数据处理。场景里所有的 Player、AIPlayer、物品它们的动作、碰撞、特效全都归这个模块控制和处理。这是六个模块里你日后打交道最频繁的模块——改角色属性、加一个新道具最后基本都落到这里定义的数据上。2.2 客户端那七个模块画面是怎么来的Canvas 画面显示处理模块。它管的是整个游戏窗口的显示设置显示驱动类型、分辨率、色深这些。相当于投影仪的设置菜单先得把投影仪调对画面才谈得上好不好看。Gui 用户交互界面模块。从游戏开始到结束所有可见的画面、按钮都归它。主菜单、血条、背包格子玩家眼睛能点能看的东西基本都在这个范畴里。Action Map 行为动作模块。它是一张映射表哪个功能键对应哪个操作。你按下 W 角色往前走按 Esc 弹出菜单背后就是这张表在把“按键”翻译成“动作”。ServerConnection 服务器连接模块。它是客户端与服务器之间的桥所有游戏信息都要经它传输交换。桥断了客户端就成了一个只会放画面的空壳。ClientCommand 客户端命令执行模块。方向跟 ServerCommand 相反服务器让客户端做的事比如让某个角色坐下从这里下来执行。一个管“往上发”一个管“往下发”别记混。Message 服务器消息处理模块。收到服务器消息之后负责显示和提示。你在屏幕中央看到的系统公告多半是从这儿出来的。World Map 世界地图模块。载入服务器指定的地图并负责地图的显示和相应处理。注意它跟服务器端那个 World Map 名字一样、活儿不一样那边算碰撞这边管显示。2.3 为什么新手也要懂这个一次“按键开枪”的旅行光看模块名没什么感觉我们跟着一次按键走一遍。玩家在客户端按下开火键Action Map 先查表确认这个键对应“开火”客户端把这个意图通过 ServerConnection 发出去服务器端的 ServerCommand 接到命令交给 Object Data 去算这一枪打没打中、撞到了什么算完之后Message 把结果广播给相关客户机客户端收到消息由 Canvas 和 Gui 把开火特效、血量变化画到屏幕上。一条链走下来可能只花了几十毫秒。这条链的意义在于以后你想改任何一个环节都得先知道它挂在哪。想改按键去 Action Map想改伤害算法去 Object Data 相关的数据定义想改命中提示的显示去客户端 Message。不知道这条链改代码就是碰运气改完不知道为什么不生效也不知道为什么突然好了。注意单机跑 demo 的时候服务器端和客户端在同一台机器上你可能感觉不到它们的存在。但只要涉及网络这两半的分工就变得非常实在改动之前先想清楚这段逻辑该在哪一边。3. 跟着启动流程走一遍从 exe 到 main.cs 的那几行代码环境搭好之后最劝退的一步是不知道该改哪个文件。这一章就解决这件事。双击游戏可执行文件之后引擎不是满硬盘找脚本它有一条固定的路线。路线走通了你后面所有的改动才有落点。这段代码用的是 TorqueScript语法接近 C 和 JavaScript下面代码块按 javascript 着色只是为了看着顺眼。3.1 双击 exe 之后引擎第一眼找的是 main.cs主目录下有一个 main.cs它是整场游戏的起点。里面干的事不复杂把要用的游戏目录登记进去然后逐个执行这些目录下的 main.cs。$defaultGame starter.fps; // 默认游戏目录名 // 把某个目录登记进引擎的模块搜索路径再执行该目录下的 main.cs function loadDir(%dir) { setModPaths(pushback($userMods, %dir, ;)); // 往分号分隔的路径列表尾部追加 exec(%dir /main.cs); // 是字符串拼接 } // 递归拆开分号分隔的路径列表逐个执行其中的 main.cs function loadMods(%modPath) { %modPath nextToken(%modPath, token, ;); // 切出第一段路径和剩余部分 if (%modPath !$ ) loadMods(%modPath); // 还有剩余就继续递归 if (exec(%token /main.cs) ! true) $modcount--; // 执行失败就把计数减一 } loadMods($userMods); // 正式启动这段代码里几个关键点值得记住。$userMods是全局变量装着以分号分隔的目录列表pushback往列表尾部追加一项nextToken按分隔符把字符串切成第一段和剩余部分注意第二个参数写的是token不带 % 前缀这是这个函数要求的特殊写法exec执行一个脚本文件返回值可以拿来判断成功与否是字符串拼接跟加号不是一回事后面讲变量时还会专门说。%dir、%modPath这些以 % 开头的都是局部变量只在函数内部有效。$defaultGame、$userMods、$modcount以 $ 开头是全局变量。这套前缀规则是 TorqueScript 最基础的一条记不住它后面看代码会很吃力。3.2 进到游戏目录看 package StarterKit 里那两个函数轮到游戏目录下的 main.cs 干活时第一件事通常是加载 common 目录那里放的是基本命令、函数和 GUI 文件。接着你会看到一个 package 块里面包着onStart和onExit两个函数。package StarterKit { function onStart() { Parent::onStart(); // 必须调用引擎内部初始化 // 依次载入客户端、服务器、数据三套脚本 exec(./client/init.cs); exec(./server/init.cs); exec(./data/init.cs); // 服务器对所有会话都要启动因为客户端也能在游戏内开服 initServer(); // 二选一专用服务器模式还是客户端模式 if ($Server::Dedicated) initDedicated(); else initClient(); } function onExit() { export($pref::*, ./client/prefs.cs, False); // 保存客户端设置 if (isObject(moveMap)) moveMap.save(./client/config.cs, false); // 保存改过的按键映射 export($Pref::Server::*, ./server/prefs.cs, False); // 保存服务器设置 BanList::Export(./server/banlist.cs); // 导出封禁名单 Parent::onExit(); // 必须调用释放资源 } }几个容易被忽略的细节。package的作用是给一组函数套个壳壳里的同名函数会优先于引擎原有版本执行这是一种不修改原文件就能扩展行为的方式。Parent::onStart()和Parent::onExit()是在调用被覆盖掉的那个原版函数漏写会直接导致初始化或释放流程中断游戏可能出现莫名其妙的问题这是新手最常犯的错误之一。onStart和onExit这两个名字是引擎自己会去调的你不需要在别处主动调用它们。$Server::Dedicated是引擎内置的全局变量为真就走专用服务器分支否则走客户端分支。./表示当前脚本文件所在的目录这个相对路径写法后面会反复出现。3.3 三个 init.cs 各管什么先记这张表onStart里那三行 exec 是分水岭脚本从此分成三摊。刚开始不用把每个文件都读一遍记住各自的职责就够了文件大致职责你什么时候会去改它./client/init.cs载入界面、鼠标、输入映射等客户端侧脚本和 GUI 文件想改启动界面、往主菜单加个按钮./server/init.cs载入玩家、武器、AI、游戏规则等服务器侧脚本想加一把新武器、调 AI 行为./data/init.cs载入共享的数据定义各类 datablock 多半在这一层想改角色血量、跳跃高度需要提醒一句这三个文件是入口不是终点。它们内部还会 exec 更多文件一层套一层。比如服务器侧的 game.cs 里就会继续 exec 玩家脚本、武器脚本、AI 脚本。所以找代码的正确姿势是顺藤摸瓜从这三个入口往下翻而不是在目录里瞎翻。提示第一次读的时候可以只读 onStart 那三十来行把 exec 的路径在纸上抄一遍画成一棵树。树画出来你就知道这个游戏是怎么一块一块拼起来的了。4. 第一个能跑的例子按下 ~ 键敲一行 echo理论看到这儿该动手了。这一章的所有操作都在游戏自带的控制台里完成不用新建文件不用改目录出错也不会把项目搞坏。控制台是新手最好的练习场也是老手最常用的排查工具。4.1 第一步唤出控制台敲响第一声运行游戏的可执行文件进到主界面或者进游戏都行然后按键盘左上角那个 键——就是跟 ~ 同一个位置、不用按 Shift 的那个。控制台窗口会弹出来底下有一行输入框。输入下面这行回车echo(hello!); // 控制台立刻回显 hello!echo就是把括号里的内容打印到控制台。看着不起眼但它是你后面调试脚本的主要手段怀疑某段代码没执行就在里面加一行 echo怀疑某个变量值不对就把它 echo 出来看。分号必须加跟 C 一样它是语句结束的标记。多行语句可以一口气粘进去引擎会按分号分行执行$a 1; echo($a); // 输出 1这里$a是全局变量是赋值echo($a)打印它的值。你可能会问为什么不能直接写echo($a)而不先赋值因为没赋值的变量是空的打印出来什么都没有。养成“先赋值、再打印”的习惯能省掉很多困惑。4.2 第二步变量、字符串、数组一样样试先试一个能让大部分人愣一下的例子echo(1 2); // 输出 3 echo(1 2); // 输出 12同样是两个带引号的字符加号把它当数字算结果是 3才是字符串拼接结果是 12。这就是 TorqueScript 灵活的地方也是新手最容易栽的地方——你以为在做字符串拼接引擎却在做加法。想做拼接认准。还有几个拼接操作符注意必须大写echo(abcd NL CDEF); // 输出 abcd换行再输出 CDEFNL是插入换行TAB是插入制表符SPC是插入一个空格。写成小写nl是不认的这个坑不少人踩过。接着看变量和数组的关系$a 2; $a[0] 3; echo($a); // 输出 2 echo($a[0]); // 输出 3 echo($a0); // 输出 3是 $a[0] 的另一种写法变量和数组同名互不影响$a和$a[0]是两个独立的值。更有意思的是$a0这种写法它等价于$a[0]多维数组$a[0,0]还可以写成$a0_0。这种灵活性看着方便读别人代码时却容易认不出来心里有个数就行。最后试一下颜色控制这个在写提示信息时挺实用echo(\c2hello!\c0hello!); // 第一个 hello 红色第二个恢复默认色\c0到\c9是切换字体颜色\c0是默认色\n换行\t制表\\表示一个反斜杠本身。颜色只影响当前行后面的字符不会改掉整个控制台的默认色。4.3 第三步写第一个函数和一个 datablock函数定义跟 C 很像参数用 % 开头// 定义一个打招呼的函数参数是局部变量 function sayHello(%name) { echo(hello, %name); // 拼接字符串 return 1; // 返回值可选不写也行 } sayHello(newbie); // 输出 hello, newbiefunction是关键字函数名后面跟括号里的参数列表参数用 % 前缀表示局部变量意味着它只在函数内有效。return是可选的不写就默认返回空。函数名和变量名都不区分大小写sayHello和sayhello是同一个函数这一点跟 C 不一样得适应一下。然后是 TorqueScript 特有的东西——数据块datablock PlayerData(PlayerBody) { renderFirstPerson false; // 第一人称视角下是否渲染自己的身体 shapeFile ~/data/shapes/player/player.dts; // 模型文件~/ 指主游戏目录 cameraMaxDist 3; // 第三人称最大镜头距离 cameraDefaultFov 90.0; // 默认视野角度 cameraMinFov 5.0; // 最小视野角度 };数据块的作用是给某一类物体预先定义一堆属性。定义完之后它就在内存里存了一份创建物体时直接引用这个定义就行不用每次都把属性重写一遍。注意结尾那个分号不能少少了会引发一串让人摸不着头脑的报错。定义好了创建物体长这样%player new Player() { dataBlock PlayerBody; // 必须项指定用哪套属性 client %this; // 归属哪个客户端连接 }; MissionCleanup.add(%player); // 加进场景退出时自动清理new返回一个句柄赋给%player。这个句柄本质上是个整数在当前客户端里唯一相当于物体的本地 ID。MissionCleanup.add那行也别省它的作用是让这个物体在场景切换或退出时被自动清理掉不加的话容易留下残余对象。4.4 第四步用 F10 和 F11 打开那两个编辑器看一眼脚本之外还有两个可视化编辑器值得花十分钟摸一下。它们不写代码但能让你直观看到“界面”和“地图”这两样东西是怎么组织的。进游戏后按 F10打开 GUI 编辑器从控件面板拖一个按钮到画面上改个名字保存。按 F11打开世界编辑器在场景里选中一个物体挪个位置保存。回到游戏里退出再进看看刚才的改动还在不在。需要有个心理准备编辑器只负责“摆样子”按钮点下去要发生什么、物体被碰到会怎样这些功能都得回到脚本里补。文档里把 UI 编辑和世界地图编辑单独列成两节讲的就是这个分工。提示第一次拖控件不用追求好看能保存、能重新加载出来就算成功。这一步的目的是让你相信“改动是生效的”后面写脚本才有底气。5. 新手最容易踩的五个坑语法、路径和 ID 上的翻车现场这一章的五条都是我见过新手最容易反复踩的。每一条按“现象、原因、解决办法”三段说照着对号入座就行。5.1 语法上的三个翻车现场坑一语句末尾漏了分号。现象是整段脚本像没生效或者控制台报错的行号跟你写的位置对不上报在下一行甚至下一段。原因是 TorqueScript 靠分号断句漏一个后面的语句会被拼到上一句里一起解析错误自然就漂移了。解决办法是看报错时别只盯着报的那一行往上翻一两行找漏掉的分号另外函数调用、赋值、数据块结尾这三处是重灾区。坑二把双引号和单引号混着用。现象是echo出来看着一模一样但比较的时候死活不相等条件判断走进奇怪的分支。原因是abcd是普通字符串abcd是标记字符串两者是不同的东西不能互换。解决办法是统一用双引号除非你明确知道自己需要标记字符串接手别人代码时先扫一眼引号用得统不统一。坑三自己起的全局变量跟引擎原有的撞了。现象是某个数值怎么改都不对或者界面突然错乱、鼠标失灵而且找不到直接原因。原因是$开头的全局变量在整个客户端里只有一份你起了个跟引擎内置变量同名的等于把人家的值覆盖掉了。解决办法是起名前加自己的前缀比如$myGame_score这种能用局部变量 % 解决的就别用全局。5.2 路径和 ID 上的两个坑坑四用了绝对路径目录一挪就找不到资源。现象是模型不显示、贴图变白或者启动时提示找不到某个文件但文件明明就在硬盘上。原因是绝对路径把整条硬盘路径写死了主目录一改名、一移动路径立刻失效。解决办法是用相对路径关键字./表示当前脚本文件所在目录~/表示主游戏文件 main.cs 所在目录。养成习惯之后整个项目文件夹可以随便搬。坑五把本地 ID 当成网络 ID 用。现象是单机测得好好的一联网别人的角色在你屏幕上乱套或者你操作的角色不是你想操作的那个。原因是每个物体有两个 ID一个是客户端本地唯一的句柄一个是整个网络唯一的网络 ID。单机逻辑用本地句柄完全没问题但跨机器传数据时传本地句柄对方根本对不上号。解决办法是记住这个区分涉及联网的逻辑要拿网络 ID别顺手把%player直接发出去。注意第五个坑在单机阶段几乎不会暴露所以特别阴。做单机 demo 时就把“本地”和“网络”这两个概念分开想等真联机了能少熬几个晚上。6. 接下来学什么从看懂脚本到自己写一个能动的角色入门阶段最容易犯的第二个错是学完语法就一头扎进一个完整游戏项目里。结果被几千行脚本淹没三天后放弃。比较稳的路径是四周每周只盯着一个目标。阶段主要做什么怎么算过关第一周在控制台里把 echo、变量、字符串拼接、if/while、函数都敲一遍不看资料能写出一个带参数、有返回值的函数第二周读 server 侧入口那几个 init.cs顺着 exec 往下翻两三层能说出某个功能大概在哪个文件里第三周只改数值血量、镜头距离、视野角度、移动速度改完进游戏能明显感觉到变化第四周加一个小东西一个能被捡起来的物品或者给现有武器换个伤害值加的东西能正常出现、正常生效、退出不报错四周之后再回头碰schedule()和eval()这两个东西。schedule用来做延时和循环eval能把一段字符串当命令执行两个都很方便也都很容易把代码写得别人看不懂。刚入门时优先用直白的写法等真的遇到非它不可的场景再学。还有个小习惯强烈建议早点养成每次动脚本之前先在要改的那段前后各加一行 echo确认这段代码真的被执行到了。听起来笨但排查问题时它能帮你把范围从“整个项目”缩到“某一行”。我最早学的时候跳过语法直接去改玩家脚本里的数值结果一个漏掉的分号让我找了整整一晚控制台报的行号指向一段我根本没动过的代码。从那以后我每次改脚本都强制走一遍加 echo、确认执行、再改逻辑三步走完才敢继续往下写。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询