一、定义:什么是组件?
组件是一个功能模块,可以被添加给 Actor 来赋予它特定的能力。例如,添加一个“旋转运动”组件就能让一个原本静止的 Actor 自动旋转;添加一个“音频”组件,它就能播放声音。
组件不能脱离 Actor 而独立存在。你可以将 Actor 想象成一个“身体”,而组件就是附着在它身上的各种“器官”或“零件”,共同决定它“是什么”和“能做什么”。这也是虚幻引擎强烈推荐的 “组合优于继承” 的设计模式的体现:我们不是去创建一个庞大而复杂的武器基类,而是组合一个 UStaticMeshComponent(外观)和一个 USphereComponent(碰撞)来快速搭建它。
一个关键的细节:组件实例化
当你创建同一个 Actor 类的多个实例时,每个实例都会拥有自己独立、唯一的组件副本。比如,一辆“汽车”的蓝图定义了两个“轮子”组件,那么你每创建一辆新车,它都会拥有自己独立的两个轮子,彼此不会干扰。
二、核心类型:三大组件体系
组件体系有一个清晰的继承层级,从最抽象的 UActorComponent 到功能最丰富的 UPrimitiveComponent。
1. Actor 组件(UActorComponent)
Actor 组件是所有组件的基类,也是功能最抽象的一类组件。它没有“变换”(Transform,即位置、旋转、缩放)属性,在游戏世界中没有一个物理上的位置。
适合的场景是那些“思想”和“属性”,例如:物品栏系统、生命值管理、能量恢复,或是控制角色何时能奔跑、跳跃的状态逻辑。
2. 场景组件(USceneComponent)
场景组件继承自 UActorComponent,它拥有一个 “变换”,意味着它可以在游戏世界中占据一个位置。
但它本身不具备任何可见的几何体,可以想象成一个看不见的“点”。适合的场景包括:摄像机、音频源、物理力场,以及将其他组件附着在一起的“骨架”,例如用于控制视角的“弹簧臂”组件就是一个典型的场景组件。
3. 图元组件(UPrimitiveComponent)
图元组件是功能最丰富的类型。它继承自场景组件,因此拥有“变换”,同时它还具有几何表示(几何体)。
这意味着图元组件既能“存在”,又能“被看见”或“被碰到”。它主要承担两类核心任务:
-
渲染(被看见):几乎所有在屏幕上能看到的东西都由它负责,比如角色的静态网格体组件、骨骼网格体组件。
-
碰撞(被碰到):处理物理交互,比如球体碰撞组件(SphereComponent)、盒体碰撞组件(BoxComponent)。
三、一些内置的组件
1. 核心渲染与碰撞组件
| 组件类型 | 描述 | 主要用途 |
|---|---|---|
| 静态网格体组件 | 使用静态网格体资产进行渲染的组件。 | 适用于不会变形且性能要求高的静态环境物体,如墙壁、石头、树木等。 |
| 骨骼网格体组件 | 使用骨骼网格体资产进行渲染的组件,支持复杂的骨骼动画系统。 | 适用于需要播放动画的动态物体,如玩家角色、NPC、怪物等。 |
| 模型组件 | 用于创建具有物理表示的简单形状(如胶囊体、球体、盒体)的组件。 | 主要用作物理碰撞的触发器或简化碰撞体,也常作为Actor的根组件。 |
| 实例化静态网格体组件 | 专门用于高效渲染大量相同模型的组件。 | 适用于需要生成成百上千个相同物体的场景,如大规模草地、树木、石块群。 |
2. 核心功能与视觉特效组件
| 组件类型 | 描述 | 主要用途 |
|---|---|---|
| 摄像机组件 | 代表玩家或AI视角的相机。 | 用于定义游戏中的观察视点,分为固定视角和跟随视角。 |
| 弹簧臂组件 | 一种特殊的场景组件,用于平滑地跟随目标并保持最佳摄像机距离。 | 避免摄像机穿透墙壁,是第三人称游戏中随动摄像机系统的核心。 |
| 音频组件 | 用于播放音效和背景音乐的组件。 | 实现游戏内任何需要发声的物体,从角色脚步声到环境背景音。 |
| 粒子系统组件 | 用于创建和播放粒子特效(如火焰、烟雾、魔法效果)的组件。 | 适用于游戏中的各种视觉特效表现。 |
| 移动组件 | 专门用于控制Actor移动逻辑的组件。 | 用于实现角色行走、飞行、车辆驾驶等不同移动方式。 |
四、工作流程
1. 添加组件
在蓝图编辑器里,最直观的方式是使用“组件”面板。打开蓝图后,“组件”窗口会显示当前蓝图已有的组件树。点击绿色的 “添加 (+)” 按钮,从下拉菜单中(如摄像机组件、静态网格体组件等)选择一个,就能将它添加到Actor中,并成为其层级的一部分。
你也可以直接从内容浏览器中拖拽一个静态网格体、声音提示或粒子系统资产到“组件”面板,引擎会自动为你创建对应的组件。
2. 组件层级与根组件
虚幻引擎要求组件之间构成一棵“树”状的层级结构。这个层级结构是嵌套的,位于最顶层的组件称为该Actor的“根组件”。移动根组件会带动其所有子组件一同移动、旋转和缩放。
这种层级关系非常实用:例如,一个“人形”角色可以将一个胶囊体组件作为根组件,然后将骨骼网格体组件(身体)和摄像机组件(视角)都附着在它上面。这样一来,我们只需要移动根组件,整个角色和摄像机都会随之移动。
3. 生命周期与注册/注销
为了能让组件在世界中生效并逐帧更新,引擎需要对它进行 “注册” 。一般情况下,当你在Actor的构造函数中创建组件时,这个过程是自动完成的。但如果你在运行时动态地创建了一个组件,必须手动调用它的 RegisterComponent() 函数来激活它。当你想要禁用或移除一个组件时,则需要调用 UnregisterComponent() 来将它从世界中注销。
Tick事件
默认情况下,组件的Tick更新是关闭的。如果需要在每一帧执行逻辑(例如,持续追踪某个目标),你必须在组件的构造函数中显式地启用它。
// 在构造函数中启用Tick PrimaryComponentTick.bCanEverTick = true;
五、蓝图与C++的协作
方法一:让蓝图继承你的C++类
你可以先创建一个C++ Actor类(如 AMyCustomActor),包含你想要的核心逻辑。编译后,在内容浏览器中右键选择蓝图类,并在父类选择中找到你刚才创建的 AMyCustomActor。这样,新的蓝图就拥有了C++父类中的所有属性和函数,你可以直接在蓝图图表中调用它们。
方法二:组件式组合(通过组件添加功能)
如果你希望某些功能可以被多个不同的Actor类共享,可以将这些逻辑封装成一个自定义的Actor组件。
蓝图示例:自定义健康组件
-
创建组件蓝图:在内容浏览器中右键选择蓝图类,在弹出的“选择父类”窗口中,选择 Actor组件,并将其命名为
BP_HealthComponent。 -
添加变量:打开新创建的组件蓝图,在“我的蓝图”面板中添加两个浮点变量:
MaxHealth和Health。将MaxHealth的默认值设为100.0。 -
初始化生命值:在“事件图表”中,在
Event Begin Play节点后连接Set Health节点,并将MaxHealth变量的输出连接到Set Health节点的Health输入上,确保组件被添加时,生命值始终是满的。 -
为Actor添加组件:编译保存后,打开你的角色蓝图。在“组件”面板点击“添加”,从列表中选择
BP_HealthComponent。
六、核心原则与最佳实践
🟢 推荐做
-
组合优于继承:尽量使用小而专的组件来组合复杂功能,而不是创建庞大的类继承体系。
-
性能优化:非必要时禁用Tick,改用事件或计时器驱动逻辑。
-
使用GameplayTags:用灵活的游戏标签系统代替字符串或枚举进行状态管理。
🔴 避免做
-
不要在Tick中做沉重的工作:每帧执行的函数应尽可能轻量,避免阻塞游戏主线程。
-
避免硬编码资产路径:在C++代码中,应优先使用
TSoftObjectPtr在构造函数中加载,然后在蓝图编辑器中设置具体的网格体资产。 -
必须在合适位置进行碰撞设置:若仅需视觉效果而不需要物理碰撞,应在细节面板中正确禁用碰撞预设,以免产生不必要的物理计算开销。
-
必须正确处理实例管理:使用实例化静态网格体组件时,必须正确维护索引数组与组件之间的对应关系,并在Actor销毁时同步清除。
感谢您的来访,获取更多精彩文章请收藏本站。









暂无评论内容