先贴上原文:使用 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中
在OnOverlapBegin
和OnOverlapEnd
的声明中添加一个新的参数
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反射系统简析(含实例过程分析)