본문 바로가기
언리얼엔진 개발/VR

[UnrealEngine5]버튼을 누르면 문 열고 닫기 C++ (2)

by yeni_0224 2023. 4. 24.
728x90
반응형

이제는 Trigger Box에 닿았을 때가 아니라 버튼을 눌렀을 때 문을 열고 닫을 수 있도록 할 것이다.

문을 열고 닫게 하는 Door Button Class를 만들어주었고, 문을 열고 닫도록 Delgate를 사용해서 Door에 문 열고 닫으라는 명령을 전달할 수 있도록 했다.

 

스테이지가 클리어 되었다는 정보를 Delegate로 받아온 상태, 이 상태에서 플레이어와 버튼이 닿았을 때 문을 열고 닫을 수 있도록 해주었다.

 

Overlap 함수를 호출하는건 BeginPlay에서 하는게 맞지만, 코드를 작성하다보니 Overlap을 호출해주는 함수를 따로 빼주었다. 물론 문제없이 호출도 잘 되고, 문도 잘 움직인다. 정돈이 필요한 상태..

Delegate 함수를 호출하는 것이 아직은 어색하지만 이렇게 또 한발자국 다가갈 수 있었다.

 

Door.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "DoorButton.generated.h"

DECLARE_DELEGATE(FOpenDoorDele)

UCLASS()
class SPACEESCAPE_API ADoorButton : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADoorButton();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

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

	UPROPERTY(EditDefaultsOnly, Category = "Door Button Settings")
	class UBoxComponent* boxComp;
	UPROPERTY(EditDefaultsOnly, Category = "Door Button Settings")
	class UStaticMeshComponent* buttonMesh;

	//손이 버튼에 닿으면 문이 열린다
	UFUNCTION()
	void OnHandOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
		UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void CheckClearStage();
	//문을 열어라 지시할것
	UFUNCTION()
	void ReportOpen();
	void NoReportOpen();

public:
	class ADoors* door;
	class AEscapePlayer* player;
	FOpenDoorDele openDoorDele;

};

Door.cpp

#include "DoorButton.h"

#include "EscapePlayer.h"
#include "Components/BoxComponent.h"
#include "RoomManager.h"
#include "EngineUtils.h"

// Sets default values
ADoorButton::ADoorButton()
{
 	// 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;

	boxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("boxComp"));
	SetRootComponent(boxComp);
	buttonMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("buttonMesh"));
	buttonMesh->SetupAttachment(RootComponent);
}

// Called when the game starts or when spawned
void ADoorButton::BeginPlay()
{
	Super::BeginPlay();
	
	for (TActorIterator<ARoomManager> it(GetWorld()); it; ++it)
	{
		ARoomManager* rm = *it;
		rm->stageClearDele.AddUFunction(this, FName("CheckClearStage"));
	}	
}

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

}

void ADoorButton::OnHandOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
	UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	player = Cast<AEscapePlayer>(OtherActor);
	player != nullptr ? ReportOpen() : NoReportOpen();
}

void ADoorButton::CheckClearStage()
{
	boxComp->OnComponentBeginOverlap.AddDynamic(this, &ADoorButton::OnHandOverlap);
	UE_LOG(LogTemp, Warning, TEXT("CheckClearStage"))
}

void ADoorButton::ReportOpen()
{	
	UE_LOG(LogTemp, Warning, TEXT("CheckClearStage : Puzzle Clear, Character and DoorButton"))
	openDoorDele.Execute();
}

void ADoorButton::NoReportOpen()
{
	UE_LOG(LogTemp, Warning, TEXT("NoReportOpen"))
	return;
}

DoorButton.h

#pragma once

#include "CoreMinimal.h"
#include "Components/TimelineComponent.h"
#include "GameFramework/Actor.h"
#include "Doors.generated.h"

class UCurveFloat;

UCLASS()
class SPACEESCAPE_API ADoors : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADoors();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

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

	/*퍼즐풀기를 완료하면 양 옆으로 열리는 문*/
	UPROPERTY(EditDefaultsOnly, Category = "Door Settings")
	class UStaticMeshComponent* doorMesh;

	UFUNCTION()
	void Open();
	UFUNCTION()
	void Close();

	//문 여는 충돌감지 진행중인가
	bool bIsOpenOverlaping = true;
	UFUNCTION()
	void ChangeDoorOverlaping();

	/*문의 부드러운 이동*/
	UFUNCTION()
	void TimeLineProgress(float val);

	FTimeline curveTimeline;
	UPROPERTY()
	FVector startPoint;
	UPROPERTY()
	FVector endPoint;
	UPROPERTY(EditDefaultsOnly, Category = "DoorTimeLine")
	float yOffset = 200;
	UPROPERTY(EditDefaultsOnly, Category = "DoorTimeLine")
	UCurveFloat* curveFloat;
	
	//문 최초 위치
	FVector initLoc;

};

DoorButton.cpp

#include "Doors.h"
#include "Components/TimelineComponent.h"
#include "DoorButton.h"
#include "EngineUtils.h"

// Sets default values
ADoors::ADoors()
{
 	// 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;

	this->RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	doorMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("doorMesh"));
	doorMesh->SetupAttachment(RootComponent);
	doorMesh->SetRelativeLocation(FVector(0, 0, 0));
	doorMesh->SetRelativeScale3D(FVector(1, 4.625f, 2.4f));
	initLoc = GetActorLocation();
}

// Called when the game starts or when spawned
void ADoors::BeginPlay()
{
	Super::BeginPlay();	

	for(TActorIterator<ADoorButton> it(GetWorld()); it; ++it)
	{
		ADoorButton* db = *it;
				
		db->openDoorDele.BindUFunction(this, FName("ChangeDoorOverlaping"));

		initLoc = GetActorLocation();
		if (curveFloat)
		{
			FOnTimelineFloat TimeLineProgress;
			TimeLineProgress.BindUFunction(this, FName("TimeLineProgress"));
			curveTimeline.AddInterpFloat(curveFloat, TimeLineProgress);
		}
	}	
}

// Called every frame
void ADoors::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	curveTimeline.TickTimeline(DeltaTime);
}

void ADoors::ChangeDoorOverlaping()
{
	bIsOpenOverlaping == true ? Open() : Close();
}

void ADoors::Open()
{
	startPoint = GetActorLocation();
	endPoint = startPoint + FVector(0, yOffset, 0);
	curveTimeline.PlayFromStart();
	UE_LOG(LogTemp, Warning, TEXT("Overlapped : Open Door"))
	bIsOpenOverlaping = false;
}

void ADoors::Close()
{
	if (bIsOpenOverlaping == true) return;
	startPoint = GetActorLocation();	
	endPoint = initLoc;
	curveTimeline.PlayFromStart();
	bIsOpenOverlaping = true;
	UE_LOG(LogTemp, Warning, TEXT("EndOverlapped : Close Door"))
}

void ADoors::TimeLineProgress(float val)
{
	FVector newLoc = FMath::Lerp(startPoint, endPoint, val);
	SetActorLocation(newLoc);	
}

아직 구현이 완성된 것은 아니다.

문이 열고 닫히기 위한 조건들이 아직 남아있기 때문이다. 허허...

 

Delegate 어렵다

Delegate에 대해 알 수 있는 좋은 블로그를 하나 남겨두며 20000

https://darkcatgame.tistory.com/66

 

UE4 C++ Delegate 정리 & 샘플 프로젝트

개인적으로 UE4 C++에서 Delegate를 사용할 때 처음에 굉장히 에러를 많이 겪었습니다, 그래서 이번 포스팅은 UE4 C++에서 Delegate를 사용하는 방법에 대해 정리하고 샘플프로젝트도 만들었습니다. https

darkcatgame.tistory.com

 

728x90
반응형