UE4 – 学习笔记之一

先贴上原文:使用 C++类向导 创建 LightSwitchCodeOnly 类

学习使用中完全有问题:原因可能是文档太旧,更新频繁也可能UE4官方并不重视C++

不过蓝图的确方便,但毕竟C++才是本质,还是有必要了解的

不多说废话了…下面是我遇到的问题以及相对的解决方法【我使用的是4.18.3】

首先,当我已经完成了仅使用蓝图完成这个可开关灯的类时,已经迫不及待想要尝试使用C++完成这个任务

第一次使用发现这个编码的确与众不同(与Unity3D相比)

比如

UCLASS()

这样的宏…等等,这被称为反射机制,与之相关的更多的资料请参考此文章结尾的参考

以上即为官方文档中的说明。【注意:在一切问题的开始一定要先检查拼写错误…血的教训】

也许你的Visual Studio并不能好好地工作,你可以参考官方的建议: 为虚幻 4 设置 Visual Studio

当然,也有XCode的相关配置指导。 但是即使我跟着指导完成了设置,似乎并没有我想象中的那样完美.

问题一:

#include "Components/PointLightComponent.h"

#include "Components/SphereComponent.h"

没错,我早该想到的:也许是这个原因,这个组件没有被include 这就是与它们相关的种种错误的根源

class UPointLightComponent* PointLight1;

class USphereComponent* Sphere1;

请将它们添加到LightSwitchCodeOnly.h中

问题二:

LightSwitchCodeOnly.h中:

UFUNCTION()
//void OnOverlapBegin(class AActor* otherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool BFromSweep, const FHitResult& SweepResult);
void OnOverlapBegin(class UPrimitiveComponent* HitComp,class AActor* otherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool BFromSweep, const FHitResult& SweepResult);

UFUNCTION()
//void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
void OnOverlapEnd(class UPrimitiveComponent* HitComp,class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

LightSwitchCodeOnly.cpp中:

Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin);
Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd);

 

如果完全按照文档中所说的那样一定会编译错误:当前AddDynamic()参数发生了变化,正如下面编译器提示的错误内容的那样

1>C:\Users\admin\Documents\Unreal Projects\first\Source\first\LightSwitchCodeOnly.cpp(24): error C2664: “void TBaseDynamicMulticastDelegate<FWeakObjectPtr,void,UPrimitiveComponent *,AActor *,UPrimitiveComponent *,int32,bool,const FHitResult &>::__Internal_AddDynamic<ALightSwitchCodeOnly>(UserClass *,void (__cdecl ALightSwitchCodeOnly::* )(UPrimitiveComponent *,AActor *,UPrimitiveComponent *,int32,bool,const FHitResult &),FName)”: 无法将参数 2 从“void (__cdecl ALightSwitchCodeOnly::* )(AActor *,UPrimitiveComponent *,int32,bool,const FHitResult &)”转换为“void (__cdecl ALightSwitchCodeOnly::* )(UPrimitiveComponent *,AActor *,UPrimitiveComponent *,int32,bool,const FHitResult &)”
1> with
1> [
1> UserClass=ALightSwitchCodeOnly
1> ]
1> C:\Users\admin\Documents\Unreal Projects\first\Source\first\LightSwitchCodeOnly.cpp(24): note: 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换

问题的解决应在LightSwitchCodeOnly.h中

OnOverlapBeginOnOverlapEnd的声明中添加一个新的参数

class UPrimitiveComponent* HitComp虽然我并不知道这个参数是干啥的…

不过现在AddDynamic就没问题了

问题三:


被我注释的是原本错误的语法 因为它会得到以下编译结果:


这似乎又是一个更新,不过我找到了可以代替的实现:
Sphere1->AttachTo(RootComponent);
看来以前UE4中AttachParent直接是暴露的…

以上大概已经可以包含这个文档中与当前ue4版本所有的冲突了 最后贴上所有的代码:

 


LightSwitchCodeOnly.h:

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/PointLightComponent.h"
#include "Components/SphereComponent.h"
#include "LightSwitchCodeOnly.generated.h"

UCLASS()
//使用UCLASS宏进行处理,使得引擎意识到此类的存在
//类似的宏有UPROPERTY()UPFUNCTION()进行处理变量和属性
class FIRST_API ALightSwitchCodeOnly : public AActor
{
GENERATED_BODY()

public:

//class UPointLightComponent* PointLight1;
//class USphereComponent* Sphere1;

// Sets default values for this actor's properties
ALightSwitchCodeOnly(const FObjectInitializer& ObjectInitializer);
UPROPERTY(VisibleAnyWhere, Category = "Switch Components")
class UPointLightComponent* PointLight1;

UPROPERTY(VisibleAnyWhere, Category = "Switch Components")
class USphereComponent* Sphere1;

UFUNCTION()
//void OnOverlapBegin(class AActor* otherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool BFromSweep, const FHitResult& SweepResult);
void OnOverlapBegin(class UPrimitiveComponent* HitComp,class AActor* otherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool BFromSweep, const FHitResult& SweepResult);

UFUNCTION()
//void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
void OnOverlapEnd(class UPrimitiveComponent* HitComp,class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

UFUNCTION()
void ToggleLight();

UPROPERTY(VisibleAnywhere, Category = "Switch Variables")
float DesiredIntensity;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

};


LightSwitchCodeOnly.cpp:

#include "LightSwitchCodeOnly.h"
// Sets default values
ALightSwitchCodeOnly::ALightSwitchCodeOnly(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
DesiredIntensity = 3000.0f;

PointLight1 = ObjectInitializer.CreateDefaultSubobject<UPointLightComponent>(this, "PointLight1");
PointLight1->Intensity = DesiredIntensity;
PointLight1->bVisible = true;
RootComponent = PointLight1;

Sphere1 = ObjectInitializer.CreateDefaultSubobject<USphereComponent>(this, TEXT("Sphere1"));
Sphere1->InitSphereRadius(250.0f);
//Sphere1->AttachParent = RootComponent;
Sphere1->AttachTo(RootComponent);

//相当于注册回调函数,文档中说明为设置通知,使用代理函数
Sphere1->OnComponentBeginOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapBegin);
Sphere1->OnComponentEndOverlap.AddDynamic(this, &ALightSwitchCodeOnly::OnOverlapEnd);
}

void ALightSwitchCodeOnly::OnOverlapBegin(class UPrimitiveComponent* HitComp,class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
ToggleLight();
}
}

void ALightSwitchCodeOnly::OnOverlapEnd(class UPrimitiveComponent* HitComp,class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor && (OtherActor != this) && OtherComp)
{
ToggleLight();
}
}

void ALightSwitchCodeOnly::ToggleLight()
{
PointLight1->ToggleVisibility();
}
// Called when the game starts or when spawned
void ALightSwitchCodeOnly::BeginPlay()
{
Super::BeginPlay();

}

// Called every frame
void ALightSwitchCodeOnly::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

参考:
UE4反射系统简析(含实例过程分析)