外观
Lesson 004|Transform 为什么要分 position、rotation、scale?
Tags: #Creator2.x #Node #Transform #Matrix #Scale #RotationDifficulty: ⭐⭐☆☆☆
🎯 本课目标
- 理解 Transform 的含义
- 理解 position、rotation、scale 各自负责什么
- 理解为什么引擎对开发者暴露 Transform,但底层使用 Matrix
- 理解父节点 scale / rotation 为什么会影响子节点
- 为后续学习 Node、Renderer、顶点更新和性能优化打基础
🧩 上节课回顾
上一课我们讲了:
text
Local 是相对于父节点。
World 是最终显示到世界中的位置。
Matrix 是节点变换规则包。
父节点变了,子节点的 World Matrix 也会受影响。今天我们继续拆 Matrix 里面最核心的内容:
text
position
rotation
scale它们合起来就是:
Transform
💡 Transform 是什么?
在游戏引擎里,Transform 可以理解成:
一个节点在场景中如何摆放。
比如一个按钮:
text
放在哪里?
旋转了多少度?
放大还是缩小?对应的就是:
text
position:位置
rotation:旋转
scale:缩放所以可以简单理解为:
text
Transform = position + rotation + scaleCreator 中还会涉及 anchor、skew、size 等概念,但这一课先抓主线。
🧠 为什么不直接存 worldX / worldY?
你可能会想:
既然最终显示的是世界坐标,那每个节点直接保存 worldX、worldY 不就好了?
问题是节点不只有位置,还有:
text
rotation
scale
父子关系
anchor例如:
text
Panel.x = 100
Panel.scale = 2
Button.x = 30Button 的最终位置不是:
text
100 + 30 = 130而是:
text
100 + 30 * 2 = 160因为父节点缩放了,子节点相对于父节点的偏移也会被缩放。
如果父节点再旋转,子节点的方向也会跟着变化。
所以引擎不能只保存简单的 worldX / worldY,而需要保存完整的变换规则。
这就是 Transform 和 Matrix 存在的原因。
🧠 position:节点在哪里
position 表示节点的位置。
例如:
ts
node.x = 100;
node.y = 50;表示:
text
节点相对于父节点偏移 x = 100, y = 50注意:
node.x通常是 Local 坐标,不是屏幕坐标。
在没有父节点变换影响时,它看起来像屏幕坐标;一旦父节点移动、缩放、旋转,它就不再等同于屏幕坐标。
🧠 scale:节点有多大
scale 表示缩放。
例如:
ts
node.scale = 2;表示这个节点相对于原始大小放大 2 倍。
如果一个 Sprite 原本宽 100,高 100:
text
scale = 1 → 显示 100 × 100
scale = 2 → 显示 200 × 200
scale = 0.5 → 显示 50 × 50但是 scale 不只影响自己。
父节点的 scale 也会影响子节点。
例如:
text
Panel.x = 100
Panel.scale = 2
Button.x = 30Button 相对于 Panel 的偏移会被放大:
text
Button.worldX = Panel.x + Button.x * Panel.scale
= 100 + 30 * 2
= 160关键点:
父节点的位置决定坐标系原点,父节点的 scale 会影响子节点的 local 偏移。
🧠 rotation:节点朝向
rotation 表示旋转。
例如:
ts
node.rotation = 45;表示节点旋转 45 度。
在父子节点关系中,父节点旋转会带动子节点整体旋转。
例如:
text
Panel.rotation = 90
Button.x = 30Button 原本在 Panel 的右边。
当 Panel 旋转 90 度后,Button 的 local 坐标没变,但它在世界坐标中的方向变了。
这就是为什么只用 x、y 不够。
🔍 为什么 Transform 要拆成 position、rotation、scale?
因为开发者需要分别控制它们。
移动:
ts
node.x += 10;缩放:
ts
node.scale = 1.2;旋转:
ts
node.rotation += 10;如果引擎只暴露 Matrix 给开发者,那么每次移动、旋转、缩放都要自己计算矩阵,这对业务开发非常不友好。
所以引擎设计成:
text
对开发者:暴露 position、rotation、scale,直观易用
对引擎底层:合成为 Matrix,统一高效计算这就是设计上的分层。
🔍 从开发者视角到引擎视角
你平时写:
ts
node.x = 100;
node.rotation = 45;
node.scale = 2;开发者视角:
text
位置改了
角度改了
大小改了引擎视角:
text
Local Transform 变了
Local Matrix 需要更新
World Matrix 可能需要更新
子节点 World Matrix 也可能受影响
Renderer 需要用新的矩阵更新顶点普通开发看到 API。
高级开发看到 API 背后的数据流。
💼 工作中的真实案例
案例一:不要在复杂父节点上频繁做 scale 动画
假设一个复杂活动面板:
text
ActivityPanel
├── Background
├── Title
├── Button
├── List
├── Spine
└── Effect如果每帧执行:
ts
this.panel.scale += 0.01;这不只是面板自己变大。
它可能导致:
- Panel 的 World Matrix 更新
- 所有子节点的 World Matrix 更新
- 大量顶点重新计算
- UI 合批可能受影响
所以复杂 UI 的缩放动画要谨慎。
案例二:旋转父节点会影响所有子节点
例如转盘活动:
ts
this.wheelRoot.rotation += 5;所有奖品图标、文字、特效都会跟着旋转。
这很方便,但也意味着整棵子树都跟着变换。
节点越多,更新成本越高。
案例三:scale = 0 不等于隐藏
有些人为了隐藏节点,会写:
ts
node.scale = 0;这不推荐。
更常见的方式是:
ts
node.active = false;或者:
ts
node.opacity = 0;具体选择要看需求。
scale = 0 只是把节点缩小为 0,它仍然可能参与部分逻辑、布局或更新。
active = false 会让节点及其子节点进入非激活状态,但频繁切换 active 本身也有成本。
⚠️ 常见误区
误区一:position、rotation、scale 是完全独立的
从 API 角度看,它们是独立的。
但最终渲染时,它们会合成一个 Matrix,一起影响显示结果。
误区二:scale 只影响节点大小
scale 不只影响节点自己,也会影响子节点的位置和大小。
父节点 scale 变化后,子节点最终显示也会变化。
误区三:rotation 只是自己旋转
父节点 rotation 会影响整棵子树。
子节点自己的 local position 不变,但 world position 会变。
🎤 面试会怎么问
问题一:Transform 是什么?
参考回答:
Transform 表示一个节点的空间变换,通常包括 position、rotation、scale。它描述节点相对于父节点如何摆放。
问题二:为什么引擎内部要使用 Matrix?
参考回答:
因为 position、rotation、scale 以及父子节点变换最终需要统一计算。Matrix 可以把这些变换组合成一个统一的数据结构,方便计算世界变换和渲染顶点。
问题三:为什么父节点 scale 会影响子节点?
参考回答:
因为子节点的 World Matrix 由父节点的 World Matrix 和自身 Local Matrix 合成。父节点 scale 改变后,子节点的世界变换也会随之改变。
📝 今日练习
假设有下面结构:
text
Root
└── Panel
└── Button属性如下:
text
Root.x = 0
Panel.x = 100
Panel.scale = 2
Button.x = 30先不考虑旋转。
回答:
- 如果 Panel.scale = 1,Button.worldX 是多少?
- 如果 Panel.scale = 2,Button.worldX 大概是多少?
- Button 自己的 x 有没有变化?
- 为什么 scale 会影响 Button 的 worldX?
📝 今日练习参考答案
- 如果 Panel.scale = 1:
text
Button.worldX = Root.x + Panel.x + Button.x
= 0 + 100 + 30
= 130- 如果 Panel.scale = 2:
text
Button.worldX = Root.x + Panel.x + Button.x * Panel.scale
= 0 + 100 + 30 * 2
= 160注意不是:
text
130 * 2 = 260因为 Panel 自己的位置 Panel.x = 100 不会被自己的 scale 放大。
被放大的是:
text
Button 相对于 Panel 的 local 偏移 30- Button 自己的
x没有变化,仍然是:
text
Button.x = 30- Button 的 worldX 变化,是因为 Button 的世界变换受父节点 Panel 的 Matrix 影响。父节点 scale 会放大子节点的 local 偏移。
🚀 能力成长
学完这一课后,你应该具备以下能力:
- 能解释 Transform 的基本含义
- 能区分 position、rotation、scale 的职责
- 能解释为什么引擎对开发者暴露 Transform,但底层使用 Matrix
- 能解释为什么父节点 scale / rotation 会影响子节点
- 能初步分析复杂父节点动画带来的性能影响
✅ 本课总结
记住五句话:
text
Transform = position + rotation + scale。
position 决定节点相对父节点的位置。
scale 会影响节点和子节点的偏移与大小。
rotation 会影响节点和子节点的方向。
开发者操作 Transform,引擎底层合成为 Matrix。下一课: Node 到底是什么?为什么它是 Creator 的核心?