HTML5 Canvas可通过伪3D技术实现赛道纵深效果:将赛道拆分为纵向条带,按透视公式缩放位置与尺寸,结合边缘灭点、分道线密度变化、Z序绘制及setTransform动态倾斜/晃动,以2D元素模拟3D感知。

HTML5 Canvas 本身是二维的,不能直接渲染 3D 场景,但可以通过数学投影和分层绘制,实现具有强烈透视感的伪 3D 赛道效果——这正是经典街机赛车(如 Out Run、Hard Drivin’)和网页版竞速游戏常用的手法。核心不在于“建模 3D”,而在于用 2D 元素模拟纵深移动与远近缩放。
伪 3D 赛道的底层逻辑:垂直切片 + 透视缩放
赛道被拆解为若干横向“条带”(strip),每一条代表一个固定纵向距离(z 层级)上的路面横截面。越远的条带,y 坐标越靠上、宽度越窄、颜色越暗(模拟大气透视),形成自然的纵深感。
- 每条赛道条带是一个矩形或梯形(更真实)
- 条带的 y 坐标 = 画布顶部偏移量(随 z 增大而减小)
- 条带宽度 = 基础宽度 × 缩放因子(s = d / (z + d),d 是焦距,通常取 200–400)
- 条带高度可固定(如 2px),也可随 z 略微变化增强动感
例如:
const d = 300;
for (let z = 0; z < 200; z += 2) {
const s = d / (z + d);
const y = canvas.height / 2 - z * 0.8; // 视觉中心下移 + 纵向压缩
const w = 400 * s;
const x = (canvas.width - w) / 2;
ctx.fillStyle = `hsl(0, 0%, ${70 - z * 0.1}%)`; // 远处变灰
ctx.fillRect(x, y, w, 2);
}赛道边缘与分道线的动态延伸
-
左右边缘:用多段贝塞尔曲线或逐段连接的折线,每段按相同缩放因子计算顶点坐标,再用
ctx.lineTo()绘制。关键是要让远端点汇聚于画面中心略偏下的“灭点”(vanishing point)。 - 中央分道线:绘制一系列等距短矩形,每个矩形的 y 和宽都按 z 缩放。当 z 增大时,矩形变短、间隔变密,产生高速前冲错觉。
建议用数组预存 100+ 个分道线片段的 (x, y, width, height),每帧整体下移并重绘,比实时计算更高效。
立即学习“前端免费学习笔记(深入)”;
车辆与对手的“Z 对齐”绘制顺序
伪 3D 中没有真正的深度缓冲,必须手动控制绘制顺序:
- 先画最远的赛道条带
- 再画远处的树木/广告牌(用
drawImage+ 缩放) - 最后画近处的车辆、碰撞火花、UI
所有动态对象需按其 z 值排序(可维护一个 renderList 数组,每帧按 obj.z 升序排列后遍历绘制)。
加入动态倾斜与镜头晃动提升真实感
单纯平移赛道会显得呆板。可引入:
-
转向倾斜:玩家左转时,整条赛道轻微右倾(对每条带做
ctx.setTransform(scaleX, skewY, skewX, scaleY, tx, ty)变换) - 颠簸反馈:根据车速和赛道纹理(如减速带标记),在 y 方向叠加小幅正弦偏移
-
FOV 动态调整:高速时略微增大焦距
d,视野变窄、两侧拉伸感增强,强化速度感
这些变换无需 WebGL,纯 Canvas 2D 的 setTransform() 就能完成,关键是把视觉反馈和物理状态(速度、转向角、z 位移)挂钩。
本质上,伪 3D 赛道不是“算出三维再投影”,而是用一组有规律缩放和平移的 2D 元素,欺骗人眼识别出纵深结构。它轻量、可控、易调试,特别适合 H5 赛车这类强调节奏与反馈的项目。



















