主题
按现象排错
从没日志、找不到球、计分错误和 HUD 不更新等现象,找到下一步检查。
先选与你看到的现象最接近的一项。每次改一个原因,重新开始一次试玩并重复原操作;不要一边修名字,一边改物理、事件和计分规则,否则难以知道哪一项起作用。
改了代码,却没有变化
- 确认改的是当前教程工程的
client/main.lua或server/main.lua,不是下载目录里另一份同名文件。 - 保存文件,在编辑器里确认同步的确完成。使用开发助手与使用 CLI 的同步流程不同,以第一课中与你工具一致的路径为准。
- 先修改一条日志里的独特文字,重新试玩,确认看到这句新文字。
- 仍然看到旧文字,就先处理工程绑定或同步,暂时不要继续调玩法。
本地文件保存成功不等于编辑器内存中的代码已经更新。停止试玩后再改代码,重新运行时只看这次会话的日志。
一条日志都没有,或只看见一端
| 检查 | 预期 | 不符合时 |
|---|---|---|
| 地图模式 | 世界版 / SE | 回到世界版教程地图 |
| 文件位置 | client/main.lua 与 server/main.lua | 修正目录和文件名 |
| 当前状态 | 已进入试玩 | 启动本次试玩后再查输出 |
| 输出来源 | 能区分 client 与 server | 选择对应输出来源,清除过滤条件 |
| 第一条错误 | 没有入口加载错误 | 先修第一条错误,再重跑 |
入口还未正常执行时,先恢复第一课检查点。后面的碰撞、HUD 或存储都不能替代这项检查。
报错里出现 nil
这通常说明代码想使用一个当前没有取得的值。看报错指向哪一个变量,再检查它的来源。
| 变量来自哪里 | 首先检查 |
|---|---|
| 场景查找 | Name、类型、父子层级与是否递归查找 |
| Players.LocalPlayer | 当前是不是 client,本地玩家是否已就绪 |
| player.Character | 角色是否尚未生成,重生后是否仍持有旧引用 |
| PlayerGui/EuiManager | UI 是否准备完成、是否重新读取当前对象 |
| require 返回值 | 模块是否 return 正确对象、路径是否存在 |
| 异步加载/存储 | 是否在完成回调前读取,是否处理失败 |
判空并输出原因能让程序停止在明确位置,但不等于问题已经修好。随后仍要修正名称、等待条件或调用时机。
找不到球体、方块或特效
- 在场景树里点击对象,逐字核对脚本使用的 Name,包括大小写、空格和中文字符。
- 核对具体类型:球体和方块应是本课指定的
WorldUnit,同名的 GroupUnit 不能替代它。 - 核对对象放在哪里。只查 World 的直接子节点时,放进分组后就可能查不到;按场景树专题确认获取链。
- 按场景搭建恢复当前检查点的对象树,再重试。
特效是可选表现时,应只影响表现。不要为了让日志安静,把计分流程改成“必须取得特效才运行”。
球推不动,或碰上目标没有日志
先不看分数,确认最小碰撞是否成立。
- 球是否是动态物理对象,物理模拟是否启用?静态物体(Static)不会按推球预期移动。球体质量(Mass)是否过大(建议设为 1)。本教程球体原点位于模型底部,Y=0 为正确落位;只有换用原点不同的素材时才需核对它是否陷入地板。
- 地面、球、方块的位置与碰撞形状是否正确?眼睛看到的渲染模型不一定等于碰撞模型。
- 目标是否允许物理碰撞和碰撞事件?按当前课的属性表检查,避免凭名称猜设置。
- 事件是否绑定在预期方块上?先看当前碰撞对象的名字,再判断它是不是那一颗球。
- 是否因初始化错误提前 return,导致连接根本没建立?
先恢复第二课的命中日志,再接回计分。排错时不要再注册第二套会加分的监听。
一次命中加很多分,或一直只显示 1
| 现象 | 优先检查 |
|---|---|
| 连续抖动时刷分 | 是否在 server 做了有效命中防抖 |
| 同一次碰撞固定加两次 | 是否安装了两个入口,或重复初始化后旧 Connection 未断开 |
| 每次都回到 1 | 是否在每次回调内把 score 初始化为 0 |
| 第二局出现上一局分数 | 回合重置是否清理状态,旧定时回调是否已失效 |
| 加入诊断后分数改变 | 诊断是否误执行加分;临时日志应只读 |
从每次命中只算一次重新核对。需要临时监听时,保存并断开其 Connection;计分只能由一条已经定义清楚的权威链修改。
得分记错人,或下一局没碰球也得分
先确认服务端记录的是哪位玩家、何时记录、何时消费或清除。
- 碰撞对象不是 Player。必须先证明它是
EggyUnit,再通过公开的角色反查接口取得玩家;查不到就不补造归属。 - 玩家离开、新回合开始、一次归属已消费时,要按当前主线规则清理记录。
- 不接受客户端直接传来的“玩家身份 + 分数”当作事实。
- 单客户端能计分,只证明了单人链路;两人轮流触球必须另做双客户端验证。
回到玩家归属。
服务端分数变了,HUD 没有变化
按数据流从前往后检查,不要同时改每一端。
| 检查点 | 应该看到什么 | 下一步 |
|---|---|---|
| 服务端计分 | 当前玩家的新分数 | 没变先修计分 |
| 服务端下发 | 完整快照发给对应玩家 | 确认事件定义与目标 |
| 客户端接收 | 当前回合与分数 | 确认先监听后请求,事件名一致 |
| 客户端校验 | 载荷字段与类型符合协议 | 比对同一版本的 common 文件 |
| 文本节点查找 | 当前 PlayerGui 下找到正确 EUITextLabel | 核对 Name、类型、就绪与重试 |
| 文本赋值与画面 | 数字更新且可读 | 检查 Visible、位置、尺寸和遮挡 |
先按通信课用客户端日志显示结果,再查HUD 课。同时复制通信专题和主线入口可能重复发送请求或绑定监听,应保留一套完整工程。
按钮点了没反应,或进行中也能重开
先判断是“按钮没有产生输入”,还是“服务端正确拒绝了当前请求”。
- 节点是否是正确的 EUIButton,名称是否与当前课一致?
- 初始化是否成功,点击 Connection 是否建立?
- 客户端是否只发请求,服务端是否收到?
- 当前是否处于允许重开的结算阶段,载荷是否符合协议,是否被节流?
- 一次结算已经接受过重开后,重复请求应被拒绝,不重复开始新局。
不能用“按钮里直接清分数”来绕过服务端规则。对照再来一局的有效请求与无效请求验收。
音效或特效没出现
先确认基础计分仍然成功,再独立检查表现资源。
- 音频 URI 必须是当前项目可访问的真实音频,不能把 mesh/preset 当音频。
- EffectUnit 先在编辑器配置资源和稳定名称,代码只查找并控制它。
- 同一特效连续使用时,旧延时回调不能把新一轮播放提前隐藏。
- 确认要给谁看或听:本地反馈和全场反馈应选择相应运行端,并分别验证。
回到让游戏更有反馈。音效不可听、截图不可见时,不把一条“播放”日志当成效果验收。
最后保存一条能复现的记录
不需要复杂格式,写清这些就够:
- 使用哪个检查点和工程版本。
- 从重新试玩开始,按什么顺序操作。
- 原本期待什么,实际看见什么。
- 当前会话的第一条相关错误或关键日志。
- 只改了哪里,重跑后结果如何。
