Skip to content

Latest commit

 

History

History
316 lines (227 loc) · 10.1 KB

File metadata and controls

316 lines (227 loc) · 10.1 KB

塔防游戏技术规范

本文档描述基于 Vue 3 + Phaser 3 重写的塔防游戏核心流程,包含防作弊验证机制。

项目目标

  • 使用现代前端技术栈(Vue 3 + Phaser 3 + TypeScript)重构原游戏
  • 实现现代后端技术栈(Django + DRF + PostgreSQL)实现结果验证和积分排行榜
  • 保持原游戏的核心玩法和数值体系
  • 添加与后端交互的排行榜功能

游戏规则

基础设定

  • 游戏类型: 动态寻路塔防(无限模式)
  • 地图规格: 16x16 格子
  • 格子大小: 32px
  • 帧率: 60 FPS
  • 入口: 左上角 (0, 0)
  • 出口: 右下角 (15, 15)
  • 全局速度系数: 0.1(GLOBAL_SPEED,用于将配置速度转换为每帧实际像素移动量)

帧号计数

  • 帧号从 0 开始,每帧递增 1,暂停时不增长
  • 所有时间相关记录使用帧号而非系统时间戳

路径系统

怪物使用动态寻路算法(BFS)从入口移动到出口。

核心特性

  • 独立路径: 每个怪物独立计算路径,不共享。同一位置出发的怪物可能走不同路径
  • 动态重算: 怪物每帧有 10% 概率自动重新寻路,遇到障碍时强制重算
  • 路径随机性: 寻路回溯时若有多条等距路径,随机选择一条
  • 建筑影响: 建筑放置后该格子变为不可通行,影响后续怪物的路径计算

可通行性规则

  • 预设障碍物(obstacles 配置): 不可通行
  • 已放置建筑的格子: 不可通行
  • 其他格子: 可通行

怪物重新寻路机制

怪物在以下情况下会重新计算路径:

  • 路径列表为空时
  • 每步有 10% 概率自动重新寻路(模拟随机移动)
  • 下一步格子变为不可通行时(如被新建筑占据)

当建筑放置后阻断了怪物的当前路线,怪物会自动重新寻路,可能选择更远的绕行路线。这是游戏策略的核心部分:玩家可以通过建筑引导怪物走更长的路线,但不能完全阻断所有通路。

建筑放置约束

建筑放置时需要通过双层检查机制:

  • 不能放置在入口或出口格子
  • 不能完全阻断入口到出口的所有路径(路径检查)
  • 不能使已存在的怪物无法到达出口(怪物检查)

可以阻断怪物的当前最短路线,此时怪物会重新寻路走更远的路线。但如果新建筑会导致某个怪物完全无路可走,则禁止建造。

速度计算

所有速度公式中的 (24/60) 是帧率补偿系数,用于保持与原 24 FPS 实现相同的实际移动速度。

怪物移动速度 = speed × GLOBAL_SPEED × (24 / 60)
子弹飞行速度 = bullet_speed × 20 × GLOBAL_SPEED × (24 / 60)
建筑攻击间隔(帧) = floor(max(2 / (speed × GLOBAL_SPEED), 1)) × (60 / 24)

子弹速度额外乘以 20 倍系数,确保对高速怪物也能有效追击。攻击间隔与 speed 成反比。

怪物系统

怪物属性

  • life: 生命值
  • speed: 移动速度(1-40)
  • max_speed: 最大速度
  • shield: 护盾值(减伤)
  • damage: 到达终点造成的伤害(1-10)
  • money: 击杀奖励金币

怪物类型(9 种)

  • 0-普通怪
    • life: 50, speed: 3, max_speed: 10, shield: 0, damage: 1, money: 5
  • 1-稀强怪
    • life: 50, speed: 6, max_speed: 20, shield: 1, damage: 2, money: 8
  • 2-速度怪
    • life: 50, speed: 12, max_speed: 30, shield: 1, damage: 3, money: 10
  • 3-血量怪
    • life: 500, speed: 5, max_speed: 10, shield: 1, damage: 3, money: 50
  • 4-护盾怪
    • life: 50, speed: 5, max_speed: 10, shield: 20, damage: 3, money: 30
  • 5-伤害怪
    • life: 50, speed: 7, max_speed: 14, shield: 2, damage: 10, money: 25
  • 6-速度血量怪
    • life: 100, speed: 15, max_speed: 30, shield: 3, damage: 3, money: 35
  • 7-极速怪
    • life: 30, speed: 30, max_speed: 40, shield: 1, damage: 4, money: 20
  • 8-护盾血量怪
    • life: 300, speed: 3, max_speed: 10, shield: 15, damage: 5, money: 60

波次生成规则

  • 波次 1-10 使用预定义配置
  • 波次 11+ 自动生成:
    • 怪物总数 = min(wave^1.1, 100)
    • 随机算法:组大小随机 1-3,怪物类型随机 0-8
  • 波次间隔:180 帧(3 秒)

难度动态调整

  • 上波未造成伤害时
    • wave < 5: difficulty × 1.05
    • difficulty > 30: difficulty × 1.1
    • 其他: difficulty × 1.2
  • 上波造成伤害时
    • >= 50 点: difficulty × 0.6
    • >= 30 点: difficulty × 0.7
    • >= 20 点: difficulty × 0.8
    • >= 10 点: difficulty × 0.9
    • < 10 点且 wave >= 10: difficulty × 1.05
  • difficulty 最小值为 1

防御塔系统

塔属性

  • damage: 攻击力
  • range: 初始射程(格子数),可升级
  • max_range: 射程升级上限
  • speed: 攻击速度
  • bullet_speed: 子弹速度
  • life: 塔的生命值
  • shield: 塔的护盾值
  • cost: 建造费用

塔类型(5 种)

  • wall (路障)
    • damage: 0, range: 0, speed: 0, cost: 5
    • 特性: 阻挡路径不攻击
  • cannon (炮台)
    • damage: 12, range: 4-8, speed: 2, cost: 300
    • 特性: 平衡型
  • LMG (轻机枪)
    • damage: 5, range: 5-10, speed: 3, cost: 100
    • 特性: 低攻击大范围经济型
  • HMG (重机枪)
    • damage: 30, range: 3-5, speed: 3, cost: 800
    • 特性: 高攻击小范围
  • laser_gun (激光枪)
    • damage: 25, range: 6-10, speed: 20, cost: 2000
    • 特性: 高速攻击高造价

升级机制

  • 默认: 每级属性 x 1.2
  • cannon(炮台): 前 11 次升级 x 1.2,第 12 次升级起 x 1.3(即 Level 2-12 用 1.2,Level 13+ 用 1.3)
  • HMG(重机枪): 每级 x 1.3

精度处理:计算过程中保持浮点精度,仅在最终结果时截断(floor)。

经济系统

  • 初始金币: 500
  • 初始生命: 100
  • 击杀奖励: 根据怪物配置(monster.money 或按公式计算)

波次奖励

  • 每 5 波: +5 生命(不超过 100)
  • 每 10 波: +10 生命(不超过 100)

胜负条件

  • 生命值降为 0: 失败
  • 无限模式: 无胜利条件

得分计算

每次攻击命中时累加:得分 = floor(sqrt(实际伤害))

技术栈

前端

  • Vue 3.5: UI 框架
  • Phaser 3.90: 游戏引擎
  • Vite 7.2: 构建工具
  • TypeScript 5: 开发语言
  • Pinia 3.0: 状态管理
  • Axios 1.13: HTTP 客户端

后端

  • Python 3.13: 开发语言
  • uv: 0.9.15 包管理器
  • Django 5.2: Web 框架
  • Django REST Framework 3.16: API 框架
  • PostgreSQL 15: 数据库
  • pytest + pytest-django: 测试框架
  • Docker + Gunicorn: 部署

整体架构

设计原则

  • 服务端权威:怪物属性、建筑属性、波次配置由服务端定义
  • 客户端零配置:客户端不内置任何游戏配置和默认状态,所有数值均从服务端获取
  • 客户端执行:游戏逻辑在客户端执行,服务端验证结果
  • 批量提交:每波结束时批量提交,而非实时上传
  • 渐进验证:每波验证一次,而非游戏结束时一次性验证
  • 服务端生成:波次配置由服务端随机生成并下发,怪物属性包含随机因子

验证方案

采用多层验证架构(Level 1 基础验证 + Level 2 伤害验证 + Level 4 统计分析),详见 安全设计文档

游戏生命周期

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ 页面加载  │───▶│ 放置建筑  │───▶│ 波次进行  │───▶│ 游戏结束  │
│ 创建会话  │    │ 开始动画  │    │ 提交验证  │    │ 提交排名  │
└──────────┘    └──────────┘    └──────────┘    └──────────┘
     │               │               │               │
     ▼               ▼               ▼               ▼
POST /sessions    无请求     POST /sessions/wave  POST /sessions/end

阶段说明

  • 页面加载: 创建会话,获取游戏配置和第一波怪物数据
  • 放置建筑: 本地处理,扣除金钱后开始游戏动画
  • 波次进行: 每波结束时提交操作记录,服务端验证后返回下一波配置
  • 游戏结束: 提交昵称和最后一波数据,记录排行榜

HTTP 状态码与错误响应

状态码

  • 200:请求成功
  • 400:请求参数错误或验证失败
  • 404:会话不存在或已过期

错误响应格式

所有错误响应使用统一的 JSON 格式:

{
  "code": "BUSINESS_ERROR_CODE",
  "message": "Human-readable error description"
}
  • code:业务状态码,用于程序判断错误类型
  • message:人类可读的错误描述

业务状态码

  • MISSING_FIELDS:缺少必填字段
  • SESSION_NOT_FOUND:会话不存在或已过期
  • WAVE_NOT_CONTINUOUS:波次号不连续
  • VALIDATION_FAILED:服务端验证失败(详细信息仅记录在服务端日志)
  • INVALID_NICKNAME:昵称验证失败
  • EARLY_END_REQUIRES_WAVE:提前结束需至少完成一波
  • ZERO_SCORE:零分不能上榜

各端点错误场景

POST /api/game/sessions

  • 无错误响应(总是成功创建会话)

POST /api/game/sessions/wave

  • MISSING_FIELDS (400):缺少必填字段
  • SESSION_NOT_FOUND (404):会话不存在
  • WAVE_NOT_CONTINUOUS (400):波次号不连续
  • VALIDATION_FAILED (400):服务端验证失败

POST /api/game/sessions/end

  • MISSING_FIELDS (400):缺少必填字段
  • INVALID_NICKNAME (400):昵称为空、超长或含非法字符
  • SESSION_NOT_FOUND (404):会话不存在
  • VALIDATION_FAILED (400):服务端验证失败
  • EARLY_END_REQUIRES_WAVE (400):提前结束需至少完成一波
  • ZERO_SCORE (400):零分不能上榜

GET /api/game/leaderboard

  • 无错误响应(无效 limit 参数自动回退为默认值 10)

前端错误处理

当收到 SESSION_NOT_FOUND 错误时:

  • 显示提示告知用户会话已失效
  • 自动重启游戏创建新会话

详细规范

以下内容已拆分到专门的规范文档: