《三角洲行动·文字版》:Canvas 战斗循环与游戏系统拆分
本文目录
这篇文章复盘 Game-All-In-One 中 bigGame 子项目的网页战斗原型。先把归属边界讲清楚:仓库 README 说明,小游戏目录既有外部来源,也有个人程序;Git 历史显示,本篇聚焦的 bigGame 核心引擎、Canvas 渲染器等文件由我在一次提交中加入。因此本文只分析这套核心逻辑,不把整个游戏仓库或其他小游戏都说成同一来源,也不复制源代码、图片或音频素材。
从浏览器入口和核心逻辑看,它是一款前端本地运行的战术射击/撤离玩法原型:Canvas 绘制战场,JavaScript 管理状态、敌人和战斗规则,进度保存在当前浏览器。本次审阅的代码没有显示服务端联机或云端存档链路;“大逃杀”人数变化目前也是本地规则模拟,不应误解为真实百人在线对战。
代码如何分层
入口页面按顺序加载地图、武器、道具、敌人、平衡参数等数据,再加载状态、渲染器、玩法系统、模式、HUD 和引擎。它采用传统浏览器脚本的全局对象协作,而不是 ES module:例如引擎会调用 GameState、CombatSystem、CanvasRenderer 和 HUD。这种方式让纯静态页面可以直接运行,也方便把旧页面接进游戏中心;代价是依赖关系藏在脚本顺序和全局变量里,改名或调整加载顺序容易在运行时才暴露问题。
职责大致可以这样读:
| 层次 | 主要职责 |
|---|---|
data/ | 地图、武器、敌人、物品、商店和数值配置 |
js/core/state.js | 玩家资料、仓库、当前局状态及本地持久化 |
js/core/engine.js | 开局、键盘输入、动作分发、每帧模拟与胜负收束 |
js/core/canvas-renderer.js | Canvas 尺寸、相机、地形、实体、HUD 画面效果和动画循环 |
js/systems/ | 地图构造、敌人 AI、战斗、拾取、玩家动作、天气、Boss 等规则 |
js/modes/ 与 js/ui/ | 撤离/缩圈模式和界面呈现 |
这是一个有意把“画出来”和“规则怎么算”分开的结构。它还没有完全模块化:部分系统通过全局对象互相调用,个别可选能力用 typeof 检查是否存在。继续扩展时,最好把数据、状态变更和副作用的入口写成明确契约,再逐步迁移模块,而不是一次性重写全部脚本。
一局游戏从哪里开始
开局时,引擎按地图 ID 取配置,创建玩家和本局状态,然后依次构建地图上的保险箱、生成敌人与战利品、尝试生成 Boss,并初始化天气、技能和所选模式。若配装中没有主武器,则给玩家一把默认手枪。最后清空战斗日志、展示操作提示、重置各个计时累加器并启动 Canvas 动画循环。
玩家的位置同时保存格子坐标和像素坐标。格子坐标适合做地图碰撞、拾取、距离和寻路;目标像素坐标则让角色移动时可以平滑过渡,而不是每次按键都瞬移一整格。这种“双坐标”模型很实用,但所有系统都必须清楚自己读写的是哪一套坐标,否则插值过程中会出现判定位置和画面位置不一致的错觉。
每帧的先后顺序
渲染器通过 requestAnimationFrame 驱动循环,并把单帧 dt 限制在 100 毫秒以内,避免页面卡顿后一次性推进过长时间。每帧先更新游戏规则,再跟随玩家更新相机,随后绘制地形、保险箱、战利品、撤离点、缩圈、实体和玩家,最后叠加天气、文字、粒子与屏幕震动。
把模拟与绘制放在同一个帧循环里,原型实现简单,也便于特效跟随战斗状态。它的下一步可以是固定步长模拟:保留累加器中未消费的时间,只按固定 tick 更新规则,再用插值绘图。当前一些累加器在触发后直接归零;浏览器掉帧时会丢掉剩余时间,可能让移动、AI 和缩圈节奏略微变化。若要做可复现战斗、回放或多人同步,固定步长和可注入的随机数会是基础设施,而不是后期的小优化。
Canvas 尺寸会随窗口变化,但位图宽高按容器 CSS 像素设置,没有按 devicePixelRatio 放大后再缩放绘制。在高像素密度手机或 Retina 屏上,线条可能不够锐利。修复时要同时管理 CSS 尺寸、Canvas backing store 和绘图变换,不能只把 canvas.width 乘倍数,否则坐标、鼠标输入和相机都会错位。
战斗判定与准星语义
开火由实时动作触发,武器射速通过上次开火时间和射击间隔限制,弹药扣除、自动换弹、命中、伤害与 HUD 更新由战斗系统处理。目标筛选先按玩家与敌人的格子距离排序,在有效射程内选最近的敌人;随后将武器精度、掩体、烟雾和配件加成合入命中率,再计算弹药穿甲、爆头倍率和护甲减伤。命中后会同步更新敌人生命、日志、击杀统计与 Canvas 命中特效。
源码里有一个值得优先确认的玩法细节:鼠标移动会更新玩家 aimAngle,但有敌人处于有效射程时,实际命中对象仍由“最近敌人”决定,并不按准星角度筛选;准星角度主要影响没有可选目标时的射击轨迹特效。如果预期是自动锁定,这应在准星和操作提示里明确;如果预期是自由瞄准,则目标选择、射线/碰撞和画面轨迹需要统一到同一个方向判定。否则玩家会感觉“明明瞄着 A,却打中了 B”。
敌人 AI 与模式差异
敌人 AI 用巡逻、追击、攻击、搜索几个状态组织行为:看到玩家就记录最后位置并追击;进入攻击距离后尝试射击;失去视野或追得太远后转入搜索,搜索超时再回到巡逻。主循环约每半秒驱动一次 AI,而角色位置和画面插值在动画帧中持续更新。这种分频能减少昂贵的行为判断次数,后续可将视野、路径搜索和射击决策分开计时,并把状态迁移写成可测的纯函数。
撤离模式会选择任务、管理剩余时间、任务进度和撤离点;缩圈模式会逐阶段移动安全区并对圈外玩家造成伤害。需要特别说明的是,缩圈模式里的存活人数会按配置间隔随机减少,并非每个“其他玩家”都有实体、路线和战斗行为。因此它更准确地说是单机生存玩法中的战局氛围模拟,后续如要呈现真实 AI 对手,应为对手建立独立实体和可验证的生存/击杀状态。
存档边界
玩家资料、仓库、成就和战斗报告通过浏览器 localStorage 读取与保存;结束一局时会汇总统计并写入本地资料。这意味着清除浏览器站点数据、换设备或使用隐私窗口,都可能让进度消失。当前模型也没有服务端校验,不能作为可信的排行榜或有价值资产账本。
稳妥的渐进路线是给存档加 schemaVersion 和迁移函数,读取时对关键字段做类型与范围校验;先保证坏数据可恢复,再考虑导入/导出。若未来增加云存档或排行,应由服务端确认结果,不能直接信任浏览器提交的击杀、奖励和战斗时长。
建议的下一轮
- 先确定射击是自动锁定还是自由瞄准,并用准星、提示文案和命中算法表达同一个规则。
- 给移动、射速、AI 状态、撤离条件和缩圈伤害补纯逻辑测试;固定随机数和时间后,失败局面应能稳定复现。
- 将帧动画与固定步长模拟分开,页面隐藏时暂停或降频,并避免丢失累加时间。
- 为 Canvas 加高 DPI 适配,同时覆盖窗口缩放、触控坐标和低性能设备。
- 为
localStorage增加版本迁移、坏数据回退和显式清档/导出入口。 - 逐步把全局脚本依赖改为显式模块边界;新系统先模块化,不需要为此推倒现有玩法。
以上结论来自源码静态复盘,不等同于本次已完成真实设备上的完整游戏验收。游戏内独立图片、声音、字体和旧游戏页面仍需要分别核对来源与授权。
项目源码
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。