UE4 C++自定义ActorComponent

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

为什么要自定义Component

在UE4 中,Actor作为存在最广泛的类,其功能实现由各种不同的component来实现,比如StaticMeshComponent实现视觉效果与体积,PawnMovementComponent实现pawn运动,CollisionComponent实现碰撞等。有时官方给定的Component无法满足要求,又不想直接在自定义Actor里因为编写函数使Actor的文件功能过大,就需要自定义ActorComponent实现功能。

蓝图实现

蓝图是封装的C++代码,通过蓝图实现将很简单。在内容浏览器里右键新建 BlueprintClass,选择ActorComponent。常用的节点是GetOwner(),GetPlayerPawn(),Castto… 等节点。
一个简单的初始化如图所示
在这里插入图片描述

C++实现

蓝图方便简单,但是在不同版本迁移、程序维护、可读性上远不如C++代码;所以最好用C++实现基本功能。

内容浏览器,鼠标右键,新建C++类,基类选择 ActorComponent,然后编写代码;
在编写C++代码时会遇到蓝图编写不会遇到的困难。

我计划编写ActorComponent思路如下:
设计ActorComponent实现Actor跟踪Pawn功能,需要读取Pawn的位置,读取Actor的位置,并读取MyActor的某个变量实现规定距离的位移。这样需要自定义Component需要在MyActor头文件中声明并在构造函数中创建,而自定义Actor需要在Component头文件中声明并在别的函数体里获得Component的拥有者Actor。这样就需要Actor与ActorComponent相互知道对方类型,需要相互包含 .h 头文件。
在代码实现过程中出现了下面两个错误:

头文件循环依赖报错。

问题来源
如果 MyActorComponent.h 与AMyActor.h相互包含,预编译时就会无限循环复制,编译器报错;
解决办法:
.h头文件中声明,.cpp文件中include需要的头文件。
在UE4的源文件中,例如APawn.h;APawn.cpp;PawnMovement.h; PawnMovement.cpp都是这样解决的。

MyActorComponent.h

...
//类的前向声明
class AMyActor;
...
UCLASS()
class MYPRO_API UMyActorComponent: public UActorComponent 
{
...
//其他变量及函数声明
...
//定义变量
public:
	AMyActor* ThisActor;
...
};

MyActorComponent.Cpp中

...
#include "MyActorComponent.h"
...
//其他include
...
//构造函数
UMyActorComponent::UMyActorComponent()
{
...
ThisActor = Cast<AMyActor>(GetOwner());
...
//函数体
...
};
...
//其他
...

同理,在MyActor.h中

...
//类的前向声明
class UMyActorComponent;
...
UCLASS()
class  MYPRO_API UMyActorComponent() : public UActorComponent 
{
...
//其他变量及函数声明
...
//定义变量
public:
	UMyActorComponent* MyComponent;
...
};

在MyActor.cpp中

...
#include "MyActorComponent.h"
...
//其他include
...
//构造函数
UMyActorComponent::UMyActorComponent()
{
...
MyComponent = CreateDefalutSubobject<UMyActorComponent>(TEXT("MyComponent"));
...
//函数体
...
};
...
//其他
...

在VS里 生成 成功,而在引擎里点击Compile(编译)时直接崩溃。

提示崩溃发生在MyActorComponent.cpp中一句代码

UMyActorComponent::UMyActorComponent()
{
...
ThisActor = Cast<AMyActor>(GetOwner());
FVector ActorLoc = ThisActor->GetActorLocation();//此处不崩溃
Size = ThisActor->ActorSize; //此处崩溃;Size为头文件已声明的变量
...
//函数体
...
};

如果改为 int Size = 4000;就没事;
想了一天,搞了很久,终于在伟大师兄的英明指导下,排除可能的原因,最后将崩溃的这句写成单独小函数,

void MyActorComponent::SetSize()
{Size = ThisActor->ActorSize;}

在MyActor.cpp中调用


UMyActorComponent::UMyActorComponent()
{
...
MyComponent = CreateDefalutSubobject<UMyActorComponent>(TEXT("MyComponent"));
MyComponent->SetSize();
...
//函数体
...
};

好使了!编译通过不崩溃了,功能实现了。师兄厉害。
继续优化,构造函数将Size初始化为常量100,将SetSize()函数在MyActorComponent.cpp的BeginPlay()中调用进行赋值最好。
想来出现这种问题的原因:
Component的构造是在Actor的构造函数中通过CreateDefalutSubobject函数实现的,所以Component实现构造时Actor构造未完成,所以调用Actor的变量可能会造成意想不到的结果,造成程序的崩溃
所以构造函数最好仅仅实现变量的初始简单赋值,调用等其他功能写成小函数,在合适的地方调用。

师兄牛逼
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的UE4 C++生成Actor的例子,假设你已经创建了一个新的C++项目: 1. 创建一个新的C++类,继承自AActor。例如,我们创建一个名为MyActor的类: ```cpp UCLASS() class MYPROJECT_API AMyActor : public AActor { GENERATED_BODY() public: AMyActor(); virtual void BeginPlay() override; virtual void Tick(float DeltaTime) override; }; ``` 2. 在MyActor.cpp文件中实现构造函数和BeginPlay函数: ```cpp AMyActor::AMyActor() { // 设置Actor的根组件 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent")); // 创建一个静态网格组件 UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent")); MeshComponent->SetupAttachment(RootComponent); // 加载静态网格 constructorHelpers::FObjectFinder<UStaticMesh> Mesh(TEXT("/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube")); if (Mesh.Succeeded()) { MeshComponent->SetStaticMesh(Mesh.Object); } } void AMyActor::BeginPlay() { Super::BeginPlay(); // 在控制台输出Actor的位置 UE_LOG(LogTemp, Warning, TEXT("MyActor is at %s"), *GetActorLocation().ToString()); } ``` 3. 在MyActor.cpp文件中实现Tick函数,使Actor在每帧旋转: ```cpp void AMyActor::Tick(float DeltaTime) { Super::Tick(DeltaTime); // 每帧旋转Actor FRotator Rotation = GetActorRotation(); Rotation.Yaw += DeltaTime * 100.f; SetActorRotation(Rotation); } ``` 4. 在MyActor.h文件中添加头文件和构造函数声明: ```cpp #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Engine/StaticMesh.h" #include "Components/StaticMeshComponent.h" #include "MyActor.generated.h" UCLASS() class MYPROJECT_API AMyActor : public AActor { GENERATED_BODY() public: AMyActor(); virtual void BeginPlay() override; virtual void Tick(float DeltaTime) override; private: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = "true")) UStaticMeshComponent* MeshComponent; }; ``` 5. 在你的场景中添加一个MyActor,例如在GameMode的BeginPlay函数中: ```cpp void AMyProjectGameModeBase::BeginPlay() { Super::BeginPlay(); // 创建一个新的MyActor AMyActor* MyActor = GetWorld()->SpawnActor<AMyActor>(AMyActor::StaticClass(), FVector(0.f, 0.f, 0.f), FRotator(0.f, 0.f, 0.f)); } ``` 6. 运行游戏,你应该可以看到一个旋转的立方体Actor。 希望这个例子能够帮助你理解如何使用UE4 C++生成Actor

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值