外观
Lesson 003|什么是 World Matrix?为什么父节点移动,子节点也会移动?
Tags: #Creator2.x #Node #Transform #Matrix #WorldMatrixDifficulty: ⭐⭐☆☆☆
🎯 本课目标
- 理解
Local和World的区别 - 理解为什么父节点移动,子节点也会跟着移动
- 初步理解 Matrix 在引擎中的作用
- 为后续学习 Transform、Renderer、DirtyFlag 和性能优化打基础
🧩 上节课回顾
上一课我们讲了:
text
this.node.x = 100
│
▼
Setter
│
▼
Node 数据更新
│
▼
Dirty Flag
│
▼
等待 Renderer
│
▼
World Matrix
│
▼
GPU 绘制
│
▼
Screen其中有一个关键点:
修改
node.x后,并不是立刻画到屏幕上,而是先修改节点数据,然后等待渲染阶段统一更新。
今天我们重点理解其中的:
World Matrix
💡 为什么需要 World Matrix?
假设有两个节点:
text
Parent.x = 100
Child.x = 50那么 Child 最终显示在屏幕上的 x 通常是:
text
100 + 50 = 150因为 Child 的位置不是直接相对于屏幕,而是相对于父节点。
所以:
text
Child 的最终位置 = Parent 的世界位置 + Child 自己的本地位置在没有旋转和缩放的简单情况下,可以这样理解。
🧠 Local 和 World
Local
Local 表示:
相对于父节点的坐标或变换。
例如:
ts
child.x = 50;意思不是:
child 在屏幕上的 x 是 50。
而是:
child 相对于父节点偏移 50。
World
World 表示:
相对于整个世界 / 场景 / 屏幕参考系的最终坐标或变换。
例如:
text
Parent.x = 100
Child.x = 50那么:
text
Child.worldX = 150🧠 Matrix 是什么?
Matrix 中文叫:
矩阵
你现在可以先把它理解成:
一张数字表格。
例如 2D 游戏里常见的变换矩阵可以想象成:
text
[ a c tx ]
[ b d ty ]
[ 0 0 1 ]现阶段不用纠结每个数字的数学含义。
在游戏引擎里,Matrix 的作用是:
把 position、rotation、scale 这些变换信息打包到一起。
也可以简单理解成:
Matrix = 节点的变换规则包。
🧠 Local Matrix 和 World Matrix
每个 Node 可以简单理解为有两类变换信息:
text
Local Matrix
World MatrixLocal Matrix
Local Matrix 由节点自己的属性计算出来:
text
position
rotation
scale
anchor
skew它表示:
我相对于父节点应该怎么变换。
World Matrix
World Matrix 由父节点的 World Matrix 和自己的 Local Matrix 合成。
可以简单理解为:
text
child.worldMatrix = parent.worldMatrix * child.localMatrix不用纠结矩阵乘法细节。
现在只需要记住:
子节点最终的世界变换,依赖父节点的世界变换。
🔍 为什么父节点移动,子节点会跟着移动?
因为子节点的 World Matrix 依赖父节点。
text
Parent worldMatrix 变化
│
▼
Child worldMatrix 也需要重新计算
│
▼
Child 显示位置变化所以:
ts
parent.x = 100;即使子节点自己的 x 没有变化,它在屏幕上的位置也会变化。
因为:
子节点 local 没变,但它依赖的父节点 world 变了。
💼 工作中的真实案例
案例一:复杂 UI 面板移动
假设有一个活动面板:
text
ActivityPanel
├── Background
├── Title
├── CloseButton
├── RewardList
├── CountDownLabel
├── Effect
└── ManyItems如果每帧移动整个面板:
ts
this.panel.x += 10;看起来只改了一个节点。
但实际上可能影响:
- Panel 自己
- Panel 下所有子节点
- 子节点的 World Matrix
- 子节点的渲染顶点数据
所以复杂 UI 面板移动时,CPU 可能会上升。
案例二:ScrollView 列表
ScrollView 中如果存在大量 item,并且频繁修改 item 的位置,可能导致大量节点矩阵更新。
所以大型列表通常需要:
- 虚拟列表
- item 复用
- 减少节点数量
- 减少频繁 Layout
案例三:Layout / Widget 频繁刷新
Layout 或 Widget 会修改子节点的位置。
如果它们每帧都刷新,就会导致大量子节点反复 Dirty。
性能优化时要重点关注:
是否有 Layout、Widget、ScrollView 在频繁触发 Transform 更新。
⚠️ 常见误区
误区一:child.x 就是屏幕坐标
不是。
child.x 通常是本地坐标,是相对于父节点的。
误区二:只改父节点,不会影响子节点
会影响。
父节点的 World Matrix 变化后,子节点的最终世界变换也会变化。
误区三:矩阵太难,所以可以完全不学
不用一开始学复杂数学。
先理解它的工程意义:
Matrix 是引擎统一处理位移、旋转、缩放的工具。
🎤 面试会怎么问
问题一:Cocos 中 node.position 是世界坐标还是本地坐标?
参考回答:
通常是本地坐标,相对于父节点。真正渲染时,引擎会结合父节点变换计算出世界坐标。
问题二:为什么移动父节点,所有子节点都会跟着移动?
参考回答:
因为子节点的 World Matrix 依赖父节点的 World Matrix。父节点变换发生变化后,子节点的世界矩阵也需要重新计算。
问题三:为什么一个复杂 UI 面板移动时可能会卡?
参考回答:
因为移动父节点会导致整棵子树的世界矩阵变脏,渲染前需要重新计算大量节点的矩阵和顶点数据。
📝 今日练习
假设有下面结构:
text
Root
└── Panel
└── Button属性如下:
text
Root.x = 0
Panel.x = 100
Button.x = 30回答:
- Button 的 world x 是多少?
- 如果 Panel.x 改成 200,Button 的 world x 是多少?
- 这个过程中 Button 自己的
x有没有变化? - 为什么 Button 显示位置变了?
📝 今日练习参考答案
- Button 的 world x 是:
text
0 + 100 + 30 = 130- 如果 Panel.x 改成 200,Button 的 world x 是:
text
0 + 200 + 30 = 230- Button 自己的
x没有变化,仍然是:
text
Button.x = 30- Button 显示位置变了,是因为父节点 Panel 的位置变了。Button 的 local 坐标没变,但它的 world 坐标依赖父节点。
🚀 能力成长
学完这一课后,你应该具备以下能力:
- 能解释 Local 坐标和 World 坐标的区别
- 能解释为什么父节点移动,子节点也会移动
- 能理解 Matrix 是节点变换规则的数字化表示
- 能初步分析复杂 UI 移动导致 CPU 上升的原因
- 能为后续学习 Transform、DirtyFlag、Renderer 打基础
✅ 本课总结
记住四句话:
text
Local 是相对于父节点。
World 是最终显示到世界中的位置。
Matrix 是节点变换规则包。
父节点变了,子节点的 World Matrix 也会受影响。下一课: Transform 为什么要分 position、rotation、scale?