开发初衷
源海世界最初只是一个念头:能不能做一个"活着"的文字世界?
市面上的文字游戏大多是静态的——NPC 永远站在原地,对话树固定不变,世界等待玩家推进而非自行运转。我想做一个不同的尝试:NPC 有自己的记忆,会遗忘、会偏移;世界有潮汐涨落,夜晚的危险与机遇并存;玩家的身份是隐藏的,你需要通过探索来认识自己。
于是有了三层宇宙的设定——黄天在上、赤原在中、渊境在底。玩家在赤原醒来,却不知道自己来自哪一层。这个"不知道"就是整个游戏的探索驱动力。
项目历程
从单人原型到全栈联机、从云端网页到本地胖客户端——15 个关键里程碑,横跨架构、玩法、性能三大维度。
详细的版本迭代日志请查看 开发随笔 页面,那里有完整的 15 节点时间线和每次更新的技术细节。
设计理念
"活着"的世界
NPC 不是数据表里的一行记录。他们有记忆,会遗忘;有性格,会偏移。潮汐时段他们会主动靠近你,平潮时段他们的行为会越来越随机。你今天交好的朋友,明天可能只是个陌生人。
"隐藏"的驱动力
隐藏身份是核心设计。玩家不知道自己是黄天原生还是中心者,只能通过行为反馈推测。GAL 剧情中,16 项隐藏属性在暗中影响分支走向——你不知道为什么走到这个结局,这本身就是探索的动力。
"呼吸"的节奏
潮汐系统让世界有了呼吸感。白天是相对安全的探索时间,夜晚是危险与机遇并存的潮汐时段。玩家需要规划自己的行动节奏,而不是无脑推进。
"离线优先"的架构
游戏不应该是"没网就不能玩"的。胖客户端架构将所有游戏资源本地化部署——页面、剧情素材、静态资源一次性安装到本地,弱网甚至断网环境下依然可以流畅游玩单机模式。
技术栈
架构设计思路
后端:Flask + WebSocket + SQLite
选择 Flask 而非 Django/FastAPI,是因为项目体量不需要重型框架,Flask 的蓝图机制足够模块化。WebSocket 用 flask-sock 轻量实现,不走 Socket.IO 那套复杂协议。后期引入 Redis 做消息队列和缓存,PostgreSQL 做分析查询。
数据库选 SQLite 而非 PostgreSQL——单人项目不需要并发写入,SQLite 单文件部署最省心。表结构按 MySQL 规范设计,将来迁移只换驱动。实际运行中 SQLite 在 50+ 并发下表现稳定,未出现锁竞争瓶颈。
前端:三栏布局 + 模块化 JS + PixiJS 2D 地图
没有用 Vue/React——文字游戏不需要复杂的状态管理。纯原生 JS + 模块化拆分,config.js 统一管理 API 地址和 Token,各功能模块独立 init。沙盒探索部分引入 PixiJS 渲染 2D 瓦片地图,Tiled 编辑器制作地图数据。GAL 剧情树使用纯 SVG + 贝塞尔曲线绘制,支持拖拽排版和子树递归渲染。
AI 对话:DeepSeek 接入
NPC 对话通过 DeepSeek API 实现。每次对话拼接 Prompt 包含:NPC 人设 + 记忆数据 + 双层人格约束 + 潮汐上下文 + 好感度修正。AI 缓存 5 分钟有效,同角色 1 秒内不重复调用。后期增加三层防护(Prompt 过滤 + 后处理 + 日志审计),25 个 meta 黑名单。
客户端:Electron + PyInstaller + NSIS
统一客户端基于 Electron 构建,内嵌 Flask 本地服务器提供离线单机模式。Python 后端通过 PyInstaller 打包为独立可执行文件。Windows 安装包使用 NSIS 制作,支持安装版和便携版双渠道发布。本地管理后台采用 pywebview + pystray 技术栈,底层调用 Edge WebView2 渲染。
技术踩坑记录
WebSocket 鉴权
最初尝试在 HTTP 握手阶段做 JWT 鉴权,但 flask-sock 不支持自定义 header。最终方案:连接建立后第一条消息发送 {type: 'auth', token: '...'},服务端验证后才加入频道。
NPC 记忆序列化
NPC 的 memory_data 是 JSON 嵌套结构,衰减时需要深拷贝再裁剪。直接 json.loads → 修改 → json.dumps 性能尚可,但要注意 SQLite 的 TEXT 字段有长度限制,记忆数据需要做容量控制。后期引入 200 字 Token 控制,超出部分按优先级裁剪。
部署备案问题
最初计划用域名 + HTTPS 部署,但个人主体无法备案游戏类网页。最终方案:游戏服务走公网 IP + 端口直连(9000),静态内容站独立部署(80/443)按个人博客备案。两套站点完全隔离,规避了备案限制。
Electron 离线客户端打包
PyInstaller 打包 Python 后端时遇到多个陷阱:hidden-import 命名不一致导致模块缺失、中文路径下 extract-zip 静默失败、frozen 模式下路径解析异常。最终通过 spec 文件精确配置 + .NET 手动解压 + 运行时路径检测三层防护解决。
Windows .bat 文件编码陷阱
CMD 使用 GBK 解析 .bat 文件,UTF-8 编码的中文会被当成命令执行导致启动失败。所有含中文的 .bat 启动脚本必须保存为 GBK 编码,chcp 65001 无法可靠修复此问题。
暗色主题适配
游戏前端从浅色迁移到暗黑悬疑风格时,遇到大量 CSS 变量覆盖问题。最终用 dark-core.css 定义 21 个令牌的 CSS 变量体系 + dark-pages.css 做页面级覆盖,body:not(.player-page) 隔离两套后台风格。8 层径向渐变实现深海背景 + 毛玻璃全局效果。
工程化实践
- Git 版本管控:规范提交格式
<type>: <描述>(feat/fix/refactor/style/docs/chore) - 代码格式化:Python 用 black + ruff,前端用 prettier(2空格/单引号/尾逗号)
- 依赖锁定:requirements.txt 精确版本,禁止
>=松散写法 - 安全红线:config.py / start_server.py / game.db / *.log 已在 .gitignore 中
- 定时任务:6 个后台循环任务(潮汐广播/衰减循环/NPC生成/资源刷新/自动存档/风控清理)
- 蓝绿部署:20 文件 / 4 新服务 + 10 API + 6 WS / 3 层架构,零停机发布
- 灰度发布:Nginx 分流 10% → 50% → 100% / 状态机 5 态 / 异常自动回滚
- 迁移引擎:split 状态机替换 + 单引号转义修复 / 293 文件批量迁移 / 乐观锁 + 多版本备份
关于本站
- 内容定位:原创世界观设定、开发随笔、设计素材分享
- 合规声明:本站按个人博客/随笔类目备案,不含游戏服务功能
- 隔离原则:本站与游戏服务(公网 IP:9000)完全独立,无任何代码、数据、部署关联
- 下载服务:本站在下载页提供桌面客户端安装包下载(v2.0.0),支持离线单机与云端联机双模式
- 更新频率:随开发进度不定期更新
做游戏是一件孤独但有趣的事。写下这些设定和踩坑记录,既是给自己留档,也是给同样在独立开发路上的人一点参考。
如果你看到了这里,感谢你的耐心。
玩家反馈
遇到 Bug?有剧情建议?想看到更多内容?
直接在下方提交,数据直达管理后台反馈看板。每一条反馈都直接影响开发方向。
其他联系渠道
也可以在游戏内通过右下角反馈按钮直接提交,
或加入玩家交流群与开发者直接沟通。