主题
决定哪些规则交给 Lua
从一个玩法需求判断编辑器、服务端、客户端和配置各自负责什么。
什么时候查这篇
你已经会摆放场景,但不确定“哪些继续用编辑器、哪些要写代码”时,读这篇。它是概念选读,没有需要安装的 Lua 文件。还没看到第一条代码日志时,先去让第一段代码跑起来。
用推球撞方块判断分工
| 你想做成的事 | 由谁负责 | 为什么 |
|---|---|---|
| 摆地面、球体和目标方块 | 编辑器 | 它们是开始试玩前就能确认的场景内容 |
| 球撞到方块后只算一次 | server 脚本 | 需要检查碰撞对象、防抖和当前回合 |
| 把得分记给最后触球玩家 | server 脚本 | 多人需要共享一份可信的归属与分数 |
| 在玩家画面显示分数 | client 脚本 | 每位玩家看到自己的界面 |
| 按钮请求开始下一局 | client 发请求,server 检查后执行 | 按到按钮不代表当前允许重开 |
| 修改一局时长和每次分值 | data 配置 | 参数集中管理,代码读取同一份定义 |
| 保存历史最高分 | 完成玩法后另接存储专题 | 普通变量只保存当前运行中的状态,不会自动跨局持久化 |
先问“这是玩家意图,还是已经判定的结果”。客户端发来“我想重开”是意图;服务端确认当前处于结算阶段并接受请求,才成为所有人共同的新回合。
编辑器里的对象,在代码中有具体类型
编辑器中都显示为节点,并不代表代码能力一样:
WorldUnit可以参与物理碰撞,用来做球和方块。EUITextLabel有文本能力,用来显示分数。Player代表玩家身份;Player.Character是场景里的蛋仔角色。Unit提供共同的名称、层级与生命周期能力,不能据此推断任何 Unit 都有碰撞或文本属性。
拿到一个对象后,先确认它是什么、从哪里来,再查该具体类型的公开能力。对象与值类型和场景树提供进一步说明。
世界版、SE 与状态同步
本教程中的“世界版”“SE”“状态同步地图”指向同一套创作环境。它与原点版的脚本体系不同;创建地图时应选择世界版模板。
在这套环境中,可以把服务端理解为共同管理对局状态的一端,每个玩家的客户端负责自己的输入和画面。“同一个世界”不等于服务器永不关闭,也不意味着一个 Lua 变量会永久保存。
不要把另一套编辑器的接口名直接搬进来。本教程采用 game:GetService(...) 入口;遇到旧例子时先查当前 Game API,不要靠猜名称补功能。
自己做一次判断
需求:玩家碰到金币后,加 3 分,金币消失,玩家看到“+3”。
先自己把四件事分到编辑器、server、client:
- 放置金币的初始外观和位置。
- 判断碰到金币的对象是不是玩家角色。
- 判断金币是否已被领取,然后增加分数。
- 显示“+3”。
展开参考答案
编辑器负责第 1 项。server 负责第 2、3 项,并决定金币是否仍可领取。client 根据服务端结果显示第 4 项。不能因为本地看见金币消失就直接认为领取成功;多人同时碰到时尤其要由 server 统一判定。
常见卡点
| 现象 | 下一步 |
|---|---|
| 不知道现在该学哪一项 | 回到10 课主线,按小游戏的下一项可见结果推进 |
| 以为必须先会全部 Lua 才能开始 | 主线会就地解释所用语法,遇到陌生写法再查Lua 速查 |
| 准备第一天同时加背包、存档和商店 | 先完成可重复的一局,之后每次只选一个专题 |
| 从旧例子复制的 API 不存在 | 确认编辑器体系、运行端及当前 API 页面,不用内部 SDK 名称绕过 |
返回主线
能解释“摆球、计分、显示”三者的分工,就可以继续第一次运行。不用把专题目录全读完。
