카테고리 없음

25.01.24 움직이는 actor(엘레베이터) 구현

alwaysyoung2 2025. 1. 24. 20:47
728x90
반응형

 

오늘은 움직이는 actor를 구현하였습니다.회전하는 actor는 알고있었으니 넘어가고

옆이나 위아래로 이동하는 구현

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

// 이 클래스는 특정 위치 사이를 왕복 운동하는 발판을 구현합니다.
UCLASS()
class QUIXEL_API AMoveUpDownRock : public AActor
{
	GENERATED_BODY()
	
public:	
	// 생성자: 이 액터의 기본값을 설정합니다.
	AMoveUpDownRock();

protected:
	// 발판의 루트 컴포넌트 (모든 컴포넌트의 기준점)
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MoveUpDownRock|Component")
	USceneComponent* SceneRoot;

	// 발판의 시각적 표현 (Static Mesh)
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "MoveUpDownRock|Component")
	UStaticMeshComponent* StaticMeshComp;

	// 발판의 시작 위치 (로컬 좌표 또는 월드 좌표)
	UPROPERTY(EditAnywhere, Category = "Movement")
	FVector StartLocation;

	// 발판의 목표 위치 (시작 위치에서 상대적 위치 또는 월드 좌표)
	UPROPERTY(EditAnywhere, Category = "Movement")
	FVector TargetLocation;

	// 발판의 이동 속도 (초당 거리)
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "MoveUpDownRock|Properties")
	float MoveSpeed;

	// 월드 좌표로 변환된 시작 위치
	FVector GlobalStartLocation;

	// 월드 좌표로 변환된 목표 위치
	FVector GlobalTargetLocation;

	// 게임이 시작되거나 액터가 스폰될 때 호출됩니다.
	virtual void BeginPlay() override;

	// 매 프레임마다 호출됩니다. 발판의 위치를 업데이트합니다.
	virtual void Tick(float DeltaTime) override;
};

해당 헤더파일에 한줄 한줄 설명을 달아 설명해보았습니다.

 

다음으로 cpp구현파일입니다.

// Fill out your copyright notice in the Description page of Project Settings.

#include "MoveUpDownRock.h"

// Sets default values
AMoveUpDownRock::AMoveUpDownRock()
{
 	// 이 액터가 매 프레임마다 Tick() 함수를 호출하도록 설정합니다.
	// 필요하지 않을 경우 false로 설정해 성능을 최적화할 수 있습니다.
	PrimaryActorTick.bCanEverTick = true;

	// 루트 컴포넌트 생성 (SceneRoot)
	SceneRoot = CreateDefaultSubobject<USceneComponent>(TEXT("ScneRoot"));
	SetRootComponent(SceneRoot); // SceneRoot를 루트 컴포넌트로 설정

	// StaticMesh 컴포넌트를 생성하고 루트 컴포넌트(SceneRoot)에 부착
	StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
	StaticMeshComp->SetupAttachment(SceneRoot);

	// 발판의 기본 이동 속도 설정
	MoveSpeed = 200.0f; // 초당 200 유닛
}

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

	// GlobalStartLocation: 액터의 현재 월드 위치를 시작 위치로 설정
	GlobalStartLocation = GetActorLocation();

	// GlobalTargetLocation: 시작 위치에서 TargetLocation 값을 더한 월드 좌표
	GlobalTargetLocation = GetActorLocation() + TargetLocation;
}

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

	// 현재 위치를 가져옵니다.
	FVector CurrentLocation = GetActorLocation();

	// 이동할 총 거리(시작 위치와 목표 위치 간의 거리)
	float JourneyLength = (GlobalTargetLocation - GlobalStartLocation).Size();

	// 현재 이동한 거리(시작 위치와 현재 위치 간의 거리)
	float JourneyTravelled = (CurrentLocation - GlobalStartLocation).Size();

	// 목표 위치에 도달했을 경우 방향을 바꿉니다.
	if (JourneyTravelled >= JourneyLength)
	{
		// 시작 위치와 목표 위치를 교체하여 방향 전환
		FVector Temp = GlobalStartLocation;
		GlobalStartLocation = GlobalTargetLocation;
		GlobalTargetLocation = Temp;
	}

	// 방향 벡터를 계산하여 정상화(길이가 1인 벡터로 변환)
	FVector Direction = (GlobalTargetLocation - GlobalStartLocation).GetSafeNormal();

	// 새로운 위치 계산: 현재 위치에 이동 속도와 DeltaTime을 곱한 방향 벡터를 더함
	FVector NewLocation = CurrentLocation + Direction * MoveSpeed * DeltaTime;

	// 액터의 위치를 업데이트
	SetActorLocation(NewLocation);
}

똑같이 줄마다 설명을 적어놨습니다.

 

이번 코드 작성을 위해 학습한 중요개념들을 정리해보자면

 

 컴포넌트와 액터

USceneComponent와 UStaticMeshComponent

  • SceneRoot와 StaticMeshComp는 컴포넌트입니다. 액터를 구성하는 부분적인 요소로, 각각 다음을 담당합니다:
    • USceneComponent: 액터의 기준점(위치, 회전, 크기).
    • UStaticMeshComponent: 시각적 표현을 담당하는 Static Mesh.

SetRootComponent()와 SetupAttachment()

  • SetRootComponent(SceneRoot):
    • 액터의 최상위 컴포넌트를 설정. 모든 컴포넌트는 이 컴포넌트에 상대적으로 배치됩니다.
  • StaticMeshComp->SetupAttachment(SceneRoot):
    • Static Mesh를 SceneRoot에 붙여서 함께 움직이도록 설정.

Transform

위치 계산

  • SetActorLocation(NewLocation):
    • 액터의 월드 위치를 업데이트합니다.
  • GetActorLocation():
    • 액터의 현재 월드 좌표를 반환합니다.

방향 벡터와 거리 계산


FVector Direction = (GlobalTargetLocation - GlobalStartLocation).GetSafeNormal();
  • Direction은 목표 위치를 향하는 방향을 나타내는 단위 벡터(길이가 1인 벡터).
  • GetSafeNormal()을 사용해 벡터를 정상화하여 이동 속도와 곱할 때 값이 왜곡되지 않도록 합니다.
 
float JourneyLength = (GlobalTargetLocation - GlobalStartLocation).Size();
  • Size()는 두 점 사이의 거리를 계산합니다.
  • 이 값은 발판이 목표 위치에 도달했는지 확인하는 데 사용됩니다.

코드를 설정한 뒤에 리플랙션을 활용하였기에 이동해야하는 벡터만 변경해주면 위아래로 이동하는 발판과 동시에 옆으로 이동하는 발판도 생성가능합니다.

 

주기적으로 발판이 사라지는 발판구현

 

헤더파일은 전과 크게 다른건 없고 추가된 변수선언정도만 있으므로 따로 설명과 기재하진 않고 바로 구현 파일로 넘어가겠습니다.

// Fill out your copyright notice in the Description page of Project Settings.

#include "DisapearRock.h"

// Sets default values
ADisapearRock::ADisapearRock()
{
 	// 이 액터가 매 프레임마다 Tick()을 호출하지 않도록 설정 (성능 최적화)
	PrimaryActorTick.bCanEverTick = false;

	// Static Mesh 컴포넌트를 생성하고, 이름을 "Platfor"로 지정
	StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Platfor"));
	SetRootComponent(StaticMesh); // StaticMesh를 루트 컴포넌트로 설정

	// 발판이 사라지는 시간 간격을 기본값으로 설정 (5초)
	Interval = 5.0f;

	// 발판의 초기 상태를 보이도록 설정
	bIsVisible = true;
}

// Called when the game starts or when spawned
void ADisapearRock::BeginPlay()
{
	Super::BeginPlay(); // 부모 클래스의 BeginPlay를 호출하여 초기화

	// 타이머를 시작하여 일정 간격마다 TogglePlatformVisibility 함수를 호출
	GetWorld()->GetTimerManager().SetTimer(
		TimerHandle, // 타이머 핸들
		this,        // 이 액터를 컨텍스트로 지정
		&ADisapearRock::TogglePlatformVisibility, // 호출할 함수
		Interval,    // 호출 간격 (초 단위)
		true         // 반복 실행 (루프 활성화)
	);
}

// Toggles the platform's visibility
void ADisapearRock::TogglePlatformVisibility()
{
	// 현재 상태에 따라 발판의 가시성과 충돌을 전환
	if (bIsVisible)
	{
		// 발판을 숨기고 충돌을 비활성화
		StaticMesh->SetVisibility(false, true); // SetVisibility: 두 번째 인자는 "propagate to children" 옵션
		StaticMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 충돌 비활성화
	}
	else
	{
		// 발판을 표시하고 충돌을 활성화
		StaticMesh->SetVisibility(true, true); // 발판을 다시 표시
		StaticMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); // 충돌 활성화
	}

	// 발판의 상태를 반전
	bIsVisible = !bIsVisible; // true ↔ false 전환
}

사용된 중요개념

타이머 시스템 (Timer System)

SetTimer와 FTimerHandle

  • 타이머란?
    • 언리얼 엔진에서 특정 작업을 일정 시간 후 또는 일정 간격마다 반복적으로 실행할 수 있도록 도와주는 시스템입니다.
  • SetTimer 사용법:
    • GetWorld()->GetTimerManager().SetTimer(...)를 사용하여 타이머를 설정.
    • 주어진 간격(초 단위)마다 특정 함수를 호출.
  • FTimerHandle:
    • 타이머를 제어(정지, 재시작)할 때 사용되는 핸들입니다.

가시성 제어 (SetVisibility)

  • SetVisibility(bool bVisible, bool bPropagateToChildren):
    • 액터가 화면에 표시되는지 여부를 제어.
    • bPropagateToChildren을 true로 설정하면 하위 컴포넌트에도 영향을 줌.

충돌 상태 (SetCollisionEnabled)

  • ECollisionEnabled::NoCollision:
    • 충돌 비활성화. 다른 객체와의 상호작용이 없음.
  • ECollisionEnabled::QueryAndPhysics:
    • 충돌과 물리 계산을 활성화하여 다른 객체와 상호작용 가능.

논리형 변수로 상태 관리 (bIsVisible)

  • bIsVisible:
    • 현재 발판의 가시 상태를 추적하는 변수.
    • 이 변수를 토글(반전)하여 발판이 보이는 상태와 숨겨진 상태를 전환.
  • 상태 관리의 흐름:
    • bIsVisible == true → 발판을 숨김.
    • bIsVisible == false → 발판을 표시.

 

728x90
반응형