UE4 C++实现自动门

Posted Vincent_0000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4 C++实现自动门相关的知识,希望对你有一定的参考价值。

前言

本文章将会教你用C++如何实现自动门。
我们任务踩到开关上面门就会升起来,我们离开门之后,两秒后门会降下来。

创建C++文件

右键创建C++文件,继承Actor类。

.h文件内容

<声明门和开关的静态网格体>
静态网格体在哪里都可以看到,并且在蓝图中可以读写。

UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	class UStaticMeshComponent* FloorSwitch;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
	class UStaticMeshComponent* Door;

<声明触发开关的感应器>
盒子组件在哪里都可以看到,并且在蓝图中可以读写。

UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
		class UBoxComponent* TriggerBox;

<声明储存初始位置的变量>
有了门和开关的初始位置,之后确定门移动到什么位置就很好计算。

UPROPERTY(BlueprintReadWrite)
		FVector InitialDoorLocation; // 储存门的初始位置
UPROPERTY(BlueprintReadWrite) 
	FVector InitialSwitchLocation; // 储存开关的初始位置

<声明组件重合的触发反应的函数>
我们人物触碰到开关后做出的反应的实现就在这两个函数之中,一个是开始重叠的时候,一个是重叠结束的时候。

UFUNCTION()
		void OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,  UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

UFUNCTION()
	void OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

这个函数这样声明不是凭空得出来的,因为我们要和我们的开关组件联系起来,那么联系起来的函数是有规定的。

首先我们看如何将他们联系起来:

TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AAFloorSwitch::OnOverlapBegin);
TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AAFloorSwitch::OnOverlapEnd);

他们之间的联系就需要用上面这个来搭建联系,
我们点进去查看他的实现:

UPROPERTY(BlueprintAssignable, Category="Collision")
	FComponentBeginOverlapSignature OnComponentBeginOverlap;

我们看到他前面有一段声明,应该是他的类型声明吧?
我们找到他:
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_SixParams( FComponentBeginOverlapSignature, UPrimitiveComponent, OnComponentBeginOverlap, UPrimitiveComponent*, OverlappedComponent, AActor*, OtherActor, UPrimitiveComponent*, OtherComp, int32, OtherBodyIndex, bool, bFromSweep, const FHitResult &, SweepResult);
特别长,其实看不太懂,只知到这个函数的第一个和第三个对应着我们刚刚看到那个变量?,从第四个开始到后面的所有就是我们函数构建要填写的数据类型和名字,(数据类型和变量名之间的逗号要记得去掉。)
重叠结束函数也类似。

<声明存储时间变量>
FTimerHandle TimerHandle; 这里出现了一个新东西,FTimerHandle感觉就是储存某个实例运行对应时间的一个变量。

<声明离开之后关门时间变量>

UPROPERTY(EditAnywhere, BlueprintReadWrite)
	float SwitchTime;

<声明关门函数>

UFUNCTION()
	void CloseDoor();

<声明门的开关操作实现函数>
这个函数和我们之前见到的不一样,因为他的属性标签是BlueprintImplementableEvent,这个的意思就是这个函数在C++中声明,蓝图中实现,待会我们会知道如何去实现这个函数。

UFUNCTION(BlueprintImplementableEvent) // 蓝图实现函数
	void RaiseDoor(); // 门上升函数

UFUNCTION(BlueprintImplementableEvent)
	void LowerDoor();// 门下降函数

UFUNCTION(BlueprintImplementableEvent)
	void RaiseFloorSwitch(); // 开关上升

UFUNCTION(BlueprintImplementableEvent)
	void LowerFloorSwitch(); // 开关下降

<声明更新函数>

UFUNCTION(BlueprintCallable)
	void UpdateDoorLocation(float Z);

UFUNCTION(BlueprintCallable)
	void UpdateSwitchLocation(float Z);

.cpp 文件实现

<构造函数>

  • TriggerBox的初始化

创建实例,并且设他为根组件

TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox"));
RootComponent = TriggerBox;

设置开关盒子的碰撞类型:

它有四种类型:
NoCollision 无碰撞
QueryOnly 仅响应踪迹碰撞,无物理碰撞
PhysicsOnly 仅响应物理碰撞,无踪迹碰撞
QueryAndPhysics 同时响应物理碰撞和踪迹碰撞

在因为我们是站在开关上面,需要他做出一些其他的反应,而不是阻挡,所以我们选第二种是最合适的。
TriggerBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);

接下来设置的就是下图所展示的部分,
设置当前Mesh的对象类型(用于区别场景的Mesh类型,以便进行不同的碰撞响应)。
TriggerBox->SetCollisionObjectType(ECollisionChannel::ECC_WorldStatic);

我们只需要对人物做出反应,其他的不用考虑,所以先将所有通道都设置为忽略状态,再单独设置响应pawn类的重叠。

TriggerBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
TriggerBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap); 


设置盒子的大小:TriggerBox->SetBoxExtent(FVector(64, 64, 32));

  • 门开关的初始化
    创建门开关的实例,附在根组件上。
FloorSwitch = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("FloorSwitch"));
FloorSwitch->SetupAttachment(RootComponent);
  • 门的初始化

创建门的实例,附在根组件上。

Door = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door"));
Door->SetupAttachment(RootComponent);
  • 设置人离开开关后们停留的时间

SwitchTime = 2;

<BeginPlay()>
获得门和门开关的初始位置

InitialDoorLocation = Door->GetComponentLocation();
InitialSwitchLocation = FloorSwitch->GetComponentLocation();

将开关盒子与角色的重叠情况进行绑定

TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AAFloorSwitch::OnOverlapBegin);
TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AAFloorSwitch::OnOverlapEnd);

<OnOverlapBegin自定义函数实现>
在开始重叠的时候,我们要把我们的时间手柄置为空,让门升起来,开关降下去。

GetWorldTimerManager().ClearTimer(TimerHandle);
RaiseDoor();
LowerFloorSwitch();

<OnOverlapEnd自定义函数实现>
GetWorldTimerManager().SetTimer(TimerHandle, this, &AAFloorSwitch::CloseDoor, SwitchTime);
设置时间,SwitchTime秒后执行关门操作。

<CloseDoor函数实现>
门降下去,开关升起来。

LowerDoor();
RaiseFloorSwitch();

<UpdateDoorLocation函数实现>
更新门的位置

FVector NewLocation = InitialDoorLocation;
NewLocation.Z += Z;
Door->SetWorldLocation(NewLocation);

<UpdateSwitchLocation更新门开关的位置>

FVector NewLocation = InitialSwitchLocation;
NewLocation.Z += Z;
FloorSwitch->SetWorldLocation(NewLocation);

创建蓝图

右键我们刚创建的C++类,创建蓝图。
给我们的组件挑选Mesh:


以上是关于UE4 C++实现自动门的主要内容,如果未能解决你的问题,请参考以下文章

UE4蓝图与C++交互——射击游戏中多武器系统的实现

UE4 Unlua源码解析8 - Lua与C++之间的参数转换的实现原理

UE4 Unlua源码解析8 - Lua与C++之间的参数转换的实现原理

基于C++代码的UE4学习—— 自定义代理结合Timer实现道具的消失与重生

UE4 C++入门之路5-热重载Compile(编译项目的三种方式)

UE4 C++入门之路5-热重载Compile(编译项目的三种方式)