外观
Lesson 005|Node 到底是什么?为什么它是 Creator 的核心?
Tags: #Creator2.x #Node #Component #Active #TransformDifficulty: ⭐⭐☆☆☆
🎯 本课目标
- 理解 Node 在 Creator2.x 中的核心作用
- 理解 Node 和 Component 的关系
- 理解为什么 Node 不等于 Sprite、Label、Button
- 理解 Node 的 active 对显示、事件、脚本和子节点的影响
- 为后续学习 Component、生命周期、事件系统和性能优化打基础
🧩 上节课回顾
上一课我们讲了 Transform:
text
Transform = position + rotation + scaleTransform 表示一个 Node 在空间中如何摆放。
也就是说:
text
position:放在哪里
rotation:旋转多少
scale:放大或缩小引擎对开发者暴露 position、rotation、scale,底层再把它们合成为 Matrix,用于计算 World Matrix 和最终渲染。
💡 Node 到底是什么?
在 Cocos Creator 里,Node 可以先理解成:
场景树里的一个“空间对象”。
它主要负责:
text
位置
旋转
缩放
父子关系
激活状态
层级关系
事件挂载
组件容器但是要注意:
Node 本身不等于 Sprite,不等于 Label,也不等于 Button。
Node 更像是一个“空壳”或者“挂载点”。
真正让它显示图片、显示文字、响应按钮逻辑的是挂在它身上的 Component。
🧠 Node 和 Component 的关系
一句话:
Node 决定“在哪里”,Component 决定“做什么”。
例如一个按钮:
text
StartButton
├── Sprite
├── Button
└── StartGameScript可以理解为:
text
StartButton:Node,负责位置、层级、active、挂载组件
Sprite:Component,负责显示图片
Button:Component,负责按钮交互和点击状态
StartGameScript:Component,负责开始游戏业务逻辑所以:
text
Node = 容器
Component = 能力如果没有 Node,Component 没有地方挂。
如果没有 Component,Node 就只是一个空节点。
🔍 为什么不让 Sprite 自己直接有位置?
你可能会想:
为什么不直接让 Sprite 有 x、y、scale、rotation?
比如:
text
Sprite.x = 100
Sprite.y = 200看起来也可以。
但问题是,一个游戏对象往往不只有一种能力。
比如一个按钮可能同时需要:
text
位置
图片
点击
动画
音效
红点
业务逻辑如果全部塞进 Sprite,Sprite 会越来越臃肿。
所以 Creator 采用更通用的设计:
text
Node 负责空间和层级
Component 负责具体能力例如:
text
ButtonNode
├── Sprite
├── Button
├── Animation
└── RedPointScript这就是组件化设计。
🧠 Node 的核心职责
1. 负责父子关系
例如:
text
Canvas
└── MainPanel
├── CloseButton
├── TitleLabel
└── RewardList这是一棵 Node 树。
父子关系决定:
text
谁跟着谁移动
谁受谁的 scale 影响
谁受谁的 active 影响
谁在层级上属于谁这也是 World Matrix 的基础。
2. 负责 Transform
Node 保存:
text
position
rotation
scale
anchor这些决定了它在父节点坐标系里的位置和变换。
例如:
ts
this.node.x = 100;
this.node.scale = 2;本质上都是在修改 Node 的 Transform。
3. 负责 active 状态
Node 有:
ts
node.active = false;它表示:
这个节点以及它下面的整棵子树是否处于激活状态。
如果父节点 active = false,那么它下面的子节点通常也不会继续正常显示和执行相关逻辑。
这可以理解为:
text
active 是树状传播的4. 负责挂载 Component
Node 自己通常不做具体业务。
它通过 Component 获得能力:
ts
this.node.addComponent(cc.Sprite);
this.node.addComponent(cc.Label);
this.node.addComponent(MyScript);所以:
text
Node 是容器
Component 是能力5. 负责事件
在 Creator 里,你经常写:
ts
this.node.on(cc.Node.EventType.TOUCH_END, this.onClick, this);事件也是挂在 Node 上的。
所以 Node 不只是空间对象,也是事件系统中的重要节点。
🔍 active = false 会影响什么?
假设有一个节点:
text
StartButton
├── Sprite
├── Button
└── StartGameScript当执行:
ts
StartButton.active = false;可以理解成:
这个节点以及它下面的整棵子树都被关闭了。
它会影响几个方面。
1. Sprite 不再显示
因为节点 inactive 后,渲染组件不会继续参与正常渲染。
text
Sprite 不显示图片2. Button 不再响应点击
节点 inactive 后,事件系统通常不会再把点击事件分发给它。
text
Button 不可点击3. StartGameScript 的 update 等逻辑通常不会继续执行
如果脚本里有:
ts
update(dt) {
// 每帧逻辑
}当节点 inactive 后,这个组件一般不会继续执行正常的 update。
这也是为什么隐藏复杂界面时,用 active = false 可以减少 CPU 开销。
4. 子节点也会受到影响
例如:
text
StartButton
├── Icon
├── Text
└── RedPoint当:
ts
StartButton.active = false;下面的 Icon、Text、RedPoint 也会受到影响。
🧠 active 和 activeInHierarchy
Creator 中通常要区分:
text
active
activeInHierarchy可以先这样理解:
text
active:我自己想不想激活
activeInHierarchy:考虑父节点以后,我最终是否真的激活例如:
text
Panel.active = false
Button.active = true此时:
text
Button.active = true
Button.activeInHierarchy = false为什么?
因为 Button 自己想激活,但它的父节点 Panel 关闭了,所以它在场景中最终还是不激活。
这个概念后面会在 Lesson009 继续深入。
💼 工作中的真实案例
案例一:为什么节点很多会卡?
每个 Node 都可能带来:
text
Transform 计算
active 状态检查
事件管理
组件生命周期
渲染数据更新即使它不显示图片,只要它在节点树里,也可能有管理成本。
所以优化 UI 时,不要只看图片大小,也要看:
text
Node 数量
Component 数量
层级深度
是否频繁 active 切换
是否频繁修改 Transform案例二:为什么不要滥用空节点?
空节点很方便。
例如:
text
Root
└── Panel
└── Content
└── ItemRoot
└── IconRoot
└── Icon这样层级清晰,但如果过度拆分,节点树会变深。
节点树越深:
text
World Matrix 传播越复杂
active 传播越复杂
查找节点越麻烦
管理成本越高所以空节点要用,但不要滥用。
案例三:为什么 getChildByName 不适合频繁调用?
例如:
ts
let icon = this.node.getChildByName("Icon");偶尔用可以。
但如果在 update() 里频繁查找,就会有问题。
因为它需要在子节点列表里查找。
更好的做法是在属性面板绑定:
ts
@property(cc.Node)
icon: cc.Node = null;或者在 onLoad 缓存:
ts
this.icon = this.node.getChildByName("Icon");核心思想:
节点树是结构,不要每帧在结构里反复搜索。
⚠️ 常见误区
误区一:Node 就是显示对象
不是。
Node 本身不一定显示。
只有挂了 Sprite、Label、Graphics 等渲染组件,它才会产生显示内容。
误区二:空节点没有成本
不是。
空节点虽然不渲染,但仍然有层级、Transform、active、组件管理等成本。
误区三:Component 可以脱离 Node 存在
在 Creator 中,Component 通常必须挂在 Node 上。
Component 是 Node 的能力扩展。
误区四:节点越细越好
不一定。
合理拆分可以让结构清晰。
但过度拆分会增加节点数量和层级深度。
🎤 面试会怎么问
问题一:Node 和 Component 的区别是什么?
参考回答:
Node 负责空间、层级、Transform、active 和事件等基础能力;Component 负责具体功能,比如显示图片、显示文字、播放动画、处理业务逻辑。Node 是容器,Component 是能力。
问题二:为什么 Creator 采用 Node + Component,而不是继承一堆类?
参考回答:
组件化设计比继承更灵活。一个节点可以通过挂载不同组件组合出不同能力,避免类继承层级过深,也更适合编辑器可视化配置。
问题三:为什么节点数量过多会影响性能?
参考回答:
因为每个节点都可能参与 Transform 更新、active 状态传播、组件生命周期管理、事件管理和渲染数据更新。即使空节点不产生 DrawCall,也会有 CPU 管理成本。
问题四:active 和 activeInHierarchy 的区别是什么?
参考回答:
active 表示节点自身是否希望激活;activeInHierarchy 表示考虑父节点状态后,节点在场景树中最终是否真的激活。父节点 inactive 时,子节点即使 active = true,activeInHierarchy 也会是 false。
📝 今日练习
假设有一个按钮节点:
text
StartButton
├── Sprite
├── Button
└── StartGameScript回答:
StartButton是 Node 还是 Component?Sprite的职责是什么?Button的职责是什么?StartGameScript的职责是什么?- 如果
StartButton.active = false,这些组件大概会受到什么影响?
📝 今日练习参考答案
StartButton是 Node。Sprite是 Component,负责显示图片。Button是 Component,负责按钮交互、点击状态和按钮行为。StartGameScript是自定义 Component,负责开始游戏相关的业务逻辑。如果
StartButton.active = false:
text
Sprite 不再显示
Button 不再响应点击
StartGameScript 的 update 等逻辑通常不会继续执行
子节点也会受到影响
整个节点从 activeInHierarchy 的激活树中退出🚀 能力成长
学完这一课后,你应该具备以下能力:
- 能解释 Node 的核心职责
- 能解释 Node 和 Component 的区别
- 能理解为什么 Creator 使用组件化设计
- 能解释 active 对显示、点击、脚本 update、子节点的影响
- 能初步分析节点数量、层级深度、空节点过多带来的性能问题
- 能理解为什么频繁 getChildByName 不适合放在 update 中
✅ 本课总结
记住六句话:
text
Node 是场景树里的空间对象。
Node 负责位置、旋转、缩放、父子关系、active、事件和组件挂载。
Component 是挂在 Node 上的能力。
Node 决定“在哪里”,Component 决定“做什么”。
active 会影响节点自身和整棵子树。
空节点不渲染,但不代表没有成本。下一课: Component 是什么?为什么逻辑要挂在组件上?