MatrixStack
用途:显式变换栈,经 RenderContext#matrices() 获取。把「进入局部坐标系 → 绘制 → 退出」写清楚。
方法速览
| 方法 | 用途 |
|---|---|
push() / pop() | 压栈 / 出栈(等价 canvas().save() / restore()) |
translate(dx, dy) / scale(sx, sy) | 2D 平移 / 缩放 |
rotate(angle, pivotX, pivotY) | 绕轴点旋转(弧度) |
translate3D(dx, dy, dz) | 三轴平移(z 单位像素,+z 向屏幕内) |
scale3D(sx, sy, sz) | 三轴缩放 |
rotateX(angle, pivotY, pivotZ) / rotateY(angle, pivotX, pivotZ) | 绕平行 X / Y 轴旋转(弧度) |
完整签名
public interface MatrixStack {
void push();
void pop();
void translate(double dx, double dy);
void scale(double sx, double sy);
void rotate(double angle, double pivotX, double pivotY);
void translate3D(double dx, double dy, double dz);
void scale3D(double sx, double sy, double sz);
void rotateX(double angle, double pivotY, double pivotZ);
void rotateY(double angle, double pivotX, double pivotZ);
}push() / pop()
签名:
void push();
void pop();行为:push() 等价于 canvas().save(),pop() 等价于 canvas().restore()——同一栈、同一深度计数,可混用,但配对不能跨过对方。栈有深度上限,超限时 push() 安全降级(不压栈、限流告警、不抛异常),配对的 pop() 变为空操作,因此「N 次 push + N 次 pop」仍能回到平衡。
translate(dx, dy) / scale(sx, sy)
签名:
void translate(double dx, double dy);
void scale(double sx, double sy);行为:增量修改当前坐标系。translate 以像素为单位,scale 以当前原点为基准。
rotate(angle, pivotX, pivotY)
签名:
void rotate(double angle, double pivotX, double pivotY);行为:绕轴点旋转,角度单位为弧度,正值 = 屏幕顺时针(Y 轴向下);轴点用当前局部坐标表示,与 RenderCanvas#rotate 同口径。
translate3D(dx, dy, dz)
签名:
void translate3D(double dx, double dy, double dz);行为:三轴平移。dz 为内容 z:像素单位、+z 向屏幕内(更远、遮挡劣势)。硬边界 |z| ≤ 2000(超出被远平面裁剪),推荐 |z| ≤ 500。
世界层(BACKGROUND / WORLD / NOTES / JUDGE_FX 及 index < 4 的自定义层)内 z 进入深度场,按深度遮挡、随轨道倾斜产生视差;世界层外安全退化(不报错、不影响像素)。dz == 0 且此前无 3D 变换时与 translate 逐位同路径。
scale3D(sx, sy, sz)
签名:
void scale3D(double sx, double sy, double sz);行为:三轴缩放。绘制顶点 z 恒为 0,故 sz 只作用于此前由 translate3D 等引入的 z 分量;sz == 1 且此前无 3D 变换时与 scale 同路径。
rotateX(angle, pivotY, pivotZ) / rotateY(angle, pivotX, pivotZ)
签名:
void rotateX(double angle, double pivotY, double pivotZ);
void rotateY(double angle, double pivotX, double pivotZ);行为:绕平行 X / Y 轴旋转(弧度),轴过当前局部坐标中的指定点。世界层内产生透视翻转(如卡片翻面);世界层外退化为 2D 压扁。
裁剪的坐标语义
RenderCanvas#clip 是局部空间语义:按调用时的当前变换求交(先裁剪、后变换)。因此在 translate 之后调用 clip(0, 0, w, h),裁的是平移后的局部矩形,而不是世界坐标;反过来「自己换算世界坐标再传入」是错误用法。
示例:局部坐标系绘制
MatrixStack m = ctx.matrices();
m.push();
m.translate(100, 80);
m.rotate(Math.toRadians(15), 40, 20); // 以局部 (40,20) 为轴心
ctx.canvas().fillRect(0, 0, 80, 40); // 局部坐标
m.pop();示例:两层 z 叠加(世界层内)
m.push();
m.translate3D(0, 0, -120); // 更远,会被前景遮挡
ctx.canvas().fillRect(0, 0, 200, 60);
m.pop();
m.push();
m.translate3D(0, 0, 0); // 基准平面
ctx.canvas().fillRect(40, 20, 200, 60);
m.pop();