纯 AI 编写的 Cocos Creator 2D 角色成长与装备玩法原型 olua
WebCoderT/olua
开发者 WebCoderT 开源了 olua,一个完全由 AI 编写代码的 2D 角色成长与装备玩法原型,人只负责提需求和看效果。项目基于 Cocos Creator 3.8.7 客户端、NestJS 12 服务端与 React 19 管理后台三端,覆盖登录、角色成长、装备、地图探索与自动战斗,含 555 件装备、100 阶军衔与 37 阶战魂系统。
English | 简体中文
本项目是一个纯 AI 编写的项目(Vibe Coding):仓库里的每一行代码都是 AI 写的,没有一行是人手写的。 人在这里只做两件事 —— 提需求、看效果。具体怎么做的、留下了哪些痕迹,见 一个纯 AI 编写的项目。
一个基于 Cocos Creator 3.8.7 的 2D 角色成长与装备玩法原型 + 配套的 NestJS 服务端与 React 管理后台, 聚焦登录、角色创建、角色成长、装备系统、地图探索与战斗玩法(打怪 / 掉落 / 技能 / 自动战斗)的完整三端演示。
三个端
仓库按端分成三个平级目录,各自有独立的 README 与 FAQ;跨端的约定与机制放在本文件与根 FAQ.md。
| 端 | 是什么 | 技术栈 | 目录 | 文档 |
|---|---|---|---|---|
| 客户端 | Cocos Creator 游戏(登录 / 选角 / 战斗 / 背包 / 商城…) | Cocos Creator 3.8.7 + TypeScript | client/ |
README · FAQ |
| 服务端 | 账号 / 角色 / 管理接口,SQLite 落库,Swagger 文档 | NestJS 12 + node:sqlite + JWT |
server/ |
README · FAQ |
| 管理端 | 运营后台(账号 / 角色 / 管理员 / 操作日志) | React 19 + Vite + Tailwind v4 | admin/ |
README · FAQ |
三端的关系:客户端是玩家玩的游戏,服务端是它唯一的权威数据源(本地只是缓存),管理端给运营改数据。 接口契约由服务端单向生成到另外两端(见 接口文件为什么是生成的)。
client(Cocos) ─┐
├─→ server(NestJS + SQLite) ←─ admin(React)
admin(React) ─┘ ↑ 唯一手写接口的地方
└─ swagger:emit → openapi.json → gen-api → 两端接口文件
项目简介
这个项目目前包含以下几部分:
- 登录场景、角色选择与创建场景
- 游戏场景主循环与地图切换(Loading 过渡场景,带进度显示)
- Tiled 地图渲染与对象组驱动:NPC 点位、复活点出生、矩形刷怪区、碰撞区
- 小地图(HUD):底图用当前地图的 preview.jpg,按视野等比缩放并随角色平移,红点落在底图上的位置即怪物真实位置
- 路线指示线:自动寻路(点击寻路 / 快速攻击追怪 / 自动挂机)期间,大地图地面与右侧小地图同时画出「角色 → 目标」的白色点状路线,终点用更大的白圈标出目的地(同一处路径数据,终点随目标移动实时更新)
- 角色属性、等级与成长系统(HP / MP / 攻防区间 / 每秒回血 / 战斗力)
- 装备系统:穿脱、属性汇总、内外观(8 方向外观位置 / 缩放 / 旋转)、未穿衣服时按性别显示默认身体(男 role/1 / 女 role/2)、装备详情弹窗(三段式着色名称 / 等级 / 部位 / 属性区间)
- 装备前后缀变体:前缀(普通 / 强化 / 精良 / 极品 / 超神)× 后缀(人级 / 天级 / 神级)每件基础装备展开 15 个变体,属性按倍率逐项缩放,名称与文字按品质着色
- 装备品质边框与详情背景:背包格与身上装备图标按前后缀组合显示发光边框动画(resources/borders 84 张图集全登记),悬停详情弹窗按同一组合切换背景动画(resources/backgrounds 41 个帧序列目录全登记);两者均取前 15 套按强度分配给 15 种组合,其余留给特殊装备的自定义表
- 战斗系统:技能触发统一入口、冷却(按动作速度折算)、魔法消耗、伤害飘字、击退、突进位移(十步一杀:鼠标落点瞬移 + 落点特效)
- 怪物系统:区域刷怪、AI 行为(待机游走 / 主动追击 / 受伤激怒追击 / 普攻)、死亡动画、信息面板、选中光圈
- 死亡与复活:怪物死亡倒地动画播完才消失;角色死亡停帧锁操控,弹窗选择原地复活 / 回复活点安全复活
- 经验与等级:击杀按角色与怪物等级差结算经验(差值越大越少,差 6 级以上无经验),升级属性重算并补满状态
- 掉落系统:按权重概率掉落、掉落件数按每只怪配的区间随机(如
[1, 10]= 本次掉 1~10 件,可重复命中同一物品)、掉落物同心环散落互不重叠、走上去自动拾取 / 点击拾取;每只怪的掉落列表独立配置在configs/monsterDrops(key 与怪物一一对应),条目逐条配权重 / 概率 / 数量,555 件装备按等级分段铺满全部怪物 - 掉落光柱:装备落在地上时按前缀品质播放光柱特效(resources/effect/light 6 套全登记,前 5 套按普通→超神自动分配、第 6 套预留给特殊装备的自定义表);地面掉落名按「前缀 + 名称 + 后缀」三段着色
- 商城系统:底部「商城」入口,系统内全部装备(555 件含前后缀变体)自动上架,默认 1 绑定元宝/件,购买直接进背包;门面式弹窗 + 卡片网格分页浏览(一行 3 张、每页 6 件),悬停图标看完整详情
- 背包操作:一键整理(合并同类可叠加物 + 按等级/部位重排,从第一格起铺满、空格沉底)、拖动物品换格(空格移动 / 同种合并 / 其余交换,拖物品不带动弹窗)、拖出弹窗松手 = 整格销毁(全屏确认框:确定销毁 / 取消回原位)、一键回收为绑定元宝、丢弃模式整格丢弃(不可恢复);整理与移动规则均为纯函数、可单测
- 自动战斗:快速攻击与自动挂机开关,基于 A* 寻路绕障碍走位
- 状态(Buff)系统:技能附加状态、身上循环特效、头像下方图标条
- 悬停详情:鼠标放在状态图标上显示名称 / 介绍 / 剩余时间,放在技能格上显示技能名称 / 介绍 / 冷却等基础信息
- 战魂系统:37 阶成长线(外观取自 war-soul 素材),绑定元宝升级,属性计入战力与地图进入条件,可勾选外显到主角右上角;弹窗入口在角色信息弹窗「战魂」按钮(与「军衔」「称号」三格竖排相邻,NPC 战魂使者仍可用)
- 称号系统:34 个带字名牌动画(resources/titles 全登记)排成 1~34 阶成长线,解锁/升级流程与战魂一致(绑定元宝价格曲线),属性按曲线生成;解锁后名牌常显在角色头顶信息栏(与军衔红字/血条同一节点),弹窗入口在角色信息弹窗「称号」按钮(不走 NPC)
- 军衔系统:100 阶成长线(10 大段 × 10 阶:兵卒 → 校尉 → 都尉 → 中郎将 → 将军 → 重号将军 → 公卿 → 王爵 → 神将 → 神话),绑定元宝晋升,属性按「等效等级裸属性 × rate × 大段 factor」生成(夹在称号与战魂之间);军衔没有素材,它的外观就是角色头顶信息栏血条上方那行红字,晋升后立即更新;弹窗入口在角色信息弹窗「军衔」按钮(三格最上),左栏 100 阶列表只在打开时建一次、切换选中不重建
- 每秒血量回复:等级 / 防御装备 / 战魂 / 称号 / 军衔 五处来源相加成一项属性(每秒 N 点),游戏主循环每秒结算一次并落盘(与回蓝共用同一次写档);强度按最大生命比例派生(默认每秒回 1%,整体调速只改
configs/growth.attributeRange.hpRecoverRate一个数);只有防御部位装备带回血(衣 40% / 头 20% / 腰带 20% / 鞋 20%);死亡期间不回复、回血不计入战斗力(不会抬高任何地图的战力门槛)、怪物不回血;旧存档自动补字段 - 头顶显示口径:角色名称显示在人物区域正中间(与怪物名称同一套「身体中心」口径,位置随 roleBody 高度自动居中);头顶信息栏只留军衔红字 / 血条 / 血量文字,称号名牌动画插在最上方
- 弹窗层级:同屏打开多个弹窗时,点哪个哪个浮到其它弹窗之上(触摸与鼠标两条输入通道都接管;飘字提示、悬停物品详情这类临时层仍在弹窗之上,全屏确认框与死亡遮罩保持盖住弹窗)
- 地图传送:传送官弹窗按地图类型分类展示,等级/战力/战魂未达标的地图点击时提示
- 小地图弹窗:读取地图目录 preview.jpg 大图预览,左键点击自动寻路、右键点击直接传送
- 资源预加载:进图前预载地图、NPC / 怪物帧动画与角色穿戴外观
- 操作摇杆:左下角常驻摇杆(底座 + 可拖动手柄),按住拖动即移动 —— 拖得少走路、拖得多跑动(死区/阈值见 configs/role.joystickMove);只用触摸通道,桌面端鼠标按住拖动同样可用,摇杆上的按压不穿透、拖动结束也不会误清选中目标
- 屏幕适配:铺满窗口(NO_BORDER)不留黑边,常驻 HUD 按可见区贴边重排;选角场景整块舞台等比缩放(contain),窗口宽高比与设计不一致时元素也不会跑到屏幕外
- 服务端:账号注册登录(scrypt 加盐摘要)、角色数据云端保存(防抖合并推送)、修订号乐观锁、两套令牌受众、权限点守卫、登录限流、口令重置与令牌主动作废、操作审计日志、公告发布与全服触达、邮件通道(模板 + 投递队列 + 失败重试)
- 管理端:账号与角色管理(六维筛选 / 结构化编辑 / 批量删除)、管理员与权限、操作日志查询、我的账号
一个纯 AI 编写的项目
这个仓库里的每一行代码都是 AI 写的。 客户端(Cocos Creator)、服务端(NestJS)、管理端(React),
以及 client/tools/ 与 tools/ 下的全部单测与审计脚本、README.md / FAQ.md 这些文档 —— 没有一行出自人手。
这是一个 Vibe Coding 项目:人不写代码,人只用自然语言提需求、跑起来看效果、说哪里不对,剩下的全部交给 AI。
人和 AI 各自干了什么
| 人 | AI | |
|---|---|---|
| 负责什么 | 提需求(「加个军衔系统」「后台要能改角色属性」)、看效果、指出哪里不对、在几个方案里拍板 | 读现有代码 → 设计方案 → 写实现 → 写单测与审计脚本 → 自查回归 → 同步文档 → 按功能提交 |
| 不负责什么 | 不写代码、不查 API 文档、不手工调格式 | 不拍板 —— 拿不准的方案会先把选项摆出来问 |
这套做法留在仓库里的痕迹
- 每个踩过的坑都会变成一个脚本。这里不靠记性防回归,靠自动化守卫:
client/tools/下有 25 套单测、tools/下有 7 套审计,比业务代码还密 —— 配置有没有外泄、接口地址有没有硬编码、生成物与服务端文档是否逐字节一致、战斗规则快照有没有漂移、服务端算的属性与客户端是不是同一份、界面点击会不会穿透到世界,全都有脚本盯着。 - 一切可调的东西都收进
client/assets/configs。数值、文案、布局、配色、时长、资源路径都不写进逻辑里。这条约定是被「AI 反复改数值」逼出来的,不是为了好看。 - 接口文件全部由服务端 Swagger 文档生成。三端签名对不上会编译报错,而不是线上出现一个
undefined。这同样是为了让 AI 改完一端后,另一端在编译期就被拦住。 - 回归是硬门槛。每次改动都要跑:服务端 e2e(248 + 77 + 279 + 108 + 25 条)+ 两端类型检查 + 25 套单测 + 7 套审计,全绿才算完。
- 每处理完一个问题就按功能提交一次。改完一个功能立刻落一次 commit,不留一堆混在一起的未提交改动 —— 这样「哪次改动引入了回归」永远能二分出来。
- 踩过的坑写进了 FAQ。每端目录下的 FAQ 收纳该端的具体问题,跨端的机制与环境坑在 FAQ.md;里面的每一条都是真实撞过的,包括环境坑(例如某类终端注入的
NODE_OPTIONS会让服务端静默起不来)。
期望管理
代码经过了完整回归、能跑通,但请把它当成一件 AI 的作品来看:结构上的取舍以「先跑起来再收敛」为主, 有些抽象(配置与逻辑分离、生成物 + 守卫、纯函数 + 单测)是为了让 AI 后续能安全改动而专门设计的,不一定是人类手写代码时的第一选择。
如果你想知道 AI 到底能把一个项目做到什么程度 —— 下面这份「功能清单」就是答案。欢迎 review、提 issue、拍砖。
游戏截图
登录
角色选择与创建
游戏主界面(角色信息 / 背包 / 技能弹窗)
技能列表
怪物与战斗
装备掉落光柱(地面掉落物按前缀品质播放光柱特效:普通→超神 5 档自动分配,第 6 套预留给特殊装备)
小地图预览弹窗(大图预览 + 怪物红点 / NPC / 刷怪区;左键点击自动寻路、右键直接传送)
战魂系统
装备品质边框与详情背景(背包 15 种前后缀品质边框;悬停详情弹窗显示按品质切换的背景动画)
商城(系统内全部装备上架,一行 3 张卡片、每页 6 件分页浏览;悬停图标看完整详情)
目录结构
olua/
├── README.md · FAQ.md # 总览与跨端问题(本文件)
├── client/ # 客户端:Cocos Creator 工程(用它打开这个目录)
├── server/ # 服务端:NestJS
├── admin/ # 管理端:React
├── tools/ # 项目级脚本(跨端)
├── website/ # 项目官网(纯静态单页)
├── public/ # 截图与联系方式二维码
├── docs/ # 项目文档(简历介绍等)
└── equip-aligner/ # 装备素材偏移对齐小工具
client —— 客户端(Cocos Creator 工程)
约定:核心代码只做「怎么跑」,一切可调的东西都在
assets/configs—— 数值、文案、布局、配色、时长、资源路径都不写在逻辑里。 自查:node tools/audit-config-leak.cjs(在仓库根跑;扫出散落在 ui/ 里的可配置项与未登记的文案 key)。
下列路径均相对
client/(即assets/configs的完整路径是client/assets/configs)。
- assets/configs:数值与静态配置(按域一文件:role/monster/skill/equipments/items/drop/map/status/border/background/title/light/mall 等)
- configs/texts:面向玩家的全部文案(浮动提示 / 校验原因 / 界面标签 / 悬停详情 / 加载进度,带
{占位符}模板) - configs/bottomNav:底部功能入口表(名称 / 图标 / 解锁等级 / 快捷键)
- configs/network:客户端唯一的服务端地址来源(根地址 / 超时 / 重试 / 角色进度同步防抖间隔)
- configs/layout:UI 布局与样式(hud / dialogs / panels / scenes / borders / backgrounds / lights / images / sizes / theme)
- configs/texts:面向玩家的全部文案(浮动提示 / 校验原因 / 界面标签 / 悬停详情 / 加载进度,带
- assets/types:纯类型声明(common/role/animation/good/skill/map/monster/drop/status/border/background/title/light)
- assets/entities:运行时实体(Role)
- assets/skills:技能行为实现(技能实现只依赖 SkillContext,不反查全局)
- assets/ui:界面脚本
- ui/core:静态管理器(GameHelper/LayerManager/MonsterManager/MonsterAI/DropManager/SkillManager/StatusManager/EffectManager/AutoBattle/PreloadManager/StorageManager/RoleUIManager/SceneManager 等)
- ui/components:按职责分组(hud/panel/dialogs/role/input/map)
- ui/helpers:UI 生成(UiHelper 基础封装 / GameUiHelper 零件库 / AnimationHelper 帧动画)
- ui/utils:纯函数工具,按功能域分目录(battle/drop/map/physics/resource/input/cursor/layout/node)
- ui/utils/net:对服务端的全部访问
- 生成物(禁止手改):
ApiRoutes路径表 /ApiModels类型(服务端 DTO 的镜像)/Api接口方法(HealthApi·AuthApi·RoleApi) - 手写:
HttpClient二次封装与统一调度 /ApiCodes业务码与文案 key /ApiError错误归一 /Session会话 /RoleSync进度同步 /NetworkSetup接线
- 生成物(禁止手改):
- assets/resources:资源目录(地图 tmx、帧动画、图集、图标、UI 素材)
- assets/scenes:登录、角色选择、加载和游戏场景
- tools:客户端专属脚本(25 套单测 +
gen-monster-config.cjs/gen-monster-drops.cjs配置生成器 +clean-role-empty-frames.cjs素材清理 +lib/单测沙箱) - settings / profiles / native / package.json / tsconfig.json:Cocos 工程配置(
package.json是 Cocos 的工程描述,不是 npm 脚本) - library / temp / build:Cocos 缓存与构建产物(不进版本库)
- 详见 client/README.md,问题见 client/FAQ.md
server —— 服务端(NestJS)
- src/common:统一响应包裹、业务码、守卫(认证 AuthGuard / 权限 PermissionGuard)、过滤器、拦截器、装饰器
- constants/permission:权限点与管理员角色的唯一来源(角色 → 权限映射;文档上的「所需权限」由它反查生成)
- constants/swagger-tags:文档分组(公共接口 / 客户端 / 管理端)
- interceptors/audit.interceptor:管理端写接口自动记日志(动作取
operationId,口令类字段落库前打码) - security:登录限流的纯函数判定(
rate-limit.util)+ 内存计数器服务(login-throttle.service)
- src/database:SQLite 连接与六张表(accounts / roles / admins / audit_logs / announcements / mail_queue,含存量补列)的仓储层
- src/modules:auth(玩家认证)/ roles(角色)/ admin(管理端:认证 / 账号 / 角色 / 管理员 / 口令)/ announcement(公告:公共拉取 + 管理端 CRUD)/ mail(邮件:模板 + 投递队列 + 后台调度)/ audit(操作日志)/ token(JWT)/ health
- src/swagger/setup:文档挂载(抽成函数,好让自动化测试也生成一次文档来验分组 / 权限标注 / 悬空
$ref) - src/swagger/emit:离线产出
openapi.json(npm run swagger:emit,两端接口文件的唯一输入) - openapi.json:机器可读契约(提交进仓库;改接口后必须重新生成,否则两端停在旧契约上)
- test/e2e.cjs:端到端用例(真实起服务 + 真实请求,248 条断言:注册登录 / 角色 CRUD / 越权 / 令牌受众隔离 / 管理端全流程 / 文档分组与权限点 / 四级越权与超管保护 / 公告拉取与时间窗)
- test/e2e-roles.cjs:角色管理专项(77 条断言:修订号乐观锁 / 六维筛选 / 结构化字段校验 / 批量与整账号删除 / 只读观察员越权 / 文档)
- test/e2e-guard.cjs:运营与安全底座专项(279 条断言:口令重置与令牌作废 / 自助改密 / 操作日志落库·打码·筛选·权限 / 按用户名与按 IP 的登录限流 / 踢下线)
- test/e2e-mail.cjs:邮件通道专项(108 条断言:用可注入的假发信器验入队 / 投递 / 重试与用尽上限 / 手动重投 / 未配置 SMTP 时整体禁用;不需要真实 SMTP 服务器)
- 详见 server/README.md,问题见 server/FAQ.md
admin —— 管理端(React)
- src/api:地址配置(唯一来源
config.ts)+ 请求层http.ts(拦截器 / 超时 / 包裹解包 / 错误归一 / 401 跳登录)- 生成物
routes.ts路径表 /models.ts类型 /endpoints.ts接口方法(authApi·accountsApi·adminsApi·rolesApi·auditApi·announcementsApi·mailsApi·statsApi·systemApi) - 手写的
types.ts(业务码 / 权限点 / 动作与目标的中文字典)与index.ts(统一出口)
- 生成物
- src/pages:登录 / 注册 / 概览 / 账号列表与详情(重置密码 · 踢下线 · 清空该账号全部角色)/ 角色列表(筛选 + 多选批量删除)与详情(基础信息 / 常用数值 / 装备·技能·背包结构化编辑)/ 管理员(改角色 · 启停 · 重置密码 · 删除)/ 公告(发布 · 编辑 · 删除 · 启停 + 生效状态列)/ 邮件(发信入队 + 投递记录:状态筛选 · 重试次数 · 失败原因 · 重投)/ 操作日志(筛选 + 分页 + 请求体展开)/ 我的账号(自助改密)
- 界面按令牌里的权限点显隐菜单与按钮(
store/session.hasPermission),服务端仍独立校验 - 详见 admin/README.md,问题见 admin/FAQ.md
tools —— 项目级脚本(跨端)
- gen-api.cjs:由
server/openapi.json产出两端接口文件(唯一的代码生成器,服务端npm run gen:api调它) - gen-battle-rules.cjs:由
client/assets/configs产出服务端战斗规则快照(战斗权威化的地基,详见server/src/modules/combat/)—— 等级 60 / 战魂 37 / 称号 34 / 军衔 100 + 战斗力权重 7 项 + 装备 555 件(已展开前后缀变体) - audit-api-generated.cjs:生成物与文档逐字节一致 / 头标记 / 接口全覆盖 / 类型不悬空 / 路径只在路径表 / Cocos
.meta齐全 - audit-api-hardcode.cjs:三端有没有硬编码地址、请求是否只在唯一出口发出、环境变量键是否都登记进
.env.example - audit-config-leak.cjs:客户端核心代码有没有可配置项外泄 +
configs/texts的 key 是否都被登记(白名单config-leak-allowlist.json) - audit-ui-click-through.cjs:客户端 UI 点击会不会穿透到世界、按压归属的接线是否齐全
- audit-battle-rules.cjs:战斗规则快照与客户端
configs是否逐字节一致(数据漂移不会报错,只会让两端慢慢算得不一样) - audit-combat-parity.cjs:服务端算的角色属性是否与客户端
combatCalc一致(算法漂移)。期望值不是抄一份口径,而是把真的GameHelper.combatCalc编译进 Node 跑一遍 —— 2849 组输入 × 10 项,覆盖全等级 / 全装备 / 全战魂称号军衔
其它
- website:项目官网(纯静态单页:核心特色 / 截图画廊 / 联系方式,logo 与 favicon 在 website/assets/icons)
- public:截图、展示素材与联系方式二维码
- docs:项目文档(
resume.md等) - equip-aligner:装备素材偏移对齐小工具(自带 README 与自检脚本)
技术栈
- Cocos Creator 3.8.7
- TypeScript
- Cocos UI / 2D 场景系统 / Box2D 物理(刚体与碰撞体)
- 服务端:NestJS 12 +
node:sqlite(Node 22 内置,无原生模块依赖)+ JWT(玩家 / 管理端两套受众)+ Swagger - 管理端:React 19 + TypeScript + Vite + Tailwind CSS v4
- 开发方式:全部由 AI 编写(Vibe Coding),人类只提需求与验收 —— 见 一个纯 AI 编写的项目
常用命令(Makefile)
仓库根有一份 Makefile,把三端的常用动作收在一处(make / make help 列出全部,make info 打印当前工具链与关键路径):
make install # 首次:装 server / admin 的依赖 make env # 生成 server/.env(已存在则跳过) make dev # 同时起服务端 :3100 与管理端 :5173,Ctrl-C 一起退出 make client-check # 客户端类型检查(Cocos 自带 tsc,0 错才算过) make client-test # 客户端 25 套单测 make server-verify # 服务端一条命令全验(编译 + 五套 e2e + 生成物审计) make admin-build # 管理端类型检查 + 构建 make gen-api # 改完接口后重新生成契约与两端接口文件 make audit # 7 个跨端审计脚本 make check # 静态检查:客户端 tsc + 管理端 typecheck + 7 个审计 make test # 全部测试:客户端 25 套 + 服务端五套 e2e make verify # 完整门禁:check + 三端构建 + 全部测试(提交前跑这个)
- 单跑一套客户端单测:
make client-test-one T=test-bag-tidy - 换机器 / 换 Cocos 版本:
make TSC=/path/to/tsc client-check - 客户端生成器与清理器:
make client-gen-monster/make client-clean-frames(预演)/make client-clean-frames-apply - 受限终端(被注入了
NODE_OPTIONS)不用特殊处理 —— Makefile 已统一清掉;想用原始环境:make RUN_ENV= <目标>
下面是各端的手工命令,不依赖 make 也能跑。三端的详细说明与全部环境变量见各自的 README。
快速开始
三端的详细说明与全部环境变量见各自的 README;这里是「最短跑通路径」。
1. 服务端(先跑起来,客户端与管理端都依赖它)
cd server npm install cp .env.example .env # 首次:端口 / 密钥 / 上限都在这里;注释里逐项说明 npm run dev # 开发(热编译);或 npm run start 跑已构建产物
- 接口文档(Swagger):http://localhost:3100/api-docs(JSON 在
/api-docs-json) - 健康检查:http://localhost:3100/api/health
- 一条命令全验:
npm run verify(编译 + 五套 e2e + 生成物一致性) - 详见 server/README.md
2. 客户端(Cocos)
- 安装并打开 Cocos Creator 3.8.7。
- 通过 Creator 的 “Open” / “Open Project” 打开
client/目录(它才是 Cocos 工程根)。 - 在编辑器中打开
client/assets/scenes下的场景文件。 - 使用预览或播放按钮运行项目。
客户端没有 npm 脚本,依赖 Cocos Creator 编辑器启动与预览。
连哪个服务端只由 client/assets/configs/network.ts 的 baseUrl 决定(真机调试改成局域网 IP)。
详见 client/README.md。
3. 管理端(React)
cd admin npm install cp .env.example .env.development # 首次:接口根地址在这里(VITE_API_BASE_URL) npm run dev # 开发;npm run build 产出 dist
管理端注册需要在 server/.env 里配 ADMIN_REGISTER_CODE(留空则开放注册),注册时填同一个注册码。
第一个注册的管理员自动成为超级管理员(全部权限),之后的都是普通管理员,要提权由超管在「管理员」页调整。
详见 admin/README.md。
4. 改接口 = 改服务端 + 重新生成
客户端与管理端不手写任何接口文件:接口路径、方法名、请求/响应类型全部从服务端的 Swagger 文档产出。
这样「服务端改一个字段、另外两端忘了改」这类问题会变成编译报错,而不是线上出现一个 undefined。
cd server && npm run gen:api # = swagger:emit + node ../tools/gen-api.cjs
server/src(控制器 + DTO + 装饰器) ← 唯一需要手写的地方
│ cd server && npm run swagger:emit
▼
server/openapi.json(机器可读契约,提交进仓库)
│ node tools/gen-api.cjs
▼
客户端 client/assets/ui/utils/net/{ApiRoutes,ApiModels,Api}.ts
管理端 admin/src/api/{routes,models,endpoints}.ts
改接口的标准动作:
- 改服务端的控制器 / DTO / 装饰器(每个接口必须有
operationId,形如role.save); npm run gen:api重新产出文档与两端接口文件;- 两端
tsc/npm run build—— 有签名不兼容的地方会直接报出来(调用点按报错改)。
生成器认文档里的这几个字段(约定都写进文档,不靠猜):
| 文档里的字段 | 由谁写 | 决定什么 |
|---|---|---|
operationId(<模块>.<方法>) |
@ApiPublicDoc / @ApiPlayerDoc / @ApiAdminDoc 的 operationId |
生成到哪个模块的哪个方法 |
x-olua-audience |
同上(装饰器自动加) | 是否带令牌(public → auth: false) |
x-olua-data-schema / x-olua-data-nullable |
@ApiDataResponse(...) |
响应里 data 的类型(缺省 = null) |
x-olua-query-schema |
@ApiQueryModel(XxxQueryDto) |
query 参数对应的命名类型 |
x-olua-permissions |
@ApiAdminDoc({ permissions }) |
生成物注释里的「所需权限」(方便两端对照) |
生成物禁止手改,tools/audit-api-generated.cjs 会逐条盯着。
契约管线的完整说明见 FAQ.md。
5. 回归门槛
改动合并前至少跑完这三类(全绿才算完)。装了 make 的话就是一条命令:
make verify # = check + 三端构建 + 全部测试手工跑(等价,不依赖 make):
# 客户端:25 套单测(在 client/ 下跑,脚本自己找 Cocos 自带的 tsc) cd client && for t in tools/test-*.cjs; do node "$t" || exit 1; done # 服务端:编译 + 五套 e2e(248 / 77 / 279 / 108 / 25)+ 生成物一致性 cd server && npm run verify # 管理端:类型检查 + 构建 cd admin && npm run build # 项目级审计(在仓库根跑) node tools/audit-api-generated.cjs && node tools/audit-api-hardcode.cjs \ && node tools/audit-config-leak.cjs && node tools/audit-ui-click-through.cjs
在受限环境(例如注入了
NODE_OPTIONS的终端)里跑服务端子进程需要清掉它:env -u NODE_OPTIONS npm run dev。详见 FAQ.md。
功能清单
✅ 已完成 ❌ 未完成 服务端与管理端的细粒度能力见各自 README。
账号与角色
| 功能 | 说明 | 状态 |
|---|---|---|
| 账号注册 / 登录 | 账号存服务端(SQLite),口令 scrypt 加盐摘要;令牌 7 天有效,登录失败不区分「账号不存在」与「密码错误」 | ✅ |
| 角色选择与创建 | 每个账号最多 3 个角色,列表与数据都存服务端;创建的新角色按客户端配置生成(新手装备/背包/快捷键) | ✅ |
| 游戏进度云端保存 | 角色改动(打怪升级 / 拾取 / 买卖 / 换装 / 吃药)自动写回服务端,防抖 1.5 秒合并,切地图与退出前立即补推 | ✅ |
| 旧存档自动迁移 | 新增字段/存储格式变更时读取自动补齐(装备/背包 id 引用制等) | ✅ |
| 删除角色 | 选角界面「管理」进入管理态,各角色头顶出现删除按钮,两步确认后由服务端删除(不可恢复) | ✅ |
| 新角色出生背包 | 通用件 + 全部基础武器/衣服,外加 1 级武器的全部前后缀变体(15 件品质) 一起发进背包,出生即可对比外观与边框 | ✅ |
| 管理端(React) | 管理员登录注册、账号分页检索与封禁、查看账号下的每个角色并改属性 / 切换在线 / 删除、重置玩家口令、踢下线 → admin/README.md | ✅ |
| 后台角色管理 | 六维筛选(关键字 / 在线状态 / 职业 / 性别 / 等级区间 / 账号);全部基础信息可改(名称 / 职业 / 性别 / 等级 / 时装 / 头像 / 所在地图 + 金币 / 元宝 / 银两 / 经验 / 战魂 / 称号 / 军衔);装备 / 技能 / 背包结构化编辑(服务端只校验结构,清单以客户端配置为唯一真相);多选批量删除、整账号清空角色;改名仍受「同账号不重名」约束 | ✅ |
| 后台改动与在线玩家一致 | 角色带修订号(每次落库 +1):玩家推进度时带上它做乐观锁,对不上说明后台改过 —— 服务端拒收、客户端自动拉最新并以它为基线(后台改动优先,玩家的旧存档不会覆盖它);角色被后台删除/踢下线时客户端自愈回选角场景 | ✅ |
| 口令管理 | 玩家忘记口令只能由客服在后台重置(客户端没有找回流程):重置时前端生成随机口令、只显示一次(服务端只存哈希),旧口令与新旧口令相同都会被拒;管理员改自己的密码要验证原密码,成功后服务端下发新令牌(否则改完立刻被自己踢出后台) | ✅ |
| 令牌主动作废 | 改口令会让此前签发的全部令牌立即失效(两表各带 token_version,签发时写进令牌、守卫每次回查库比对)—— 无状态 JWT 光改口令踢不掉旧令牌,这是补上的那一环 |
✅ |
| 登录限流 | 按用户名(默认 5 次 / 10 分钟)与来源 IP(默认 20 次 / 10 分钟)两个维度计数,超限锁定并告知还要等多久;达阈值后计数归零(正常用户被误锁不会「一错再错」);阈值与开关都在 server/.env,反代的 TRUST_PROXY 陷阱有注释说明 |
✅ |
| 踢下线 | 后台一键清掉账号的在线角色;只清标记是拦不住的(玩家本地还在跑),所以服务端同时拒收该账号非在线角色的存档推送(业务码 20007),客户端收到后飘字并回选角界面 —— 角色数据完好,重选一次即可继续 | ✅ |
| 操作日志 | 管理端写操作自动留痕(动作取接口的 operationId,新增接口零额外工作;读接口不记);口令 / 令牌 / 注册码一类字段落库前递归打码;登录成功与失败都记(含来源 IP 与尝试的账号名);带筛选(关键字 / 动作 / 目标 / 结果 / 时间范围)与分页界面;写日志永不影响主流程(内部吞异常 + 超量自动清理最旧的) |
✅ |
| 权限管理 | 管理员分三级(超级管理员 / 管理员 / 只读观察员),权限点粒度到「每个接口」(查看 / 封禁 / 删除 / 改角色 / 重置口令 / 查日志 / 发公告…);权限点唯一来源 + 守卫实时校验,界面按权限显隐;保护最后一个启用中的超级管理员 | ✅ |
| 公告发布 | 运营在管理端发布「标题 / 正文 / 级别(重要优先展示)」并设定生效时间窗(可立即生效 / 不设截止),停用即下架;「是不是生效中」由服务端判定(与玩家侧拉取同源),管理端只展示、不拿本地时钟自己算 | ✅ |
| 邮件触达 | 运营按模板给玩家发信:只入队不等投递(后台调度器发,失败指数退避重试、用尽上限标失败并留原因),投递记录可查状态 / 重试次数 / 失败原因并支持重投;未配 SMTP 时通道整体禁用(明确报错而不是静默丢信);模板是数据、必填变量缺失即拒发 | ✅ |
| 接口文档 | Swagger 抛出(/api-docs),按公共接口 / 客户端 / 管理端三组展示;每个接口标出令牌要求与所需权限点;统一响应包裹 + 业务码 |
✅ |
| 泡点活动 | 持续获得经验,经验条与等级动态更新 | ✅ |
地图与场景
| 功能 | 说明 | 状态 |
|---|---|---|
| 场景切换与 Loading 过渡 | 换图/进图带进度显示 | ✅ |
| Tiled 对象组驱动 | NPC 点位、复活点、矩形刷怪区、碰撞区 | ✅ |
| 复活点出生 | 进图/传送统一从 revive 点出生 | ✅ |
| 小地图 | 真实地图底图(地图 preview.jpg 按视野等比缩放、随角色平移)+ 名称/世界坐标/角色黑点/附近怪物红点/寻路路线 | ✅ |
| 小地图预览弹窗 | 读取地图目录 preview.jpg,左键点击自动寻路、右键点击传送;NPC 白点与名称、刷怪区名称、寻路路线 | ✅ |
| 地图传送官弹窗 | 按 MapType 分类,标题 + grid 排列传送按钮,新增地图自动扩展 | ✅ |
| 地图进入限制 | 等级/战力/战魂未达标时拦截传送并提示原因 | ✅ |
| 碰撞范围调试可视化 | 按开关显示碰撞框(角色/障碍/怪物配色区分) | ✅ |
角色成长
| 功能 | 说明 | 状态 |
|---|---|---|
| 等级属性成长 | 按等级生成攻击/防御区间,战斗力计算 | ✅ |
| 击杀经验 | 按角色与怪物等级差衰减(差 ≥6 级无经验),击杀位置飘字 | ✅ |
| 升级流程 | 属性重算、血蓝补满、升级特效 | ✅ |
| HP / MP | 血球魔法球、头顶血量实时刷新、魔法自然回复 | ✅ |
| 战魂系统 | 37 阶单一成长线,左中右三栏弹窗,绑定元宝升级;入口 = 角色信息弹窗「战魂」按钮(紧邻「称号」),NPC 战魂使者仍可用 | ✅ |
| 战魂属性生效 | 各阶属性计入角色属性与战斗力,并作为地图进入条件 | ✅ |
| 战魂外显 | 弹窗勾选后当前等级战魂动画挂主角右上角,切图/重登保留 | ✅ |
| 称号系统 | 34 个带字名牌动画(resources/titles 全登记)排成 1~34 阶成长线;解锁/升级流程与战魂一致(绑定元宝价格曲线),属性按「等效等级裸属性 × rate × 系列 factor」生成 | ✅ |
| 称号外显 | 解锁后名牌常显在角色头顶信息栏(与名称/血条同一个节点,原生尺寸不缩放),无开关、切图/重登保留;入口在角色信息弹窗「称号」按钮(紧邻「战魂」,不走 NPC) | ✅ |
| 军衔系统 | 100 阶(10 大段 × 10 阶)单一成长线,左中右三栏弹窗 + 军衔徽记;绑定元宝晋升(价格 = 30 × N²),属性按「等效等级裸属性 × rate × 大段 factor」生成(满衔 ≈ 裸属性 52.5%,夹在称号 39% 与战魂 67% 之间) | ✅ |
| 军衔外显 | 军衔名以红色文字常显在角色头顶信息栏血条上方(角色名称之下,军衔没有素材、这行红字就是它的外观),未授衔留空、晋升后立即更新,切图/重登保留;入口在角色信息弹窗「军衔」按钮(与「战魂」「称号」三格竖排相邻,不走 NPC) | ✅ |
| 战魂数值与消耗逐级手调 | 升级消耗与属性为公式占位,待逐级调整 | ❌ |
装备与物品
| 功能 | 说明 | 状态 |
|---|---|---|
| 装备穿脱与属性汇总 | 穿戴校验(等级/性别/职业),换装实时重算 | ✅ |
| id 引用制存储 | 装备槽/背包存物品 key,改配置重启即生效 | ✅ |
| 内外观显示 | 8 方向外观位置/缩放/旋转、内观位置、前后缀与标签 | ✅ |
| 装备/物品配置 | 12 衣服、20 武器及戒指/项链/鞋/盔/带,带图标与文案 | ✅ |
| 装备前后缀变体 | 前缀 5 档 × 后缀 3 档,每件展开 15 变体(共 555 件),属性按倍率缩放、名称品质着色 | ✅ |
| 装备品质边框 | 背包与身上装备图标按前后缀组合显示发光边框动画(resources/borders 84 张图集全登记,前 15 张按强度分配给 15 组合),特殊装备可配自定义边框 | ✅ |
| 装备详情弹窗 | 三段式着色名称、等级/部位、回收价、属性区间与基础信息;悬停位置由纯函数摆放(尽量靠屏幕中间 + 整块留在可见区,任意窗口尺寸/任意格子都完整可见) | ✅ |
| 装备详情背景 | 详情弹窗按前后缀组合显示品质背景动画(resources/backgrounds 41 个帧序列目录全登记,前 15 个按强度分配给 15 组合),特殊装备可配自定义背景 | ✅ |
| 掉落系统 | 权重掉落表、件数区间随机([1,10] 掉 1~10 件)、同心环散落不重叠、自动拾取/点击拾取 |
✅ |
| 每怪独立掉落表 | configs/monsterDrops 一只怪一份列表,条目逐条配权重/概率/数量 + 掉落件数区间;药品材料按等级分档、装备按等级段铺满 555 件变体 |
✅ |
| 背包一键整理 | 弹窗底部一键:合并同类可叠加物 + 按等级/部位重排,从第一格起铺满、空格沉底,算法纯函数可单测 | ✅ |
| 背包拖动物品 | 按住物品拖到别的格子:空格 = 移动、同种可叠加 = 合并(超上限留原格)、其余 = 交换;幽灵图标跟随 + 落点高亮,拖物品不会带动整个弹窗,规则纯函数可单测 | ✅ |
| 背包一键回收 | 弹窗底部一键:背包里的装备换成绑定元宝(身上穿着的不算),价 = 等级曲线 × 前后缀倍率,两步确认后生效 | ✅ |
| 背包丢弃物品 | 把物品拖到背包弹窗外面松手 → 全屏确认框(确定 = 整格销毁、取消 = 物品回原位);另有弹窗底部「丢弃」进入丢弃模式点格子丢弃(两步确认)。不限物品大类,与「一键回收」并存 | ✅ |
| 通用确认框 | components/dialogs/ConfirmDialog:全屏模态黑幕 + 面板 + 确定/取消,自己独占触摸与鼠标两路输入(下层 UI 与世界都点不到);文案由使用方从 configs/texts 传入 |
✅ |
| 装备数值填写 | 战斗数值逐件调整 | ❌ |
| 背包叠加数量角标 | 格子显示可叠加物品数量 | ❌ |
| 掉落物名称前后缀 | 地面掉落名按「前缀 + 名称 + 后缀」拼全并三段着色(前缀/名称用前缀色、后缀用后缀色),与装备详情弹窗同走一套取色规则;非装备仍单行白字 | ✅ |
| 装备掉落光柱 | 装备落在地上时图标下方播放品质光柱动画(resources/effect/light 6 套全登记,前 5 套按前缀普通→超神自动分配、第 6 套预留给特殊装备自定义表),进图预载 | ✅ |
| 商城系统 | 底部「商城」入口(M):系统内全部装备(555 件含前后缀变体)自动上架,默认 1 绑定元宝/件,购买直接进背包(余额不足/背包满不扣钱不改包);弹窗即商城门面背景(resources/mall/bg),商品一行 3 张卡片、每页 6 件分页浏览(翻页整页重建,打开不卡顿),悬停图标看完整详情;商品与价格见 configs/mall |
✅ |
战斗与技能
| 功能 | 说明 | 状态 |
|---|---|---|
| 技能系统 | 统一触发入口、冷却/耗蓝/距离校验、特效、击退 | ✅ |
| 键盘 + 鼠标双操控 | WASD/SHIFT + 左键走右键跑、拖动实时改向、左键点怪攻击/右键选中 | ✅ |
| 自动战斗 | 快速攻击/挂机开关,A* 寻路绕障碍,卡住换目标 | ✅ |
| 路线指示线 | 自动寻路期间大地图地面 + 小地图同步绘制白色点状路线(终点大白圈) | ✅ |
| 状态 Buff | 技能附加状态、身上循环特效、图标倒计时 | ✅ |
| 突进技能(十步一杀) | 按鼠标位置瞬移:范围内落鼠标点、范围外按技能距离取最远落点,落地播放特效 | ✅ |
| 状态数值接入伤害 | 格挡/减伤/加防等数值效果参与结算 | ❌ |
| 怪物技能 | 怪物释放配置的技能(当前只会普攻) | ❌ |
| 玩家受击反馈 | 受击动作/飘字等表现完善 | ❌ |
怪物
| 功能 | 说明 | 状态 |
|---|---|---|
| 区域刷怪 | 开图按地图配置的刷怪矩形随机生成 | ✅ |
| 怪物 AI | 待机游走、主动追击、被动怪受伤激怒追击、普攻结算 | ✅ |
| 死亡动画 | 死亡倒地播完才移除节点,缺帧兜底直接移除 | ✅ |
| 怪物地图信息 | 名称居中(主动红/被动黄),头顶血条+血量文字 | ✅ |
| 怪物信息面板/选中光圈 | 点击选中,血量/属性实时显示 | ✅ |
| 怪物配置全量完善 | 220 只怪的可见身体尺寸(contentSize)与外观偏移(outOffset)按素材 auto-trim 实测(client/tools/gen-monster-config.cjs 生成,碰撞盒/点选/血条位置全由它决定,历史上 5~220 号是 0×0 点不中);动作速度收敛为 monsterDefaultSpeedRate 默认表 + 条目可覆盖;主动怪按「BOSS 或身体宽 ≥ 250px」规则铺开(76/220),出售价按等级×定位生成 |
✅ |
| 怪物定时刷新 | 死亡后按周期补充(当前开图生成一次) | ❌ |
死亡与复活
| 功能 | 说明 | 状态 |
|---|---|---|
| 角色死亡流程 | 死亡动画停末帧、锁全部操控、怪物停止追击尸体 | ✅ |
| 复活弹窗 | 黑色半透明遮罩 + 原地复活 / 安全复活(回当前地图复活点) | ✅ |
界面与其他
| 功能 | 说明 | 状态 |
|---|---|---|
| HUD 全家桶 | 角色信息栏/血球/魔法球/经验条/快捷键栏(6 格+冷却)/小地图 | ✅ |
| 悬停详情弹窗 | 状态图标悬停显名称/介绍/剩余时间;技能格悬停显名称/介绍/冷却等 | ✅ |
| 自定义鼠标指针 | 指向怪物攻击指针、指向物品按大类变色 | ✅ |
| 资源预加载 | 进图前预载地图/NPC/怪物/外观帧动画,按目录缓存 | ✅ |
| UI 命中检测 | 点击界面元素不穿透到世界(不打断操作) | ✅ |
| UI 点击不穿透(UI 内部) | 点击元素在鼠标事件通道上同时登记,点弹窗关闭按钮/面板不会触发下层 HUD(如误开小地图弹窗) | ✅ |
| 世界侧按压归属 | 按住走路以按下开始、抬起结束:界面拦下抬起时交还世界侧(不会卡住一直走);按压起点由各界面元素自己登记(记的是引擎给的命中目标,与冒泡顺序无关),登记点一律先过 UITransform 防呆(不会把引擎打崩);点 NPC 不误触发走路、不打断挂机 | ✅ |
| 屏幕适配 | 铺满窗口(NO_BORDER)+ 常驻 HUD 贴边重排;选角场景整块舞台等比缩放,任意窗口宽高比下元素都在可见区内 | ✅ |
| 公告展示 | 登录页:进入登录场景就弹「重要」公告(只弹重要、不按已读过滤),「我知道了」关闭;游戏内:小地图「公告」入口 + 未读红点,公告板左右分栏(左列表按「重要在前」分层、同级保持服务端次序,右正文),打开即把本次生效中的公告标为已读(本次仍看得到哪几条是新的) | ✅ |
| 素材缺口补齐 | 武器每方向后 4 帧、cloth 011/012/013、weapon 005/021 缺失资源 | ❌ |
| 界面布局打磨与命名规范 | 整体视觉与资源命名统一 | ❌ |
文档
| 文档 | 内容 |
|---|---|
| README.md | 本文件:项目总览、三端索引、目录结构、快速开始、功能清单 |
| FAQ.md | 跨端:地址唯一来源、契约管线、三端联动的机制、环境坑、回归怎么跑 |
| client/README.md · client/FAQ.md | 客户端:Cocos 工程怎么打开、客户端架构与约定、预览报错与玩法配置的问题 |
| server/README.md · server/FAQ.md | 服务端:启动与环境变量、数据模型、认证与权限、契约生成、限流与审计 |
| admin/README.md · admin/FAQ.md | 管理端:启动与构建、权限显隐、页面清单、api 层分工 |
| docs/resume.md | 简历用项目介绍 |
素材与联系方式
资源素材过大无法进行版本控制,如果需要请联系我。
来源:GitHub · github.com










