# 像素勇者 **Repository Path**: defiphoenix/Roguelike-A ## Basic Information - **Project Name**: 像素勇者 - **Description**: 一个cocos做的肉鸽游戏 像素勇者 - **Primary Language**: 其他 - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2026-10-29 - **Last Updated**: 2026-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 像素勇者 · 无尽肉鸽 v1.1 一款竖屏像素风 2D 动作肉鸽(Roguelike)游戏,使用 **Cocos Creator 3.8.8** 开发,目标平台为微信小程序,当前已支持 Web Mobile 本地运行。 > 游戏全名:**像素勇者** | 玩法副标题:**无尽肉鸽** --- ## ✨ 功能特性 ### 主页面 - 月夜沙漠背景,像素风 UI - 主按钮区:**开始游戏** / **角色管理** / **无尽试炼**,最下方右侧是一个方形**奖杯**按钮(打开排行榜) - 右上角三个入口:设置齿轮 / 好友 / 礼物盒(兑换码与反馈) - 开始游戏弹窗:单人游戏 / 多人游戏(多人未开放) ### 玩法模式 - **单人游戏(normal)**:40 波,第 10 / 20 / 30 波为精英波、**第 40 波为最终 BOSS**, 击败 BOSS 即「通关成功!」;血量归零则「游戏结束」 - **无尽试炼(endless)**:没有通关、**没有 BOSS**,波数无限,只有死亡才结束; 结算面板会额外显示本局过波数(刷新纪录会标注「新纪录!」)与击败数 - 两种模式的「再来一把」都会**沿用本局模式** ### 战斗系统(无尽肉鸽) - 竖屏 540×960 像素风地图,虚拟摇杆控制移动(固定 / 跟随两种模式,可在设置中切换) - 角色自动索敌攻击(伤害带 0.9~1.1 随机浮动,基础暴击率 6%) - **攻击方式由武器决定**(`chars.weapon`): - **长剑(sword)**:范围挥砍 —— 攻击范围内**所有**敌人同时受伤 - **法镜(staff)**:单体索敌 —— 只打范围内**最近的一个**目标,射出一条魂火青射线(hitscan) - **40 波编排**(单人模式):波间**不清场**(上波活着的怪留到下一波);**第 10 / 20 / 30 波为精英怪波、第 40 波为最终 BOSS**, 进入特殊波时清场一次并弹出全屏横幅(横幅跟随相机固定在屏幕上方);无尽试炼则没有特殊波、波数无限 - **6 种怪、每种独立像素贴图**,体型按阶位递增(普通 < 精英 < BOSS) | 怪 | 攻击方式 | 体型 | 解锁 | |---|---|---|---| | 游魂 | 近战 | 14 | 第 1 波 | | 巫火 | 远程火球 | 13 | 第 5 波 | | 石甲兽 | 近战坦克 | 22 | 第 10 波 | | 精英·重装卫兵 | 近战(脚下金环) | 26 | 第 10 波 | | 精英·巫火术士 | 远程火球 | 24 | 第 20 波 | | 石像王(BOSS) | 近战(脚下红橙双环) | 44 | 第 40 波 | - **远程怪**停在 190~210px 外发射火球弹道(命中才扣血,飞行约 1.6 秒,来得及走位) - 怪的血量 / 攻击 / 速度随波数线性缩放(`config.ts` 的 `scaleHp/scaleAtk/scaleSpeed`) - 怪物被消灭时播放**消散特效**(白闪 + 扩散环 + 像素碎块四散,体型越大越夸张) - **击败最终 BOSS → 清场并直接结算**,弹出「通关成功!」;血量归零则显示「游戏结束」; 通关记录会写到「当前登场角色」上(见「角色管理」的通关印章) - 经验晶掉落自动吸附;**升级**时回满血,并**自动在攻击 / 生命 / 防御中随机一项 +2**, 同时弹出**三选一**面板(前两位出技能、第三位出属性)—— 这次「白送」的那点加成落在哪一项 会写在面板标题下方(如「升级自动奖励:生命上限 +2」),不用再盯着血条猜它为什么没动 - **技能**(各 5 级,Lv4→Lv5 显示「大升级!!」): - **法阵**:脚下展开**像素风魔法阵** —— 外圈 + 符文刻度环 + 内接五角星 + 棋盘格抖动底纹, 图案**左右严格对称**;按固定时间步进做**慢帧(跳帧)旋转**(约 3.9 秒一圈),持续对范围内敌人结算伤害(Lv1-4 蓝色、满级粉色) - **土豆雷**:埋设 → 待机 → 敌人靠近引爆 - **局内道具**:击杀怪物后按概率掉落,走近即自动拾取。概率由管理后台「游戏局内管理」维护, 随 `/api/state` 下发到客户端;默认三种各 **2%**,且**互相独立判定**(概率都很小,几乎不会同时掉) | 道具 | 图标 | 拾取效果 | |---|---|---| | 炸弹 | 圆弹体 + 斜引线 + 火花 | 直接秒杀全图上所有**非精英、非 BOSS** 怪(精英与 BOSS 免疫),并在玩家脚下炸开一场**爆炸特效**(尖刺火球 + 冲击波环 + 四散火花)| | 磁铁 | U 形马蹄(两极朝上,比另两个更小更紧凑) | 把场上所有经验晶**吸向玩家**(缓慢起步、逐渐加速飞向玩家;不弹冲击环、不弹计数浮字) | | 医疗箱 | 白箱 + 红十字 | 立刻**回满血** | 道具直接以纯像素图标落在地上(**不带半透明底衬**,避免在花哨地面上糊成一团色块)。 > 后台把某项概率改成 0 或停用,就是**真的不掉落**(不会回落到默认值)。 > 概率语义:**启用**时可在 `0.01% ~ 100%` 之间填(不能为 0,否则等于「启用了却永不掉落」); > **停用**时概率自动归 0。数据库 `item_drops.rate` 上有 `CHECK(rate >= 0 AND rate <= 1)` 约束, > 即使有人绕过后台直接改库,也写不进 >100% 的值。 - **怪物走路「果冻感」**:移动中的怪身体一胀一缩(横向胀、纵向缩,体积守恒式挤压,像史莱姆一弹一弹地爬, 约 1.1Hz、幅度 ±11%),静止(进入攻击距离)时立刻复原。缩放只作用于挂在怪身上的**视觉子节点**, 逻辑坐标不受影响 —— 索敌、碰撞、命中判定、掉落位置全都仍然精确。 - HUD:血条 + 经验条 + 波数(含难度段位 / 无尽试炼显示「无尽」)+ 场上怪物计数;伤害飘字(暴击为金色大字) - 结算界面按模式区分:**单人只有「获得金币」一行**;**无尽试炼**额外显示本局过波数、历史最高纪录与击败数。 胜负两种界面配色不同(胜利金色、失败红色) ### 美术风格 - 全部手搓:像素位图由 `px.ts` 的 `drawPixMap()` 按「字符 → 颜色」点阵绘制,UI 用 `Graphics` + `Label` 直接画, **不使用 ScrollView / 预制体** - 怪物、土豆雷、三种局内道具用多色像素位图;法阵把图形**栅格化到像素网格**(逐格画方块, 网格始终轴对齐 → 旋转时像素依旧是方的,不会跟着歪);死亡特效、炸弹爆炸特效、弹道用 `Graphics` 实时绘制 ### 角色 | 角色 | 武器 | 生命 | 攻击 | 防御 | 攻击范围(格) | 攻击间隔(s) | 获取 | |---|---|---|---|---|---|---|---| | 草莓勇士 | 长剑(范围挥砍) | 10 | 5 | 2 | 3 | 0.8 | 默认拥有 | | 镇魂法师 | 法镜(单体索敌) | 8 | 7 | 3 | 15 | 0.3 | 500 金币购买 | | 山岳霸主 | 长棍(范围横扫 + 旋转棍影) | 15 | 3 | 5 | 2 | 0.5 | 800 金币购买 | > 获取方式可在管理后台「角色管理」里改成 **正常售卖 / 暂停售卖 / 活动获取** > (见「角色管理」一节),`chars.sale_status` 决定游戏内购买按钮的文案与可购买性。 - 登场角色的属性即玩家属性(`battle.applyCharStats` 以服务端数据为准);头像、游戏内立绘 与战斗贴图都按登场角色自动切换(贴图映射见 `config.ts` 的 `CHAR_SKINS`) - 武器类型决定攻击方式:`sword` 范围挥砍 / `staff` 单体索敌 / `club` 范围横扫(额外播「棍子转一圈」特效) - ⚠️ 新角色的贴图不在构建包的 resources 里(热注入加不进构建产物),`CHAR_SKINS` 里标 `url: true` 的会**先试 `resources.load`,失败才退回** `/textures/.png` + `ImageAsset` 运行时加载 (同一张贴图只解析一次,结果缓存在 `_texCache`)。所以在 Cocos 里正式 Build 之后, 这两张图会被打进 resources 包,自动走第一条路,**零额外请求**,代码不用改 - 立绘取景按「证件照」:从肩到头,头顶留 9%、下巴在 61%、底边切在胸口上方 (`tools/gen_peak_portrait.py` 里的 `CROP`,AI 原图是半身像,必须再裁一刀) - 角色美术:精灵图用 `tools/gen_peak_art.py` 这类脚本按 1152×576(6列×3行,48×48 帧 ×4)画; 立绘 1024×1024 由 AI 生成后用 `tools/gen_peak_portrait.py` 统一灰白底并去水印 ### 角色管理 - 地牢拱门背景 + 木板信息面板 - **多角色浏览**:左侧一列圆形头像,点哪个切哪个(含未拥有的 —— 那是购买入口) - 圆形头像框 + 角色待机立绘展示(待机动画循环,按角色加载对应贴图) - 属性面板:生命值、武器类型、攻击力、防御力、攻击范围、攻击间隔、击败数量 (数值全部来自服务端角色数据,非前端写死) - 按钮按「是否拥有 + 售卖方式」出文案: - 已登场 → 灰色「已登场」;已拥有未登场 → 红色「登场」 - 未拥有且**正常售卖** → 金色「购买 · N金币」(点击二次确认后扣金币) - 未拥有且**暂停售卖** → 「限时购买」+ 小字「请关注开放购买时间」(不可购买,仅提示) - 未拥有且**活动获取** → 「活动获取」+ 小字「请关注游戏活动」(不可购买,仅提示) - 售卖方式由管理后台维护(`chars.sale_status`),服务端 `api_buy` 同样会拒绝非正常售卖的角色 - **通关印章**:用过该角色打完 40 波(单人模式通关)后,属性区右下角盖一枚斜置的红色「通·关」印章 ### 昵称与个人资料 - 点击主页面左上角头像名牌 → 修改昵称(最长 12 字,重名校验) - **改名冷却 7 天**:冷却期内面板上方显示「当前冷却期剩余:x天x小时x分钟」,不在冷却期则不显示该行 ### 排行榜 - 主页面奖杯按钮打开,顶部「好友 / 全服」切换 - **历史最高榜(实时更新)**:直接取每位用户的最高通过波数(`users.best_wave`),打出新纪录刷新即见 - 显示前 100 名,每行 = 名次(**1~3 名金 / 银 / 铜奖杯**,其余为数字)+ 圆形头像 + 昵称 + 「最高通过波数:XX 波」 - 底部固定一行「我的排名」,未上榜时名次显示 `-` ### 好友与聊天 - 好友列表(头像 + 昵称 + uid + 未读红点),支持按 uid / 昵称搜索 - 我的 uid 可点击复制,方便分享给好友 - 好友申请:收到 / 发出两个分页,可接受、拒绝、删除 - **屏蔽词打码**:消息里命中后台维护的屏蔽词时,显示为等长 `*` - 聊天窗口:气泡分左右、消息上方自带「日期 + 时间」(昨天显示为「昨天」) - **实时刷新走 WebSocket**(`/ws/chat`):服务端消息一落库就推给收件人,窗口开着立刻可见 - **多行输入**:回车换行(最多显示 3 行,超出自动滚到底部),`Ctrl/⌘ + Enter` 发送;也可以直接点「发送」按钮 - 长消息气泡自动换行并自适应高度,不会溢出边框 ### 兑换码与反馈 - 主页面右上角礼物盒进入 - **兑换码**:输入兑换码换取金币 / 解锁角色(统一转大写比较,同一账号同一码只能领一次) - 标题栏左侧的感叹号图标可切到**反馈页**:填写标题 + 内容提交给后台 - 兑换码由 `tools/gen_redeem.py` 生成(见下文) ### 账号封禁 - 在管理后台封禁某位玩家(`users.banned`)后,该账号打开游戏时:服务端对 `/api/*` 与 `/ws/chat` 一律返回 **403 `{err:'banned'}`**(静态资源照常返回,页面仍能打开),前端随即盖上一层 **不可关闭的全屏提示层**(「账号已被封禁 / 请联系管理员 / 游戏功能已停用」)。 - 提示层会**吞掉全部触摸事件**,各面板入口另有守卫,因此**主菜单任何按钮都点不动**; 被封禁期间**不做任何数据伪装** —— 名字、金币保持原样,只是被遮罩整体盖住。 - 解封后刷新即恢复正常:封禁可逆,不影响存档。 ### 设置 - 音乐音量 / 音效音量 - 摇杆模式:固定摇杆 / 跟随摇杆 - 退出到主页面(当前局游戏直接结束,不结算) --- ## 🛠 技术栈 | 层 | 技术 | |---|---| | 引擎 | Cocos Creator 3.8.8 | | 语言 | TypeScript | | 渲染 | Cocos 内置 WebGL | | 字体 | 像素字体 ZLabsPixel| | 后端 | Python `http.server` + PyMySQL(存档 / 好友 / 聊天 / 排行榜 / 兑换码) | | 管理后台 | Python **FastAPI** + Uvicorn(`admin/`,独立进程,共用同一 MySQL) | | 实时通道 | 手写 WebSocket(`socketserver.ThreadingMixIn`,零第三方依赖) | | 数据库 | MySQL 8(表结构见 `schema.sql`) | | 构建 | web-mobile 平台 | --- ## 📋 环境要求 | 依赖 | 版本 / 说明 | |---|---| | Cocos Creator | 3.8.8(只有在重新构建、或改场景与挂载组件时才需要) | | Node.js | ≥ 18(跑 `_inject.js` 热注入和 `tools/` 下的验证脚本) | | Python | 3.x,需 `pymysql`(`pip install pymysql`) | | 管理后台依赖 | FastAPI / Uvicorn / PyMySQL / PyJWT(见 `admin/requirements.txt`) | | MySQL | 8.x,监听 `127.0.0.1:3306`;默认 `root` / `123456`,见 `server.py` 顶部 `MYSQL_CONF`,与本机不一致就改这里 | > `node_modules` 里只装了一个包 `ws`,供 `tools/` 下的测试脚本做 CDP 调试与 WebSocket 通信用。 --- ## 🚀 快速开始 ### 本地预览 `server.py` 同时提供后端 API(MySQL)和构建产物托管: ```bash python server.py ``` 浏览器访问:**http://127.0.0.1:8200/** > **日志**:两个服务的输出都会自动写到 `logs/`(`server.log` / `admin.log`), > 单文件 5MB、保留 5 份自动轮转,无需清空。所以**不要**再写 `python server.py > _server.log` > —— 日志改动为接管 `print` 后,重定向的文件会一直是空的;直接前台运行即可, > 终端里照常能看到(只有检测到输出被重定向时才关闭终端副本,避免重复写一份不会轮转的文件)。 首次运行会自动建表。想用两个身份互加好友 / 聊天,开两个标签页分别加 `?uid=10000001`、`?uid=10000002` 即可(没有登录体系,用 URL 里的 uid 指定身份)。 > 身份**只认 uid** —— uid 唯一且稳定,改名后依然定位到同一个人; > 昵称可以随时改、还可能重名,所以不能当作身份标识(历史版本支持过的 `?as=<昵称>` 已废弃)。 > 纯静态预览也可以用 `python -m http.server 8200`,但好友、聊天、进度保存 > 这些依赖 API 的功能会不可用。 ### 启动网页管理后台(独立服务) `admin/` 是一个**独立的 FastAPI 服务**,与游戏后端互不影响,共用同一个 MySQL 库: ```bash pip install -r admin/requirements.txt # 首次 python admin/main.py # 默认 http://127.0.0.1:8300/ ``` - 首次启动会自动建 `admins` / `admin_logs` 表,并创建默认超级管理员 **`admin` / `admin123`**(登录后请立刻在「修改密码」里改掉) - 默认**只绑定 127.0.0.1**;需要换地址/端口用 `ADMIN_HOST` / `ADMIN_PORT` 环境变量 - 接口文档:http://127.0.0.1:8300/docs 模块:仪表盘 / 用户管理 / 角色管理 / **游戏局内管理** / 兑换码 / 问题反馈 / 消息审计 / 排行榜 / 账号与日志。 身份分三级:**超级管理员 `super`**(唯一,可见「账号与日志」)/ **管理员 `admin`**(可改数据)/ **只读 `readonly`**; 所有写操作都会记进 `admin_logs` 审计日志。 - **超级管理员受保护**:不可新增、不可把别人改成超管,且超管账号不可被「修改身份 / 重置密码 / 停用 / 删除」 (本人要改口令用右上角「修改密码」)。 - **屏蔽词**:在「消息审计」里点「屏蔽词管理」增删改查。词表由游戏后端 `/api/words` 下发给客户端, 聊天中命中的词会打码成等长 `*`(服务端下发时也会打码,DB 里保留原文供审计)。 - **角色管理**:改数值(生命/攻击/防御/范围/攻速/价格)与**售卖方式**。 **武器类型只读**(它决定攻击逻辑,改错会让表现与手感对不上); 售卖方式分 **正常售卖 / 暂停售卖 / 活动获取**,直接决定游戏内购买按钮的文案与可购买性。 - **游戏局内管理**:改局内道具(炸弹 / 磁铁 / 医疗箱)的**掉落概率**与启用开关。 按百分比填(`0.05` = 0.05%),最多两位小数;**启用时有效值 0.01 ~ 100**,**停用时概率自动变 0**。 悬停/越界的提示文案为「输入值为0.01-100」,越界即时标红并在保存时被前端拦截。 配置写入 `item_drops` 表,游戏端下次拉取 `/api/state` 即生效; 表上另有 `CHECK(rate >= 0 AND rate <= 1)` 约束兜底(防直接改库写出 >100%)。 - **排行榜**:前三名金银铜奖牌 + 头像,行内可直接「清除波数 / 封禁」。 - **封禁**:在「用户管理」或「排行榜」里封禁玩家后,该账号打开游戏会看到**不可关闭的全屏提示层**、 主菜单完全点不动(详见「账号封禁」一节);解封即恢复。 ### 改完代码热更新(免重新构建) ```bash node _inject.js # 把 assets/scripts 下的 TS 转译并注入 build 产物 ``` 然后浏览器 `Ctrl+Shift+R` 强刷。 ### 重新构建 ```bash "C:\ProgramData\cocos\editors\Creator\3.8.8\CocosCreator.exe" --project "<项目路径>" --build "platform=web-mobile;debug=true;buildPath=build;startScene=9f9fd7c4-93f0-3947-0cb9-01300b2bbcfc" ``` --- ## 📁 项目结构 ``` 像素勇者Cocos/ ├── assets/ │ ├── resources/ │ │ ├── textures/ # 游戏贴图 │ │ │ ├── hero.png # 草莓勇士精灵图 1152×576,6列×3行,单帧 192×192 │ │ │ ├── hero_mage.png # 镇魂法师精灵图(与 hero.png 同布局,tools/gen_mage_art.py 生成) │ │ │ ├── portrait.png # 草莓勇士头像 1024×1024 │ │ │ ├── portrait_mage.png # 镇魂法师头像 1024×1024 │ │ │ ├── hero_peak.png # 山岳霸主精灵图(同 1152×576,tools/gen_peak_art.py 生成) │ │ │ ├── portrait_peak.png # 山岳霸主头像 1024×1024(AI 生成 + gen_peak_portrait.py 处理) │ │ │ │ # ⚠️ 这两个走 /textures 直出,不在构建包 resources 里(无 .meta,编辑器首次打开会自动生成) │ │ │ ├── coin.png # 金币图标 200×200 │ │ │ ├── friends.png # 好友图标 1254×1254 │ │ │ ├── dungeon_bg.png # 角色管理地牢背景 1024×2048 │ │ │ ├── wood_bg.png # 角色管理木板纹理 1024×2621 │ │ │ └── menu/ │ │ │ └── login-bg.jpg # 主页面月夜沙漠背景 1080×1920 │ │ └── fonts/ │ │ └── ZLabsPixel.ttf # 像素字体 │ │ ├── audio/ # BGM 与音效(走 /audio/ 路由 + Web Audio,不经 resources) │ │ │ ├── bgm.mp3 # BGM「Chip Bit Danger」(OpenGameArt,CC0) │ │ │ ├── attack/attack_staff/hurt/levelup/click/explosion.mp3(SFXMint,CC0) │ │ │ └── pickup.wav # 拾取经验:MC 风格双音 plink,tools/gen-pickup-sfx.py 合成(原创) │ └── scripts/ │ ├── Game.ts # 主组件:生命周期 + 共享状态 │ ├── Player.ts # 主角移动与动画 │ └── game/ # 按职责拆分的功能模块 │ ├── types.ts # 共享结构类型 │ ├── config.ts # 战斗数值配置表(波次 / 缩放 / 怪表 / 属性池 / 技能表) │ ├── net.ts # 后端 API / 身份参数 / 时间格式化 │ ├── px.ts # 像素位图与绘制 │ ├── ui.ts # 通用控件工厂(按钮/单选/滑块/弹窗) │ ├── input.ts # 文本输入框与剪贴板 │ ├── hud.ts # 血条 / 经验条 / 波数 │ ├── battle.ts # 战斗循环(刷怪/伤害/升级/结算) │ ├── menu.ts # 主菜单与头像名牌 │ ├── settings.ts # 设置面板 │ ├── friends.ts # 好友列表 / 搜索 / 申请 │ ├── chat.ts # 聊天窗口 │ ├── rank.ts # 排行榜弹窗(好友 / 全服) │ ├── redeem.ts # 兑换码与反馈面板 │ ├── sfx.ts # 音效 / BGM(Web Audio:懒加载、音量、静默降级) │ └── profile.ts # 改名与角色管理 ├── server.py # 游戏后端:MySQL + 构建产物托管(8200) ├── schema.sql # 数据库表结构(含 admins / admin_logs) ├── admin/ # 网页管理后台(独立 FastAPI 服务,8300) │ ├── main.py # 应用入口:启动时自动建表 + 建默认超管 │ ├── db.py # 数据库访问层(共用 roguelike 库) │ ├── auth.py # 登录令牌(JWT)+ 密码哈希(PBKDF2)+ 角色权限 + 审计 │ ├── routers/ # 按模块拆分的路由 │ │ ├── auth_routes.py # 登录 / 当前账号 / 改密 │ │ ├── dashboard.py # 仪表盘统计 │ │ ├── users.py # 用户管理(金币 / 昵称 / 冷却 / 封禁) │ │ ├── chars.py # 角色数值 + 给玩家解锁 / 设登场 │ │ ├── gameplay.py # 游戏局内管理(道具掉落概率 / 启用开关) │ │ ├── redeem.py # 兑换码生成 / 停用 / 启用 / 删除 / 流水 │ │ ├── feedback.py # 问题反馈状态流转 │ │ ├── messages.py # 消息审计(游戏端不支持玩家撤回,故无撤回) │ │ ├── ranks.py # 排行榜 │ │ ├── words.py # 屏蔽词增删改查(聊天打码用) │ │ └── admins.py # 管理员账号 + 审计日志(仅 super) │ ├── static/ # 前端单页(无框架:index.html + app.js + style.css) │ └── requirements.txt # 后台依赖 ├── _inject.js # TS 热注入脚本(改完代码免重新构建) ├── logkit.py # 日志模块:接管 print → logs/(5MB × 5 份自动轮转) ├── tools/ # 辅助脚本(本地验证用,不参与构建) │ ├── smoke-test.js # 面板冒烟测试:逐个开/关面板,收集异常并截图 │ ├── chat-test.js # 聊天端到端:双身份验证多行输入 / Ctrl+Enter / 实时推送 / 气泡自适应 │ ├── ws-smoke.js # 只验 WebSocket 通道(握手 + 广播),不经浏览器,最快 │ ├── admin-smoke.js # 管理后台端到端:登录 / 越权拒绝 / 写操作 / 封禁联动游戏后端 │ ├── admin-shot.js # 管理后台页面探针:登录 + 逐个模块截图 + 收集 JS 异常 │ ├── probe-censor.js # 屏蔽词端到端:加词 → 发消息 → 断言气泡里出现 * │ ├── probe-sale.js # 售卖方式端到端:暂停售卖/活动获取时游戏按钮文案与小字 │ ├── probe-ban.js # 封禁端到端:封禁后游戏盖全屏提示层 + 主菜单点不动(真实鼠标点击对照) │ ├── probe-items.js # 升级奖励与连升弹窗 / 局内道具掉落·效果·图标 / 法阵像素旋转(端到端断言 + 截图) │ ├── probe-death.js # 受击闪红·击退·飘字·红晕 / 死亡碎裂 / 结算后摇杆彻底失效(端到端断言 + 截图) │ ├── probe-sqli.js # 管理后台 SQL 注入渗透:登录·鉴权·列表·路径·分页·写接口·错误泄漏(83 项) │ ├── probe-auth.js # 改密后旧令牌立即失效 / 新令牌不被误杀 / 停用仍立刻生效(20 项) │ ├── probe-audio.js # 音频系统:八类音频 fetch+解码 / BGM 循环 / 音量钳制 / 增益分层 / 拾取随机音高(19 项) │ ├── probe-mage.js # 角色管理/战斗内截图探针 │ ├── probe-peak.js # 山岳霸主全链路:角色数据 / 换装帧表 / 长棍横扫范围 / 旋转棍特效生命周期(轴心=手心)/ 立绘(21 项) │ ├── gen-pickup-sfx.py # 拾取音效合成器(MC 风格木质双音 plink,纯 stdlib,可反复重生成) │ ├── gen_redeem.py # 兑换码生成器(命令行版;网页后台也能生成) │ ├── gen_mage_art.py # 镇魂法师像素贴图生成器(精灵图,可反复运行重生成) │ ├── gen_peak_art.py # 山岳霸主像素贴图生成器(壮汉 + 长棍,同 1152×576 帧表) │ ├── gen_portrait.py # 镇魂法师头像后处理(统一背景 + 去水印) │ └── gen_peak_portrait.py # 山岳霸主头像后处理(同上) ├── build/web-mobile/ # 构建产物(web-mobile 单页包,gitignore) ├── library/ # Cocos 资源缓存(gitignore,删了会触发编辑器全量重新导入) ├── temp/ profiles/ settings/ # Cocos 编辑器临时产物与工程配置(gitignore) └── README.md ``` > `assets/scripts/game/*` 不在编辑器构建链路里,通过 `_inject.js` 热注入到 > `build/web-mobile/assets/main/index.js`:改完 TS 跑一次 > `node _inject.js` 再刷新页面即可看到效果。 > 首次注入时 `_inject.js` 会把「未注入」的原始产物留底为 > `index.js.preedit`(只生成一次)。万一注入把包改坏,用它覆盖回 `index.js` > 即可快速回滚,不必重新构建。 > ⚠️ 若构建时 `assets/scripts/game/*.ts` 被补了 `.meta`(编辑器会自动补),Cocos 会把它们 > 当普通项目脚本编进产物,产出**扁平模块名**(`chunks:///_virtual/hud.ts` 而非 `game/hud.ts`), > 且 `main` 按字母序插在 game 模块中间,game 模块不再连续。 > `_inject.js` 已能自动识别这种「错位产物」并修正依赖指向,注入后照常可用; > 最干净的做法仍是构建前删净 `assets/scripts/game/*.ts.meta` 与 `game.meta`。 > 万一注入真把包改坏:`cp index.js.preedit index.js` 即可回滚。 --- ## ✅ 本地验证 改动后不必手动点一遍,`tools/` 下三个脚本可以自动跑(都需要先 `python server.py` 把后端起起来): ```bash cd <项目根> NODE_PATH=node_modules node tools/ws-smoke.js # 最快:只验 WebSocket 握手 + 广播,不经浏览器 NODE_PATH=node_modules node tools/smoke-test.js # 面板冒烟:逐个开/关面板,收集异常并截图 NODE_PATH=node_modules node tools/chat-test.js # 聊天端到端:双身份验多行输入 / Ctrl+Enter / 实时推送 ``` 管理后台(需先同时起 `python admin/main.py` 与 `python server.py`): ```bash NODE_PATH=node_modules node tools/admin-smoke.js # 登录 / 越权拒绝 / 写操作 / 超管保护 / 屏蔽词 / 封禁联动(自动清理测试数据) NODE_PATH=node_modules node tools/admin-shot.js # 无头浏览器走一遍登录 + 各模块,收集 JS 异常并截图 NODE_PATH=node_modules node tools/probe-censor.js # 屏蔽词端到端:加词 → 发消息 → 断言气泡里出现 * NODE_PATH=node_modules node tools/probe-sale.js # 售卖方式端到端:暂停售卖/活动获取时游戏按钮文案与小字 NODE_PATH=node_modules node tools/probe-ban.js # 封禁端到端:全屏提示层 + 主菜单冻结(跑完自动解封还原) NODE_PATH=node_modules node tools/probe-items.js # 升级自动奖励 / 道具掉落与三种效果 / 法阵像素旋转 NODE_PATH=node_modules node tools/probe-death.js # 受击反馈 / 死亡特效 / 结算后摇杆与按键彻底失效 NODE_PATH=node_modules node tools/probe-sqli.js # SQL 注入渗透测试(83 项:登录·鉴权·列表·路径·分页·写接口·错误泄漏) NODE_PATH=node_modules node tools/probe-auth.js # 改密后旧令牌立即失效(20 项,自动建/删临时管理员) NODE_PATH=node_modules node tools/probe-audio.js # 音频系统(19 项:加载解码 / BGM 循环 / 音量钳制 / 增益分层 / 拾取随机音高) NODE_PATH=node_modules node tools/probe-peak.js # 山岳霸主全链路(21 项:角色数据 / 换装帧表 / 长棍横扫 / 旋转棍特效(轴心=手心)/ 立绘) ``` 截图落在 `tools/shots/`(已被 gitignore,每次运行自动重建)。 `smoke-test.js` / `chat-test.js` 走无头 Edge + CDP,需要本机装有 Edge; 也可用 `BROWSER_PATH` 环境变量指向别的 Chromium 内核浏览器。 --- ## 🔌 后端接口一览 `server.py`(8200)同时提供 API 与构建产物托管。**身份一律由请求自带的 `?uid=` 决定** (uid 唯一且稳定,昵称可改、可重名,不作为身份)。绝大多数接口是 `POST /api/xxx`; 只读接口 `/api/state`、`/api/chat_history`、`/api/whoami`、`/api/rank` 也支持 GET,可直接在浏览器里调试: | 分类 | 接口 | |---|---| | 状态与存档 | `/api/state`(含 `chars` / `blocked_words` / `items` 局内道具掉落配置)、`/api/save`、`/api/whoami`、`/api/set_name`、`/api/switch` | | 角色 | `/api/buy_char`、`/api/deploy` | | 好友 | `/api/friend_add`、`/api/friend_search`、`/api/friend_find`、`/api/friend_handle`、`/api/friend_remove` | | 聊天 | `/api/chat_send`、`/api/chat_history`、`/api/chat_read` | | 排行榜 | `/api/rank`(`scope=friends` / `global`,GET 调试:`/api/rank?uid=10000001&scope=global`) | | 兑换与反馈 | `/api/redeem`、`/api/feedback` | | 屏蔽词 | `/api/words`(GET/POST 均返回 `{ok, words:[...]}`,供前端对聊天打码) | | 实时 | `/ws/chat?uid=`(WebSocket,消息落库即推送) | 兑换码生成(写库): ```bash python tools/gen_redeem.py --coins 500 [--char strawberry] [--max-uses N] [--note x] [--list] ``` ### 管理后台接口 `admin/main.py`(8300)所有接口都在 `/api/admin/*` 下,除 `/login` 外都需要 `Authorization: Bearer `(登录返回的 JWT)。完整交互文档见 http://127.0.0.1:8300/docs 。 | 分类 | 接口 | |---|---| | 鉴权 | `/api/admin/login`、`/api/admin/me`、`/api/admin/change_pwd` | | 仪表盘 | `/api/admin/stats` | | 用户 | `/api/admin/users`、`/api/admin/users/{id}`、`/{id}/coins`、`/{id}/name`、`/{id}/cooldown_reset`、`/{id}/ban`、`/{id}/clear_wave` | | 角色 | `/api/admin/chars`、`/api/admin/chars/{id}`、`/api/admin/users/{uid}/chars/{cid}/unlock`、`/deploy` | | 游戏局内 | `/api/admin/gameplay`、`/api/admin/gameplay/{item_id}`(改掉落概率 / 启用开关) | | 兑换码 | `/api/admin/redeem`、`/{code}/logs`、`/{code}/max_uses`、`/{code}/disable`、`/{code}/enable` | | 反馈 | `/api/admin/feedback`、`/api/admin/feedback/{id}/status` | | 消息 | `/api/admin/messages`、`/api/admin/conversations`(游戏端无撤回,故无撤回接口) | | 屏蔽词 | `/api/admin/words`、`/api/admin/words/{id}`(POST 改 / DELETE 删) | | 排行 | `/api/admin/ranks`(前端「功能」列可清除波数 / 封禁) | | 管理员(仅 super) | `/api/admin/admins`、`/{id}/role`、`/{id}/enabled`、`/{id}/pwd`、`/api/admin/logs` | --- ## 🎮 操作 - 鼠标点击 / 触摸操作 - 左下角摇杆控制角色移动 - 设置中切换摇杆模式(固定 / 跟随)