Canvas跑酷游戏主循环必须用requestAnimationFrame递归调用,统一在单帧内完成update(含deltaTime位移计算)、collision检测与render;禁用setInterval,所有坐标与碰撞逻辑须基于Canvas内部坐标系,禁用DOM offset混用。

canvas 是跑酷游戏最直接可靠的渲染入口,不用框架、不引入库也能跑起来——关键不在“能不能”,而在状态更新节奏是否稳定、碰撞判断是否落在帧内、DOM 与 Canvas 渲染是否错位。
怎么用 requestAnimationFrame 控制游戏主循环
跑酷游戏不是靠 setInterval 拖动的幻灯片。一旦用错定时器,角色跳跃会卡顿、障碍物穿模、速度感崩塌。
requestAnimationFrame必须在每次回调里主动调用自身,形成递归链;漏掉一次就停帧-
所有逻辑(位置更新、碰撞检测、绘图)必须塞进同一个回调里,不能拆到多个
setTimeout中立即学习“前端免费学习笔记(深入)”;
帧率下降时,不要强行补帧;而是通过时间差(
deltaTime)缩放位移量,保持物理感一致-
示例节选:
let lastTime = 0; function gameLoop(timestamp) { const deltaTime = timestamp - lastTime; lastTime = timestamp; <p>update(deltaTime); // 用 deltaTime 调整 speed * deltaTime render(); requestAnimationFrame(gameLoop); }
collision 检测为什么总漏判或误判
用 getBoundingClientRect() 或 CSS offsetLeft/offsetTop 做碰撞,90% 的失败都源于坐标系错乱:
- Canvas 绘图坐标系原点在左上角,而 DOM 元素的
offsetTop是相对于文档流的,混用必出错 - 障碍物如果用
div实现(非 Canvas 绘制),需确保其position: absolute且父容器position: relative,否则offset值不可靠 - 真正安全的做法:所有参与碰撞的对象,统一用 Canvas 内部坐标管理(
x,y,width,height),不依赖 DOM 位置 - 最简矩形碰撞逻辑(Canvas 坐标下):
function isColliding(a, b) { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; }
怎么让 jump 动作不飘、不卡、不双跳
火柴人跳不起来,往往不是重力公式写错,而是状态机没闭环:
-
jumping标志必须和「是否接触地面」强绑定,不能只靠按键触发 - 地面判定不能写死
y === groundY,要留容差(如y >= groundY - 5),否则因浮点误差永远落不下 - 跳跃中再次按空格/上键,应被忽略——除非你明确实现了二段跳逻辑,并用
jumpCount计数 - 推荐结构:
if (isGrounded && keys.up) { stickman.jumping = true; stickman.jumpVelocity = -15; // 向上初速度 } if (stickman.jumping) { stickman.jumpVelocity += 0.8; // 重力加速度 stickman.y += stickman.jumpVelocity; if (stickman.y >= groundY) { stickman.y = groundY; stickman.jumping = false; stickman.jumpVelocity = 0; } }
Canvas 尺寸设成 800x300 还是自适应?
固定尺寸(如 800x300)适合调试和性能压测;但上线前必须处理缩放问题:
- 直接改
canvas.width/canvas.height属性会清空画布并重采样,导致模糊 - 正确做法:CSS 设置
canvas { width: 100%; height: auto; },再用 JS 同步设置canvas.width和canvas.height为设备像素比 × CSS 尺寸(window.devicePixelRatio) - 更稳妥的方案:放弃拉伸,用
transform: scale()缩放整个#gameContainer,让 Canvas 保持原始分辨率,仅 UI 层响应式
实际项目里,最常被跳过的一步是:没在 resize 事件里重置 Canvas 缓冲区尺寸,结果横屏后画面挤压变形,连障碍物都变扁了。



















