一、自己/团队介绍
大家好,我是九刀,一名有十多年手搓代码经验的全栈开发者,同时也是一名线下社交游戏(警匪游戏,狼人杀,剧本杀,桌游)的疯狂爱好者,曾经做过剧本杀监制,发行,也协办过剧本杀展会,同时还开发并运营过几个剧本杀相关的APP。
去年差不多也是这个时候,我第一次打开 TRAE IDE,说实话,当时整个人是懵的——以前一个月的工作量,TRAE 一两天就能搞定,而且代码质量比我手写的还要好。一开始我甚至有点沮丧,但用久了就发现,TRAE 更像是一个能力极强但经验尚浅的搭档。它能帮你把框架搭起来、把细节补全,但关键的设计决策、业务逻辑的理解,还是需要人来把关。这种"人机协作"的模式,让我这一年效率翻了好几倍。
《时光公园的最后一天》这个想法在我脑海里转了好几年:把真实的公园变成游戏舞台,让玩家"边走边破案"。但技术栈太复杂(微信小程序 + Spring Boot + MySQL + GPS 定位 + 多人协作),剧情内容量又太大(近20个角色视角、五幕剧情、完整对话树),一直没有动手。直到发现 TRAE AI 创造力大赛,同时最近也比较有空,给了我把这个产品实现的动力——于是拉着 TRAE,从零开始,两周时间把后端架构、前端页面、数据库设计、剧情内容全部搭了起来,又经过一个月的迭代打磨,形成了一个完整的产品,并进行了线下测试。
一个跟 AI 吵了一整年架的开发者
二、产品简介
是什么?
《时光公园的最后一天》是一款基于微信小程序的 LBS 实景解谜剧本杀游戏。玩家走进真实的公园,通过 GPS 定位自动解锁场景,与虚拟 NPC 对话、搜集线索、完成任务,最终揭开二十年前园艺师林依然失踪的真相。
游戏融合了三种核心体验:
-
LBS 实景探索:GPS 后台持续定位触发场景,真实公园即游戏地图,电子围栏圈定游戏范围,离开公园即刻离开游戏。
-
剧本杀推理:多视角叙事,16 个npc角色各有秘密,矛盾证词需要交叉验证。
-
情感叙事:五幕剧情层层递进,从迷雾降临到真相揭开,钟楼钟声再次响起。
面向谁?
核心目标用户: 18-35 岁城市青年,喜欢剧本杀、密室逃脱、解谜游戏;喜欢户外活动的轻度游戏玩家;对城市文化、历史故事感兴趣的人群,公园遛娃的宝妈。
典型使用场景:
-
周末和朋友约去公园,打开小程序"边逛边玩"
-
剧本杀爱好者想体验"户外剧本杀"的新鲜感
-
家长带孩子逛公园,用游戏让孩子了解公园历史和城市记忆
完整功能
| 功能模块 | 具体功能 | 说明 |
|---|---|---|
| GPS 定位系统 | 后台持续定位、地理围栏触发 | wx.startLocationUpdateBackground 实时追踪,Haversine 公式计算距离,20 米范围内自动解锁场景;降级方案为 3 秒轮询单次定位 |
| 场景探索 | 场景介绍、搜索物品 | 每个场景可"搜索"发现物品,支持概率计算、最低搜索次数、幕分层物品(同一场景不同幕发现不同物品) |
| NPC 对话系统 | 多分支对话树、物品出示、任务触发 | 对话节点 + 选项表结构,5 种动作类型(获得物品/消耗物品/获得线索/完成任务/结束游戏),支持前置物品过滤 |
| 背包与道具 | 物品收集、交给 NPC | 全队共享背包,物品可通过搜索场景或 NPC 对话获得,可交给 NPC 推进剧情 |
| 线索板 | 线索收集、按幕分组 | 线索按剧情幕数分组展示,支持文本/图片/音频三种类型,全队共享 |
| 任务系统 | 主线任务、支线任务 | 任务有前置依赖链,场景解锁联动任务解锁,任务完成触发幕推进 |
| 多人协作 | 房主制、邀请码加入、共享进度 | 6 位邀请码加入游戏局,同局所有玩家共享场景/任务/背包/线索/NPC 状态/对话历史,支持中途加入 |
| 幕推进系统 | 自动幕切换、NPC 联动激活 | ActConfig 配置每幕推进所需任务,支持级联推进;NPC 激活条件引擎支持 5 种条件(幕数/任务完成/持有物品等) |
| 片尾结局 | 图片轮播、旁白文字、总结 | 对话树 end_game 动作触发片尾,包含图片轮播 + 旁白文字 + 剧情总结 |
| 公园电子围栏 | 多边形围栏、区域限制 | 射线法判断玩家是否在公园范围内,离开公园时提示返回 |
| 多公园支持 | 场景坐标覆盖、独立围栏 | 同一剧情可部署到不同公园,每个公园独立配置场景 GPS 坐标和电子围栏 |
| 代理商/商户系统 | B2B2C 多层级管理 | 代理商创建公园、管理商户;商户管理玩家;数据权限隔离 |
| 故事回顾 | 主线/支线/人物小传 | 游戏结束后可回顾完整剧情,含五幕主线叙述、支线故事、16 个人物完整小传 |
| BGM 系统 | 按幕切换背景音乐 | 6 首 BGM 对应序章到终章,幕切换时自动联动切换 |
| 后台管理 | NPC/对话/场景/任务/物品/线索管理 | 完整的超级管理员后台 + 代理商后台,支持游戏局管理、玩家管理、商户管理 |
用户使用路径
-
进入游戏 → 微信授权登录(或手机号登录)→ 首页播放序章视频 → 展开剧情引导信 → 进入地图
-
加入游戏 → 输入 6 位邀请码 → 加入游戏局 → 等待房主开始(或中途加入共享进度)
-
探索公园 → 走向场景 → GPS 触发自动解锁(震动提示)→ 查看场景介绍和背景故事
-
与 NPC 互动 → 点击 NPC 头像 → 进入对话树 → 选择对话选项或出示道具 → 触发动作(获得物品/线索/完成任务)
-
搜集线索 → 点击"搜索"按钮 → 按概率发现物品/线索 → 自动收入全队共享背包
-
完成任务 → 根据任务提示 → 找到目标 NPC/线索/道具 → 对话中触发任务完成
-
推进剧情 → 完成本幕所有任务 → 自动进入下一幕(弹窗提示 + BGM 切换)→ 解锁新场景和新 NPC
-
最终结局 → 完成第五幕最终任务 → 对话树触发
end_game→ 片尾图片轮播 + 旁白 → 进入故事回顾
五幕剧情结构
| 幕数 | 名称 | 核心内容 |
|---|---|---|
| 序章(0) | 迷雾降临 | 钟楼敲响,浓雾笼罩公园,玩家收到匿名信,与神秘老人初次接触 |
| 第一幕(1) | 失踪之谜 | 调查林依然失踪案,与公园中的关键人物对话,收集初始线索 |
| 第二幕(2) | 往事浮现 | 深入调查,发现矛盾证词,揭开二十年前公园不为人知的秘密 |
| 第三幕(3) | 真相逼近 | 关键线索汇聚,各方势力浮出水面,真相逐渐清晰 |
| 第四幕(4) | 最后一天 | 公园最后一天,所有线索串联,钟楼钟声再次响起,真相大白 |
故事背景
时光公园建成于 1985 年,是这座城市最早的综合性公园。2025 年,公园即将被拆除。今天,是它对外开放的最后一天。
黄昏时分,你推开锈迹斑斑的铁门。钟楼敲响了六下。浓雾从湖面升起。一个苍老的声音在你身后响起:“这座公园等这一天,等了二十年。记住——在这个公园里,你听到的每一句话,都可能是谎言。”
1987 年 7 月 15 日,公园园艺师林依然在公园内失踪,警方以"离家出走"结案。二十年后,她的女儿林晓曦回到这座即将拆除的公园,试图找出母亲失踪的真相。但她不知道的是——那天在公园里的六个人,每个人都在说谎。
这不是一桩失踪案。这是一场持续了二十年的集体谎言。
相比初赛 Demo 的升级
| 升级项 | 初赛 Demo | 复赛完整版 |
|---|---|---|
| 剧情深度 | 单幕剧情,少量 NPC | 五幕完整剧情,16 个 NPC,完整对话树,多条支线 |
| 多人协作 | 单人游戏 | 房主制 + 邀请码加入 + 全队共享进度,支持中途加入 |
| NPC 系统 | 固定激活 | 条件驱动激活引擎,支持 5 种激活条件(幕数/任务/物品等),幕推进时联动重新评估 |
| 幕推进 | 无 | ActConfig 配置系统,任务完成自动触发幕切换,支持级联推进和全部/任一完成模式 |
| 片尾结局 | 无 | 对话树 end_game 触发片尾系统,图片轮播 + 旁白文字 + 剧情总结 |
| 矛盾证词 | 无 | 剧情层面设计矛盾证词和被篡改的证据,需要交叉验证(如"错位的证词"、“磁带的双重声音”) |
| 场景搜索 | 简单搜索 | 概率计算 + 最低搜索次数 + 幕分层物品(同一场景不同幕发现不同物品)+ 全队共享搜索次数 |
| 公园围栏 | 无 | 电子围栏系统,射线法判断玩家是否在公园范围内 |
| 多公园部署 | 单公园 | 场景坐标覆盖机制,同一剧情可部署到不同公园,每个公园独立配置 GPS 坐标 |
| 代理商系统 | 无 | B2B2C 多层级商业模型,代理商/商户/玩家三级管理,数据权限隔离 |
| 故事回顾 | 无 | 游戏结束后回顾完整剧情,含主线/支线/16 个人物完整小传 |
| BGM 系统 | 无 | 6 首 BGM 按幕切换,幕切换时自动联动 |
| 后台管理 | 无 | 完整的超级管理员后台 + 代理商后台,支持游戏局/玩家/商户/公园/场景/NPC/对话/任务/物品/线索全面管理 |
| 认证系统 | 仅微信登录 | 微信登录 + 手机号登录双方式,JWT Token 认证 |
| 数据库 | 9 张核心表 | 21 张数据表,含游戏局维度进度管理、代理商商户体系、公园围栏等 |
| 测试功能 | 无 | 增加点图移动的测试功能,方便评委测试,体验到公园内实景移动的效果。 |
三、产品演示视频
产品演示视频:
抖音链接:
剧情介绍:https://v.douyin.com/pXkHQgCQpKE/
功能介绍: https://www.douyin.com/video/7671623121962609081
四、产品创作历程
创意诞生
这个想法源于我的一次经历:在N年前我作为一个剧本杀监制,当时由于一个剧情卡壳,去公园里边遛弯边考虑剧情,在夕阳下看到了一位坐在花坛上的老人,脸上挂着微笑,看着广场上嘻笑追逐的儿童。那一刻我突然想:如果公园有记忆,它会记住什么?
于是有了核心创意——把真实的公园变成游戏舞台,让玩家在真实空间中体验一场跨越二十年的悬疑故事。
初赛阶段
初赛时我提交了一个能跑通的 Demo:实现了基础 GPS 定位和场景解锁,设计了少量 NPC 和简单对话树,完成了序章的剧情。核心链路验证通过:玩家可以走进公园 → 解锁场景 → 与 NPC 对话 → 搜集线索。
复赛迭代
核心架构升级
-
多人游戏会话系统:从 Player 维度迁移到 Game 维度,实现房主制 + 邀请码 + 全队共享进度
-
幕推进配置系统:ActConfig 表配置每幕推进条件,任务完成自动触发幕切换
-
NPC 条件激活引擎:支持 5 种激活条件,幕推进时联动重新评估
剧情内容填充
-
五幕完整剧情设计:从迷雾降临到真相大白,16 个 NPC 的完整对话树
-
矛盾证词设计:在剧情层面设计矛盾证词和被篡改证据,增加推理深度
-
支线故事:多条支线剧情,丰富叙事层次
商业化与多公园部署
-
代理商/商户系统:B2B2C 多层级商业模型,数据权限隔离
-
公园电子围栏:射线法判断玩家位置,限制在公园范围内游戏
-
多公园支持:场景坐标覆盖机制,同一剧情可部署到不同公园
-
代理商取点工具:小程序端为代理商提供 GPS 坐标采集功能
体验优化与测试
-
片尾结局系统:对话树触发片尾,图片轮播 + 旁白 + 剧情总结
-
故事回顾系统:游戏结束后回顾主线/支线/人物小传
-
BGM 系统:6 首背景音乐按幕切换
-
在线下公园完成了全面测试
关键决策
为什么选微信小程序而不是 App? 降低用户门槛,无需下载安装,扫码即玩;微信生态优势,一键登录、社交分享;适合线下场景,玩家在公园里边走边玩,小程序最轻量。
为什么用 LBS 实景而不是纯虚拟场景? 真实公园即游戏地图,降低内容生产成本;玩家身临其境,沉浸感远超纯虚拟场景;每个城市都有公园,作品可复制推广到多个城市。
为什么从 Player 维度迁移到 Game 维度? 初赛时每个玩家独立进度,无法实现真正的多人协作。复赛时将所有进度数据(场景/任务/背包/线索/NPC 状态/对话历史)以 gameId 为维度存储,实现同局玩家完全共享进度,支持中途加入。
为什么设计代理商/商户系统? 游戏要推广到多个公园,需要让各地代理商独立管理自己的公园和玩家。B2B2C 模型让系统平台 → 代理商 → 商户 → 玩家形成清晰的数据隔离和权限管理链路。
五、TRAE 实践过程
Session ID :.3520003649314604:7764bf0b80e0585241beaa0f966b8ee1_6a30c62f48c469ed8cba1a94.6a66c77b414fedb36230493b.6a66c77b2445a35c71b79873:Trae CN.T(2026/7/27 10:50:35)
Session ID :.3520003649314604:2b6bd7eecf9969b826e5778b8cf72b32_6a30c62f48c469ed8cba1a94.6a6967bbb09b28241f455aba.6a6967bba657b33a1880672e:Trae CN.T(2026/7/29 10:38:51)
Session ID :.3520003649314604:6a3ef1044f8b990f80791a4f1bf6464c_6a30c62f48c469ed8cba1a94.6a6abaaccafce97a90e6f38b.6a6abaac79665b447eb56548:Trae CN.T(2026/7/30 10:45:00)
六、技术方案分享
技术栈
| 层级 | 技术 | 说明 |
|---|---|---|
| 前端 | 微信小程序(WXML/WXSS/JS) | 原生小程序开发,无需下载安装,14 个页面 |
| 后端 | Spring Boot 3.x + Spring Security | RESTful API,JWT 认证,三套账号体系(玩家/代理商/管理员) |
| 数据库 | MySQL 8.0 | utf8mb4 字符集,21 张数据表 |
| 地理计算 | Haversine 公式(Java 实现) | 计算玩家与场景距离,20 米范围内自动解锁 |
| 电子围栏 | 射线法(Ray Casting) | 判断玩家是否在公园多边形围栏内 |
| 文件存储 | TOS 对象存储(火山引擎) | 存储场景图片、NPC 头像、BGM 音频资源 |
| 认证 | 微信 openid + JWT Token / 手机号验证码 | 双方式登录,玩家/代理商/管理员三套独立认证 |
| BGM | wx.createInnerAudioContext | 6 首 BGM 按幕切换,循环播放 |
架构设计
微信小程序(前端 14 个页面)
↕ HTTPS / REST API(JSON)
Spring Boot 后端(三套账号体系)
├── 玩家端 API(/api/)
├── 代理商后台(/agent/)
└── 超级管理员后台(/admin/)
↕ JPA / Hibernate
MySQL 数据库(21 张表)
数据库设计
项目从初赛的 9 张表扩展到 21 张表,核心设计:
1. Game 维度共享进度(6 张表)
-
games(游戏局)→game_players(玩家关联)→game_scenes(场景进度)→game_tasks(任务进度)→game_items(共享背包)→game_clues(共享线索)→game_npc_state(NPC 激活状态)→game_dialogue(对话历史) -
所有进度以 gameId 为维度,实现同局玩家完全共享
2. 幕推进配置(2 张表)
-
act_config(幕推进配置)+act_config_tasks(任务关联) -
定义每幕推进到下一幕需要完成哪些任务,支持全部/任一完成模式
3. 代理商/商户体系(4 张表)
-
agents(代理商)→agent_admins(代理商管理员)→merchants(商户)→players.merchant_id(玩家归属) -
B2B2C 多层级数据隔离
4. 多公园支持(3 张表)
-
parks(公园)→park_scene_configs(场景坐标覆盖)→park_fences(电子围栏) -
同一剧情部署到不同公园,每个公园独立配置坐标和围栏
关键技术点
1. GPS 后台持续定位
小程序端使用 wx.startLocationUpdateBackground 实现后台持续定位,wx.onLocationChange 回调中节流(5 秒间隔)后调用后端检查附近场景。降级方案为 3 秒轮询 wx.getLocation:
startLocationTracking() {
wx.startLocationUpdateBackground({
success: () => {
wx.onLocationChange((location) => {
this.throttledCheckNearby(location);
});
},
fail: () => {
// 降级为轮询
this.locationInterval = setInterval(() => {
wx.getLocation({ type: 'gcj02', success: (loc) => {
this.throttledCheckNearby(loc);
}});
}, 3000);
}
});
}
2. Haversine 公式地理围栏
后端精确计算玩家与场景之间的球面距离,20 米范围内自动触发场景解锁:
public double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
final int R = 6371000; // 地球半径(米)
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
3. 对话树动作引擎
对话选项支持 5 种动作类型,选择后自动执行副作用:
private void executeAction(Long gameId, DialogueOption option) {
switch (option.getActionType()) {
case "get_item": // 获得物品
inventoryService.addItemToGame(gameId, itemId, "npc_" + npcId);
break;
case "give_item": // 消耗物品
inventoryService.removeItemFromGame(gameId, itemId);
break;
case "get_clue": // 获得线索
inventoryService.addClueToGame(gameId, clueId);
break;
case "complete_task": // 完成任务
taskService.completeTask(gameId, taskId);
break;
case "end_game": // 结束游戏,触发片尾
gameService.endGame(gameId);
break;
}
}
4. NPC 条件激活引擎
支持 5 种激活条件,场景解锁和幕推进时联动重新评估:
private boolean evaluateActivateCondition(String condition, int currentAct, Long gameId) {
if (condition == null || condition.equals("always")) {
return true; // 场景解锁即激活
}
if (condition.startsWith("act>=")) {
int requiredAct = Integer.parseInt(condition.substring(5));
return currentAct >= requiredAct; // 幕数达到才激活
}
if (condition.startsWith("task:")) {
String taskKey = condition.substring(5);
return taskService.isTaskCompleted(gameId, taskKey); // 任务完成才激活
}
if (condition.startsWith("item:")) {
Long itemId = Long.parseLong(condition.substring(5));
return inventoryService.hasItem(gameId, itemId); // 持有物品才激活
}
return false;
}
5. 幕推进级联机制
任务完成后检查是否满足幕推进条件,支持级联推进(推进到新幕后继续检查):
public void advanceActIfNeeded(Long gameId, Long completedTaskId) {
int maxIterations = 10; // 防死循环
for (int i = 0; i < maxIterations; i++) {
Game game = gameRepository.findById(gameId).orElseThrow();
int currentAct = game.getCurrentAct();
List<ActConfig> configs = actConfigRepository.findByFromAct(currentAct);
if (configs.isEmpty()) break;
for (ActConfig config : configs) {
boolean allCompleted = checkTasksCompleted(gameId, config.getTaskIds());
if (allCompleted) {
game.setCurrentAct(currentAct + 1);
gameRepository.save(game);
// 激活新幕的 NPC
sceneService.reevaluateNpcsOnActAdvance(gameId, currentAct + 1);
break; // 继续循环检查下一幕
}
}
}
}
6. 公园电子围栏(射线法)
使用射线法判断玩家是否在公园多边形围栏内:
public boolean isPointInPolygon(double lat, double lng, List<double[]> polygon) {
int n = polygon.size();
if (n < 3) return true; // 无围栏或顶点不足,不限制
boolean inside = false;
for (int i = 0, j = n - 1; i < n; j = i++) {
double yi = polygon.get(i)[0], xi = polygon.get(i)[1];
double yj = polygon.get(j)[0], xj = polygon.get(j)[1];
if (((yi > lat) != (yj > lat)) &&
(lng < (xj - xi) * (lat - yi) / (yj - yi) + xi)) {
inside = !inside;
}
}
return inside;
}
7. 防作弊设计
-
场景解锁时后端重新校验玩家坐标,不依赖前端请求
-
电子围栏限制玩家必须在公园范围内操作
-
关键操作失败时不扣减本地数据,等待同步成功
-
对话历史全队共享,防止重复触发
七、产品迭代规划
短期规划(1-3 个月): 持续开发新的剧本内容,并接入更多公园场景,制作"城市公园解谜系列";优化 GPS 精度,支持室内定位(蓝牙信标)。
中期规划(3-6 个月): 增加 AR 元素,扫描公园实景触发虚拟角色;与文旅景区合作,制作定制化实景解谜产品。
长期愿景: 打造"中国城市公园解谜地图",每个城市都有自己的实景剧本杀,让年轻人重新走进公园,在户外活动中感受城市文化和历史故事。
**以上就是《时光公园的最后一天》的复赛作品介绍,感谢阅读!欢迎在评论区交流讨论。*


