真实射击游戏必须用 requestAnimationFrame 控制主循环,基于 deltaTime 归一化位移计算,状态更新与渲染分离,子弹用 Canvas 绘制并局部擦除,碰撞检测用距离平方或 AABB,按键状态需全局管理并防默认行为。

用 requestAnimationFrame 控制游戏主循环,别用 setInterval
浏览器重绘节奏和 JS 执行节奏不一致,setInterval 容易导致画面卡顿、子弹位移跳变或输入响应延迟。真实射击游戏必须靠 requestAnimationFrame 对齐屏幕刷新率。
- 每次回调拿到的是上一帧到当前帧的耗时(
deltaTime),所有位移计算要乘以它,否则在不同刷新率设备上速度不一致 - 不要在回调里直接写渲染逻辑——先更新状态(玩家位置、子弹坐标、敌人血量),再统一渲染,避免状态和画面不同步
- 如果帧率掉到 30fps 以下,
deltaTime可能超过 33ms,需加阈值限制(如Math.min(deltaTime, 16))防单帧过长导致子弹“瞬移”
子弹用 canvas 绘制比 DOM 元素快一个数量级
每个子弹都建一个 玩家打中敌人、子弹击中目标,本质是点与圆(或矩形)的距离判断。常见错误是算欧氏距离再比半径: 按住方向键时, 将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。 实际运行中,最常被忽略的是时间步长(transform: translate() 移动?50 发子弹同时存在时,DOM 重排+重绘开销会立刻拖垮 60fps。Canvas 2D 上画圆或小矩形,CPU 占用低且可控。
bullets = [{x: 100, y: 200, vx: 5, vy: 0, life: 100}],每帧遍历更新 x += vx * dt,超出画布或 life 就
splice 掉ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill();,比 drawImage 贴图更轻量(除非你要带尾迹或旋转效果)ctx.clearRect(x-5,y-5,10,10))再重绘,对少量高速移动对象更省碰撞检测用距离平方比较,别调
Math.sqrt
Math.sqrt(dx*dx + dy*dy) ——sqrt 是高开销操作,每帧上百次调用明显掉帧。
dx*dx + dy*dy ,完全等价但零函数调用
bullet.x > enemy.x && bullet.x enemy.y && bullet.y ,比圆形检测还快
keydown 和 keyup 必须配对管理按键状态,别在事件里直接移动keydown 会连续触发,但你不能在每次事件里执行一次位移——这样会导致加速跑、松手后还滑行,或者连发子弹间隔失控。
const keys = {ArrowUp: false, ArrowDown: false, Space: false},keydown 设 true,keyup 设 false
keys.ArrowUp 决定是否加速度,再积分得速度和位置;keys.Space 控制是否生成新子弹(并加冷却计时器)keydown 里 e.preventDefault(),尤其移动端软键盘弹出时容易误触deltaTime)未归一化带来的跨设备体验差异,以及 DOM 操作混入 Canvas 渲染路径导致的隐式重排。这两点不处理,游戏在低端机或 Chrome 外其他浏览器里基本不可玩。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










