[C++] 간단한 엘리베이터 만들기

Woogle·2022년 9월 13일
0

언리얼 엔진 5

목록 보기
16/63
post-thumbnail

블루프린트 없이 100% C++ 코드로만 엘리베이터를 만들어보았다.

  • 지난번에 만든 C++ 문의 코드를 응용했다.
    https://velog.io/@woojoo0407/C-문-만들기

  • CapsuleCollision에 Overlap시 OnOverlapBegin과 OnOverlapEnd 함수를 바인딩했다.

  • Tick 함수에서 변수(bIsOverlaped, CurrentPlatformHeight, MaxPlatformHeight)를 체크해서 OpenDoor, CloseDoor 함수로 분기되게 만들었다.

  • RaisePlatform, LowerPlatform 함수에서 DeltaTime을 받아 문의 각도를 조절했다.


📄 헤더 파일

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/CapsuleComponent.h"
#include "Elevator.generated.h"

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Elevator")
	UStaticMeshComponent* Button;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Elevator")
	UStaticMeshComponent* Platform;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Elevator")
	UCapsuleComponent* CapsuleCollision;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Elevator")
	float MaxPlatformHeight = 500.f;

	bool bIsOverlaped = false;

	float CurrentPlatformHeight = 0.f;

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(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

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

	UFUNCTION()
	void RaisePlatform(float DeltaTime);

	UFUNCTION()
	void LowerPlatform(float DeltaTime);
};

📄 소스 파일

#include "Elevator.h"

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

	Platform = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Platform"));
	Platform->SetRelativeScale3D(FVector(3.f, 3.f, 3.f));
	RootComponent = Platform;

	CapsuleCollision = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleCollision"));
	CapsuleCollision->InitCapsuleSize(15.f, 30.0f);
	CapsuleCollision->SetupAttachment(RootComponent);

	Button = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Button"));
	Button->SetRelativeLocation(FVector(0.f, 0.f, 5.f));
	Button->SetRelativeScale3D(FVector(0.3f, 0.3f, 0.1f));
	Button->SetupAttachment(CapsuleCollision);

	static ConstructorHelpers::FObjectFinder<UStaticMesh>ButtonSM(TEXT("'/Game/LevelPrototyping/Meshes/SM_Cylinder.SM_Cylinder'"));
	if (ButtonSM.Succeeded())
	{
		Button->SetStaticMesh(ButtonSM.Object);
	}

	static ConstructorHelpers::FObjectFinder<UStaticMesh>PlatformSM(TEXT("'/Game/StarterContent/Architecture/SM_AssetPlatform.SM_AssetPlatform'"));
	if (PlatformSM.Succeeded())
	{
		Platform->SetStaticMesh(PlatformSM.Object);
	}
}

// Called when the game starts or when spawned
void AElevator::BeginPlay()
{
	Super::BeginPlay();
	
	CapsuleCollision->OnComponentBeginOverlap.AddDynamic(this, &AElevator::OnOverlapBegin);
	CapsuleCollision->OnComponentEndOverlap.AddDynamic(this, &AElevator::OnOverlapEnd);
}

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

	if (!bIsOverlaped && CurrentPlatformHeight == 0.f)
	{
		return;
	}
	else if (bIsOverlaped)
	{
		RaisePlatform(DeltaTime);
	}
	else
	{
		LowerPlatform(DeltaTime);
	}
}

void AElevator::OnOverlapBegin(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor != nullptr && OtherActor != this && OtherComp != nullptr)
	{
		UE_LOG(LogTemp, Warning, TEXT("Overlap Begin"));
		bIsOverlaped = true;
	}
}

void AElevator::OnOverlapEnd(class UPrimitiveComponent* OverlappedComp, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	if (OtherActor != nullptr && OtherActor != this && OtherComp != nullptr)
	{
		UE_LOG(LogTemp, Warning, TEXT("Overlap End"));
		bIsOverlaped = false;
	}
}

void AElevator::RaisePlatform(float DeltaTime)
{
	if (CurrentPlatformHeight <= MaxPlatformHeight)
	{
		FVector NewRocation = FVector(0.f, 0.f, DeltaTime * 100);
		Platform->AddRelativeLocation(NewRocation);
		CurrentPlatformHeight = Platform->GetRelativeLocation().Z;
	}
}

void AElevator::LowerPlatform(float DeltaTime)
{
	if (CurrentPlatformHeight >= 0.f)
	{
		FVector NewRocation = FVector(0.f, 0.f, -DeltaTime * 100);
		Platform->AddRelativeLocation(NewRocation);
		CurrentPlatformHeight = Platform->GetRelativeLocation().Z;
	}
}

개선할 부분

  • Overlap되는 물체가 플레이어인지 체크하는 부분이 구현되어있지 않다.
  • 플랫폼 움직임이 너무 빠르면 콜리전이 뚫릴 수 있다. 콜리전 컴포넌트를 추가해서 막을 필요성이 있다.
  • 필요시 스위치가 눌리는 움직임을 구현할 수 있다.

참고 자료

profile
노력하는 게임 개발자

0개의 댓글