本文用于记录UE学习。
UE C++中,一个常见的Actor的创建过程可以分成三部分:
- 在.h中声明组件变量
- 在构造函数中使用CreateDefaultSubobject创建组件。
- 在BeginPlay()中执行游戏运行时的初始化
组件是 Actor 持有的子对象,可以负责显示、碰撞、声音、摄像机等功能。
创建一个Actor包含:
- 场景组件 SceneRoot
- 静态网格组件 MeshComponent
- 盒体碰撞组件 BoxCollision
实例写法:
//.h #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ComponentActor.generated.h" // 前置声明 class USceneComponent; class UStaticMeshComponent; class UBoxComponent; UCLASS() class NEW_CPP_API AComponentActor : public AActor { GENERATED_BODY() public: AComponentActor(); protected: virtual void BeginPlay() override; protected: // 根组件 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") TObjectPtr<USceneComponent> SceneRoot; // 模型组件 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") TObjectPtr<UStaticMeshComponent> MeshComponent; // 碰撞组件 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") TObjectPtr<UBoxComponent> BoxCollision; };前置声明是什么?
它是提前告诉编译器有一个类叫USceneComponent,类的具体内容以后再告知。编译器此时只知道这些名字是类,不知道类内部有什么。
TObjectPtr<USceneComponent> SceneRoot; 是什么?
可分为三个部分:
- TObjectPtr 模板类型
- <USceneComponent> 保存的对象类型
- SceneRoot 变量名
表示创建一个名为SceneRoot,它用于引用USceneComponent类型的UObject对象。
此处也可以用指针,初学阶段貌似是没有差异的:USceneComponent* SceneRoot;
#include "ComponentActor.h" #include "Components/SceneComponent.h" #include "Components/StaticMeshComponent.h" #include "Components/BoxComponent.h" AComponentActor::AComponentActor() { // 如果不需要每帧执行 Tick,就关闭 PrimaryActorTick.bCanEverTick = false; // 1. 创建场景根组件 SceneRoot = CreateDefaultSubobject<USceneComponent>( TEXT("SceneRoot") ); // 2. 将其设置为 Actor 的根组件 SetRootComponent(SceneRoot); // 3. 创建静态网格体组件 MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>( TEXT("MeshComponent") ); // 4. 将网格体附加到根组件 MeshComponent->SetupAttachment(SceneRoot); // 5. 创建盒体碰撞组件 BoxCollision = CreateDefaultSubobject<UBoxComponent>( TEXT("BoxCollision") ); // 6. 将碰撞组件附加到根组件 BoxCollision->SetupAttachment(SceneRoot); // 7. 设置碰撞盒大小 BoxCollision->SetBoxExtent(FVector(50.0f, 50.0f, 50.0f)); // 8. 设置组件的相对位置 MeshComponent->SetRelativeLocation( FVector(0.0f, 0.0f, 0.0f) ); BoxCollision->SetRelativeLocation( FVector(0.0f, 0.0f, 0.0f) ); } void AComponentActor::BeginPlay() { Super::BeginPlay(); if (GEngine) { GEngine->AddOnScreenDebugMessage( -1, 3.0f, FColor::Green, TEXT("ComponentActor BeginPlay") ); } }SceneRoot = CreateDefaultSubobject<USceneComponent>(
TEXT("SceneRoot")
);
右边创建一个场景组件对象;左边把创建出来的组件对象地址保存到头文件声明的SceneRoot变量中。.cpp文件中的SceneRoot和.h中的SceneRoot是同一个成员变量。
CreateDefaultSubobject为创建组件或其他子对象的函数。基本格式如下:
组件变量 = CreateDefaultSubobject<组件类型>( TEXT("组件名称") ); //例如: MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>( TEXT("MeshComponent") ); //UStaticMeshComponent:要创建的组件类型 //MeshComponent:保存组件地址的成员变量 //"MeshComponent":组件在UE对象系统中的名称设置根组件SetRootComponent()
每个具有空间位置的Actor通常都需要一个根组件。Actor世界位置、世界旋转、世界缩放都以根组件为基础。
设置组件父子关系:
MeshComponent->SetupAttachment(SceneRoot)
表示将MeshComponent绑定为SceneRoot的子类。
为什么使用USceneComponent作为根组件
USceneComponent具有Transform,支持组件附加,且本身没有模型、没有碰撞;可类比于蓝图组件面板中的DefaultSceneRoot组件
对于需要移动和碰撞的Actor(如:子弹、拾取物、陷阱、移动平台等),通常可以让碰撞组件直接作为根组件。