canvas无内置图层,需手动控制绘制顺序并组织对象数据结构:按z值升序排序绘制、多canvas分层、处理遮挡与透视、优化性能。

Canvas 本身不内置图层或深度概念,所有绘制都是按代码执行顺序“扁平”覆盖的——先画的在下,后画的在上。要实现复杂场景的深度排序与图层叠加,关键在于**手动控制绘制顺序 + 合理组织对象数据结构**,而不是依赖 Canvas 自身的 Z 轴能力。
按深度值(z-index)排序后绘制
为每个可绘制对象(如角色、UI、背景元素)添加 z 属性(数字,越大越靠前),统一存入数组,绘制前按 z 升序排序:
- 排序必须在每一帧渲染前重新执行,尤其当对象 z 值动态变化(如角色跳跃时 z 增加)
- 避免使用浮点数作为 z 值(易引发精度导致排序异常),推荐整数或带固定小数位的数值
- 若需精确重叠控制(如半透明物体),应启用
globalAlpha并注意混合顺序:半透明对象必须从远到近绘制(即 z 从小到大),否则会出现错误叠加
用多个 Canvas 元素模拟图层
将不同语义层级(如背景层、角色层、UI 层)分别绘制在独立的 <canvas></canvas> 上,通过 CSS 定位与 z-index 叠加:
- 背景层 Canvas 可设为
width/height=100%,绘制一次即可复用(静态背景)或低频重绘(滚动地图) - 角色层 Canvas 保持与视口尺寸一致,每帧清除并重绘所有角色(含其动画、状态)
- UI 层 Canvas 应设置
pointer-events: none(除非 UI 需交互),避免遮挡底层点击事件;若需响应,则用isPointInPath()或坐标映射做命中检测
处理遮挡与透视关系
纯 2D 场景中,“深度”本质是视觉遮挡逻辑。例如角色走进建筑门内,不能仅靠 z 值,还需结合空间位置判断是否被墙体遮挡:
- 对有遮挡需求的对象(如建筑、树木),预定义其遮挡区域(矩形或路径),在绘制前做简单包围盒交集检测
- 若使用等距视角(isometric),需将世界坐标
(x, y, z)映射为屏幕坐标,并以y + z(或y + height)作为排序依据,而非原始 y 值 - 动态遮挡(如角色蹲下变矮)应实时更新其参与排序的“有效高度”,影响其相对前后关系
性能与维护建议
深度管理容易成为性能瓶颈,尤其对象数量超过百级时:
- 避免每帧对全部对象做全量排序,可采用桶排序(按 z 分段)或增量更新(仅重排变动对象)
- 将静态图层(如地形、建筑底图)预先渲染到离屏 canvas(
OffscreenCanvas或普通 canvas 缓存),减少重复计算 - 用类或构造函数封装图层逻辑(如
LayerManager),暴露add(obj)、remove(id)、render(ctx)接口,便于调试与扩展











