canvas 像素游戏入门:从字符画到 60fps 主循环
做了个小火箭游戏,最大的心得是:像素风 + 低分辨率画布,是业余开发者做"看起来不错"游戏的最低成本路径。这篇把几招核心技巧拆开讲。
一、低分辨率画布最省心
不要在高分辨率上硬画。用一个很小的内部分辨率(比如 160×240),然后 CSS 放大整数倍:
<canvas width="160" height="240" style="width:480px;height:720px"></canvas>
配合 image-rendering: pixelated,放大后是干净利落的像素颗粒,而不是糊成一团:
canvas {
image-rendering: pixelated; /* 关键!不然放大全是锯齿渐变 */
}
好处立竿见影:
- 绘制量极小:160×240 的 fillRect 比 1920×1080 快几个数量级
- 天然像素风:不用精雕细琢,1px 就是 1px
- 性能余量足:留给你做粒子、扫描线等特效
二、用字符画出素材
不想用图片资源?直接用字符串数组定义精灵——和写"画"是一回事:
const ROCKET = [
" O ",
" OOO ",
" OOOOO ",
" OOCOO ",
"COOOOOC",
];
const PALETTE: Record<string, string> = {
O: "#d9701a", // 橙
C: "#0f9b8e", // 青
};
渲染时遍历字符,O→橙色方块,C→青色方块:
for (let r = 0; r < ROCKET.length; r++) {
for (let c = 0; c < ROCKET[r].length; c++) {
const ch = ROCKET[r][c];
if (ch === " ") continue;
const color = PALETTE[ch];
if (color) {
ctx.fillStyle = color;
ctx.fillRect(x + c, y + r, 1, 1);
}
}
}
这种方法素材即代码:易改、易复用、零资源加载,还天然和"像素字体""像素图标"一个画风。
三、固定时间步长:让 60Hz 和 144Hz 手感一致
最怕的就是动画速度和帧率绑定——高刷屏的玩家会"外星人速度",低帧玩家"慢动作"。解法是固定时间步长 + 累加器:
const STEP = 1000 / 60; // 目标 60 FPS
let acc = 0;
let last = performance.now();
function frame(now) {
acc += now - last;
last = now;
if (acc > 250) acc = 250; // 防止长时间切后台回来积压爆炸
// 把累加的时间按固定步长消费掉
while (acc >= STEP) {
update(); // 物理/逻辑只在这里跑
acc -= STEP;
}
draw(); // 渲染每帧都跑,反正是重画
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
好处:
- 物理完全确定,和屏幕刷新率无关
- 逻辑稳定跑 60 次/秒,不管屏幕是 60、120 还是 144Hz
- 物体对象池、碰撞检测都只在
update()里做一次
四、状态机管阶段切换
游戏不该是一坨 if 堆积,用状态机把阶段分清楚:
boot → ready → ascent → transition → descent → boom/landed → result
type Phase = "ready" | "ascent" | "descent" | "boom" | "result";
function update(s) {
switch (s.phase) {
case "ascent":
// 升空:自动上升,玩家左右躲
break;
case "descent":
// 下降:重力牵引,玩家喷气对抗
break;
case "boom":
// 爆炸倒计时
break;
}
}
每个阶段只管自己的逻辑,切换阶段=改 phase。加新阶段不碰旧代码,可维护性直线上升。
五、HUD 也画进画布
分数、燃料条、速度这些别用 DOM 覆盖,直接塞进 Canvas 一起画。这样游戏循环完全自给自足,不依赖 React 的 setState,也就不会有"react 重渲染拖慢 60fps 循环"的问题。只有"游戏结束/重新开始"这种低频状态交给外层框架。
小结
做一个像素小游戏的效率公式:
- 低分辨率画布(像素风 + 高性能)
- 字符画素材(零资源 + 风格统一)
- 固定时间步长(多帧率手感一致)
- 状态机(可维护)
- HUD 上画布(不拖累循环)
这五招够你从零到一个能玩的像素游戏。剩下的就是把它变得好玩——那需要的是内容,不是技术了。