任务:在场景中做一个开关门,角色踩上开关后,门打开,离开开关2s后门自动关闭
第一步、新建一个C++ Actor类命名为DoorSwitch,并编写相应代码
DoorSwitch.h代码如下:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components\PrimitiveComponent.h"
#include "DoorSwitch.generated.h"
UCLASS()
class LEARNTEST_API ADoorSwitch : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ADoorSwitch();
//Door的静态网格体
UPROPERTY(EditAnywhere)
class UStaticMeshComponent* DoorStaticMesh;
//Switch的静态网格体
UPROPERTY(EditAnywhere)
class UStaticMeshComponent* SwitchStaticMesh;
//触发器组件
UPROPERTY(EditAnywhere)
class UBoxComponent* TriggerBox;
//用于储存Door初始化位置的向量
UPROPERTY(VisibleAnywhere)
FVector DoorInitLocation;
//用于储存Switch初始位置的向量
UPROPERTY(VisibleAnywhere)
FVector SwitchInitLocation;
//用于储存关门延迟时间延迟时间的向量
UPROPERTY(EditAnywhere,Category = "Switch Variates")
float WaitTime;
//定时器句柄,开启和关闭定时器时需要使用该参数
FTimerHandle TimerHandle;
//关门函数,在定时器中调用
UFUNCTION()
void CloseDoor();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//进入触发器时执行函数
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);
//开门函数,蓝图中实现
UFUNCTION(BlueprintImplementableEvent)
void DoorUp();
//关门函数,蓝图中实现
UFUNCTION(BlueprintImplementableEvent)
void DoorDown();
//开关上升函数,蓝图中实现
UFUNCTION(BlueprintImplementableEvent)
void SwitchUp();
//开关下降函数,蓝图中实现
UFUNCTION(BlueprintImplementableEvent)
void SwitchDown();
//更新Door位置的函数,可在蓝图中调用
UFUNCTION(BlueprintCallable)
void UpdataDoorLocation(float Value);
//更新Switch位置的函数,可在蓝图中调用
UFUNCTION(BlueprintCallable)
void UpdataSwitchLocation(float Value);
};
DoorSwitch.cpp代码如下:
#include "DoorSwitch.h"
#include "Components\BoxComponent.h"
#include "Engine\Public\TimerManager.h"
// Sets default values
ADoorSwitch::ADoorSwitch()
{
// 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;
//创建门的静态网格体,并将其附着在根组件上
DoorStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorStaticMesh"));
DoorStaticMesh->SetupAttachment(RootComponent);
//创建开关的静态网格体,并将其附着在根组件上
SwitchStaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SwitchStaticMesh"));
SwitchStaticMesh->SetupAttachment(RootComponent);
//创建触发器静态网格体,并将其设置为根组件
TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox"));
RootComponent = TriggerBox;
//触发器相关碰撞预设,只对Pawn类型进行碰撞检测,其他的忽略
TriggerBox->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
TriggerBox->SetCollisionObjectType(ECollisionChannel::ECC_WorldStatic);
TriggerBox->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
TriggerBox->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn,ECollisionResponse::ECR_Overlap);
//初始化关门延迟时间
WaitTime = 2;
}
//关门函数,在定时器中调用
void ADoorSwitch::CloseDoor()
{
//这两个函数在蓝图中,利用时间轴实现
DoorDown();
SwitchUp();
}
//更新Door的位置,蓝图中调用
void ADoorSwitch::UpdataDoorLocation(float Value)
{
FVector NewLocation = DoorInitLocation;
NewLocation.Z += Value;
DoorStaticMesh->SetWorldLocation(NewLocation);
}
//更新Switch的位置,蓝图中调用
void ADoorSwitch::UpdataSwitchLocation(float Value)
{
FVector NewLocation = SwitchInitLocation;
NewLocation.Z += Value;
SwitchStaticMesh->SetWorldLocation(NewLocation);
}
// Called when the game starts or when spawned
void ADoorSwitch::BeginPlay()
{
Super::BeginPlay();
//游戏开始时,获取初始的Door和Switch的位置
DoorInitLocation = DoorStaticMesh->GetComponentLocation();
SwitchInitLocation = SwitchStaticMesh->GetComponentLocation();
//触发器绑定相应事件
TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &ADoorSwitch::OnOverlapBegin);
TriggerBox->OnComponentEndOverlap.AddDynamic(this, &ADoorSwitch::OnOverlapEnd);
}
// Called every frame
void ADoorSwitch::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
//进入触发区域(开关位置)时执行函数
void ADoorSwitch::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
UE_LOG(LogTemp, Warning, TEXT("SwitchON"));
//关定时器
GetWorldTimerManager().ClearTimer(TimerHandle);
//关门
DoorUp();
SwitchDown();
}
//离开触发区域(开关位置)时执行函数
void ADoorSwitch::OnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
UE_LOG(LogTemp, Warning, TEXT("SwitchOFF"));
//开启定时器,延时后触发CloseDoor函数
GetWorldTimerManager().SetTimer(TimerHandle, this, &ADoorSwitch::CloseDoor,WaitTime);
}
第二步、以DoorSwitch C++类为父类建立蓝图类,在该蓝图类中设置门和开关的静态网格体,并且利用时间轴实现开门,关门函数
1、设置门和开关的静态网格体
2、利用时间轴实现开门,关门函数