傅可心 / greenbread.cn
← 返回首页

工作项目 · 客户端核心系统

镜岫

一款以明代南京秦淮河流域为背景的叙事 RPG,包含 NPC 对话、全屏演出、AR 小游戏与多人对战。 负责范围为客户端核心系统——把不同内容形态组织为可配置、可恢复的任务流程,并完成多人架构、场景生命周期与内容工具建设。

项目类型
叙事 RPG · AR 交互
平台
Android 手机
引擎
Unity 6 · URP
参与时间
2025.11 – 至今
状态
待公测
镜岫项目主画面

CASE SUMMARY

我解决的不是单个功能,
而是整条客户端链路。

任务调度多类型 Segment 统一执行
状态与恢复8 章 / 分支 / 断点续接
多人架构NGO / 专用服务器
内容生产数据资产 / 自动校验
01

负责板块

负责客户端核心模块从方案设计、功能实现到真机联调与工程排障。

01

任务与剧情流程

Chapter / Act / Segment 状态机、分支解锁、断点恢复、主界面任务展示与奖励发放。

02

联机与多人玩法

NGO 客户端—服务器架构、专用服务器、云端房间生命周期、积分点、AR 挑战与比赛结算。

03

AR 与场景生命周期

AR 场景叠加加载、任务单元接入、完成与评分判定、返回主场景后的状态恢复和流程续接。

04

内容与工程工具

ScriptableObject 内容配置、剧情绑定校验、NPC 动画接线、编辑器排障与工程问题修复。

05

地图与移动端支持

定位源适配、地图坐标转换、围栏稳定性、权限状态和 Android 真机链路。

02

核心游戏循环

整条链路是:读取任务状态 → 分发 Segment → 执行对话 / 视频 / AR / 多人局 → 完成结算 → 保存并恢复进度。 地理触发是内容入口之一,但核心工作是后续任务调度、玩法执行与状态恢复。

环节 做的事 要解决的问题
任务状态 读取章节、前置与已确认游标,确定当前需要执行的最小内容单元。 不同内容不能依赖一条硬编码流程,冷启动也不能重复播放。
世界触发 任务满足前置后,由地理围栏或剧情事件激活章节入口。 触发条件与实际任务执行需要解耦。
章节推进 章节 / 幕 / 段落三级状态机,按段落类型分发对话、过场、AR、联机大厅。 内容形态差异大,不能写成一串硬编码流程。
玩法执行 叠加加载 AR 场景、激活对应任务单元、按完成情况评级并返回主场景。 场景切换时相机、玩家与 UI 的归属容易错乱。
联机对战 地理围栏建房、玩家同步、积分点生成与占领、AR 挑战、比赛结算回剧情。 对战是一局一份世界状态,必须与常驻业务分开。
结算与恢复 本地记录已完成幕与游标,发放道具与图鉴奖励,冷启动后续接。 玩家随时可能杀进程、切场景或中途离开。
03

系统详解

投入最多的四个子系统。每块按「问题 → 做法 → 结果」展开,末尾补充关键设计决策的取舍理由。

四、定位与地图支持

辅助能力

问题:玩法完全依赖真实位置,但开发和测试几乎都在室内。 早期代码直接读 SDK 回调,导致测试必须出门,定位源一换就要动业务逻辑。

做法:定义统一的位置提供者接口,把真实 GPS、高德 SDK、键盘、触摸拖动与虚拟摇杆 全部实现成可替换的来源,由一个管理器单例对外广播同一种位置数据; 再用适配器把经纬度按等距投影换算成 Unity 世界坐标,驱动玩家与围栏判定。 高德侧还要处理国内坐标系与国际坐标系的转换差异。

结果:切换定位模式只需改一个枚举,业务代码零改动; 室内用摇杆就能跑完整章节流程,真机出门用同一套逻辑验证。

  • 接口隔离:位置来源与消费方彻底解耦,新增来源不影响任何调用方。
  • 坐标系处理:国内定位坐标到国际坐标的转换,以及经纬度到米制世界坐标的投影。
  • 会话原点:以首次定位点作为世界原点,联机时改为网络同步的统一原点。
  • 权限三态:区分精确定位、仅大致位置与拒绝,避免只授权大致位置时整条链路静默卡死。

为什么不直接用 SDK 的回调?

因为定位来源会变,而且必须支持模拟。抽一层接口之后,模拟摇杆和真实 GPS 对下游是同一种数据,测试成本直接降下来。

只授权「大致位置」时会怎样?

早期表现是永远停在加载:定位服务不启动,世界原点不置位,POI 生成的等待循环一直卡着。后来改成三态检测加引导,并给等待加超时兜底。

一、任务调度与状态管理

玩法流程

问题:内容形态差异极大——有 NPC 对话、有全屏过场、有 AR 小游戏、还有多人对战, 但它们都要串在同一条章节推进里,并且玩家可能在任何一步退出。

做法:把内容拆成章节 / 幕 / 段落三级: 章节承担前置依赖与分支关系,幕绑定地理坐标与围栏半径,段落是最小执行单元并带类型。 推进器只做一件事:取出下一个未完成段落,按类型分发给对应的执行者。 章节数据全部落在 ScriptableObject 上,策划改内容不用碰代码。

结果:支撑了 8 章内容,包含三条并行支线的自由选择、隐藏任务, 以及断点续接——冷启动后能回到正确的段落,已完成的演出不重播。

  • 分支设计:第三章后进入并行支线组,玩家自选顺序,三线全通才解锁终章。
  • 围栏防抖:周期检测 + 连续命中才进入 + 退出滞后距离,避免提示反复闪烁。
  • 断点恢复:本地只保存已确认的游标与演出状态,恢复时不越过尚未播放的本地内容。
  • 引导与复活:任务路径采样、走错方向提示、复活点与围栏锁定。
  • 编辑器校验:菜单一键检查章节数据覆盖、重复配置与类型错配,避免配置错误留到真机。

为什么要拆到「段落」这一层?

因为一幕里往往是「先对话、再玩 AR、再对话」。如果只到幕,中途退出就只能整幕重来;拆到段落之后恢复粒度才够细。

分支怎么保证不会走乱?

章节声明前置依赖,同一分支组内本地只保留一个未完成的已选支线;完成后清除选择并重新弹出入口。终章同时依赖三条支线,三线全通才解锁。

二、联机与专用服务器

架构迁移

问题:项目最初是 Photon Fusion 的 Host 模式,房主即服务器。 这在户外多人对战里不合适:房主退出整局就断,且积分与胜负判定放在玩家设备上不可信。

做法:迁到 Netcode for GameObjects 的客户端-服务器模式, 搭建独立运行的专用服务器;玩家位置由客户端上报、服务端裁决并同步, 得分点与比赛状态由服务端生成和结算。同时用条件编译把服务端不需要的 UI 与渲染剥离, 让服务端能以无图形模式运行。

结果:对战不再依赖某个玩家的设备; 补上了连接审批与房间容量上限、队伍标识、断线与踢出后的回主场景流程和重连提示。

  • 权威划分:位置、队伍、得分点归服务端,客户端只做输入与表现。
  • 连接审批:在启动前开启审批回调做人数上限,并支持命令行覆盖容量。
  • 专用服构建:条件编译隔离客户端 UI,无图形环境下的启动参数与运行守卫。
  • 房间生命周期:从本机校验推进到云端按需分配对战容器,理清「已分配 / 就绪 / 进行中 / 关闭」状态与轮询时机。
  • 安全边界:识别出服务端密钥不能打进客户端包,改由服务端代申请容器再下发地址。

为什么对战不能和常驻业务放在一个进程里?

端口不是问题,生命周期才是。一局结束要销毁的是这一局的世界状态,而账号与业务服必须常驻;一个进程里做不到「打完就杀」。而且一个进程一份会话,不拆进程房间就形同虚设。

迁移过程中最麻烦的是什么?

移动权威的归属。原先客户端直接改位置,迁移后要改成上报输入、由服务端执行移动,否则会出现两处同时写位置导致的抖动与拉回。

三、AR 交互与场景管理

交互系统

问题:每章 AR 玩法都是独立场景,但它们要能被剧情流程统一调度, 并且完成后必须干净地回到主场景,不留下相机、玩家与 UI 的残留状态。

做法:用叠加加载把 AR 场景挂到主场景之上,切换时统一处理相机堆叠、 玩家可见性与主界面显隐;场景内用任务单元封装单个小游戏的开始、完成、重玩与评级; 完成通知经事件通道回到流程推进器,再决定是否卸载场景并进入下一段。

结果:新增一个 AR 玩法只需实现任务单元并配置章节数据, 不需要改动流程推进逻辑;完成判定与评分口径在各章之间保持一致。

  • 场景进出:叠加加载与卸载、相机堆叠切换、渲染与输入的归属处理。
  • 任务单元:统一的开始 / 完成 / 重玩接口,按完成情况评级并写入玩家属性。
  • 玩法接线:灯谜、拾取、道具架、弹弓发射与道具效果等交互模块。
  • 动画驱动:用动画事件对帧触发逻辑与音效,把过场动画接进段落流程。
  • 联机 AR 挑战:占领得分点后触发挑战,成功与失败分流到不同的销毁与提示路径。

从 AR 场景返回时最容易出什么问题?

主界面没有正确恢复,以及玩家与远端玩家的渲染被整体隐藏后没有还原。这类问题都要求场景进出的显隐逻辑集中在一处,不能各写一份。

为什么用事件通道而不是直接调用?

AR 场景是叠加加载的,场景内脚本和主场景的流程推进器互相拿不到引用。用 ScriptableObject 事件通道之后,两边只依赖同一个资产,不需要互相查找对象。

04

项目画面

后三张是独立实现的 AR 交互玩法。它们各自是叠加加载的场景, 由统一的任务单元接口接入章节流程,完成判定与评级口径保持一致。

主界面与地图
jinglin-1.jpg主界面地图 / 定位
主界面与地图导航:任务点分布、罗盘朝向与昼夜表现。
剧情与对话
jinglin-2.jpg剧情推进 / 对话
章节演出:段落按类型分发,对话与过场串在同一条推进链上。
多人对战
jinglin-3.jpg多人对战 / 联机
多人对战:得分点占领、队伍标识与比赛结算。
AR 围棋对弈
jinglin-4.jpgAR 交互 / 围棋对弈
AR 围棋:棋盘落子交互与局面判定,结束后按结果评级并续接章节。
AR 拼图
jinglin-5.jpgAR 交互 / 拼图
AR 拼图:碎片拖放与就位判定,完成度达标才触发通过。
古法染色
jinglin-6.jpgAR 交互 / 古法染色
古法染色:多步骤工序操作,按材料与步骤正确度判定成色。
05

工程与排障

玩法之外,项目里有一部分工作是把开发环境和真机问题按住。这部分同样关键,因为它决定团队能不能顺利往下做。

问题 定位过程 处理
编辑器像卡死、按钮点不动 表面看是 UI 失灵,实际是某个逐帧脚本用越界值索引输入设备,每帧抛异常,异常栈与控制台重绘吃满主线程。 改成先校验再读取,并加一个异常风暴守卫:一秒内异常超过阈值就自动暂停并报错,避免同类问题再拖垮编辑器。
地图材质异常、无法合批 一个场景里被写入上千个内嵌材质实例,另一个场景则残留大量空材质槽;根因是编辑器工具在内存里造材质后随场景保存。 逐批撤销无效覆盖、重建缺失材质资源并留好备份,同时定位到生成工具这个源头。
大场景打开就卡住 约两万个渲染对象、没有 LOD、未烘遮挡剔除,编辑器视图直接把显卡拖垮。 先用可见性守卫让编辑器可用,并把根治方案(分块与剔除)记录成待办,避免临时手段被当成修复。
联机连不上但日志显示成功 建房校验走的是一条独立连接,它成功不代表游戏连接已建立,两者要分别看日志。 按连接分层排查,并把关键状态与失败原因补进日志,减少反复复现的成本。
真机日志乱码 中文日志经设备日志再编码后变成乱码,出问题时反而看不懂。 约定日志只用 ASCII,中文留给界面文案,并在关键日志里补上操作名、状态码与相关 id。
06

可复用的成果

三句话概括

  • 用统一接口抽象定位来源,让依赖真实位置的玩法可以在室内完整测试,把验证成本从「出门一次」降到「点一下摇杆」
  • 把联机从房主即服务器迁到专用服务器架构,位置与胜负判定收归服务端,并补上容量限制与断线恢复。
  • 章节 / 幕 / 段落三级状态机加数据驱动配置撑起 8 章内容、并行支线与断点续接,新增玩法不改流程代码。