[ UE5 C++ ] 구간 이동 플랫폼 만들기 (Local → World 좌표 변환)

LeeTaes·2024년 3월 10일

UE5_기능구현

목록 보기
2/2

구간 이동 플랫폼 만들기

  • 출발지 - 목적지를 순회하는 플랫폼 만들기 실습
  • 타겟 위치를 에디터에서 편리하게 설정하는 방법
  • Local → World 좌표 변환 방법

  1. 움직이는 액터 만들기
  • 움직이는 액터를 만들기 위해 Actor를 부모로 하는 C++ 클래스 생성하기

  1. 목적지를 Editor에서 편하게 설정하도록 변수 선언 및 설정하기
  • 언리얼의 위치 좌표는 FVector에 저장 가능합니다.
  • UPROPERTY()에 meta = (MakeEditWidget = true) 키워드를 추가해 기즈모를 생성 가능합니다.
private:
	UPROPERTY(EditAnywhere, Category = "Option", meta = (AllowPrivateAccess = "true"), meta = (MakeEditWidget = true))
	FVector TargetLocation;
  • 위 클래스를 부모로 하는 블루프린트 클래스를 생성 후 눈에 보이도록 간단한 메시 추가하기 (ex. 큐브 등)
  • BP를 월드에 배치하기
  • 위와 같이 TargetLocation의 기즈모가 생성되어 Viewport 상에서 세밀하게 목적지 설정이 가능합니다.

  1. 이동 로직 만들기
  • 출발지에서 목적지로 이동한다는 것은 벡터로 표현이 가능합니다.
    → 목적 위치(벡터) - 출발 위치(벡터)

  • 속도를 저장할 변수를 선언합니다.

private:
	UPROPERTY(EditAnywhere, Category = "Option", meta = (AllowPrivateAccess = "true"))
	int32 Speed;
  • 이동한다는 것은 매 프레임 현재 위치에서 속도만큼 이동한다는 것을 의미합니다.
    → 내 위치 = 현재위치 + 속도

  • 위와 같은 방법은 하나의 단점이 존재합니다.

  • 매 프레임마다 이동하므로 컴퓨터 성능에 따라 액터의 이동속도가 변할 수 있습니다.

  • 즉, 1초에 1프레임을 호출 가능한 성능의 컴퓨터와 1초에 10프레임을 호출 가능한 성능의 컴퓨터 간의 차이가 10배의 속도 차이로 이어진다는 것을 의미합니다.

  • 다음 프레임이 오기까지의 시간을 체크해 반영해줘야 합니다.
    내 위치 = 현재위치 + 속도 * DeltaTime

void AMovingPlatforms::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	
    // 현재 액터의 위치를 저장합니다.
    FVector Location = GetActorLocation();
    
    // 속도만큼 이동시켜줍니다.
    Location += Speed * DeltaTime;
    
    // 이동한 위치를 저장합니다.
    SetActorLocation(Location);
}

  1. 이동 방향 구하기
  • 위 코드에서는 목적지로 향하는 방향은 생각하지 않았습니다.
  • 이동 방향을 체크해 정확한 방향으로 이동해야 합니다.
    이동 방향 = (목적 위치 - 현재 위치)의 정규화
    → 언리얼에서는 GetSafeNormal() 함수로 정규화가 가능합니다.
  • 이동 방향을 체크했으므로 이동 로직을 수정합니다.
	// 방향 구하기
    FVector Direction = (TargetLocation - Location).GetSafeNormal();

	// 특정 방향으로 속도만큼 이동시켜줍니다.
 	Location += Direction * Speed * DeltaTime;
    
    // 이동한 위치를 저장합니다.
    SetActorLocation(Location);

현재 상황에서 실행해보면?

  • 액터는 타겟 위치를 넘어서서 이동합니다.
  • 타겟 위치는 액터에 포함되어 있습니다. (타겟 위치의 부모 : 액터)
  • 즉, 액터가 움직이면 포함된 자식(타겟 위치)도 같이 움직이기 때문에 타겟 위치가 계속 업데이트 되며 원하는 위치에서 종료되지 않습니다.

  1. 시작 위치와 종료 위치를 시작과 동시에 저장하고 반영하기
  • 우선 시작 위치와 종료 위치를 BeginPlay()에서 저장하고 사용하도록 해보겠습니다.
  • 시작 위치는 GetActorLocation() 함수로 쉽게 구할 수 있습니다.
  • 목적 위치는 TargetLocation이지만, 그대로 사용할 수 없습니다.
    → TargetLocation은 Local 좌표(액터 하위)이므로 World 좌표가 필요함
  • Local → World로 이동시키는 방법은 다음과 같습니다.
    Local * 월드 변환 행렬(Scale * Rotation * Translation) * 부모의 월드 변환 행렬(부모 존재 시)
  • 언리얼의 Transform은 여러 기능을 제공합니다.
    언리얼 Transform
// MovingPlatforms.h
private:
	FVector GlobalTargetLocation;
	FVector GlobalStartLocation;

// MovingPlatforms.cpp

void AMovingPlatforms::BeginPlay()
{
	Super::BeginPlay();
    
    // 시작 지점과 목표 지점(World) 설정
	GlobalStartLocation = GetActorLocation();
	GlobalTargetLocation = GetTransform().TransformPosition(TargetLocation);
}

void AMovingPlatforms::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	FVector Location = GetActorLocation();
    
    // 방향 설정
    FVector Direction = (GlobalTargetLocation - GlobalStartLocation).GetSafeNormal();

	Location += Direction * Speed * DeltaTime;
	SetActorLocation(Location);
}

  1. 구간 반복 이동 설정하기
  • 구간을 반복해서 이동한다는 것은 쉽게 목적지에 도달하면 목적지 좌표와 출발지 좌표를 교체해준다고 생각할 수 있습니다.
  • 목적지에 도달했는지를 알아보기 위한 방법은 다음과 같습니다.
    1. 현재 위치와 시작 위치 사이의 거리 구하기
    2. 목적 위치와 시작 위치 사이의 거리 구하기
    3. 2번의 결과보다 1번의 결과가 같거나 커진다면 목적지에 도착한 것
  • 언리얼에서는 벡터의 크기를 구하는 함수를 제공합니다.
    → Size() : 벡터의 크기 반환
  • 목적지에 도달했다면 출발지와 목적지의 위치를 교환해줍니다.
void AMovingPlatforms::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	FVector Location = GetActorLocation();

		// 거리를 구해 목적지를 지나간다면?
		if ((Location - GlobalStartLocation).Size() > (GlobalTargetLocation - GlobalStartLocation).Size())
		{
        	// 출발지, 목적지 교체
			FVector Temp = GlobalTargetLocation;
			GlobalTargetLocation = GlobalStartLocation;
			GlobalStartLocation = Temp;
		}
        
		// 방향 구하기
		FVector Direction = (GlobalTargetLocation - GlobalStartLocation).GetSafeNormal();

		// 해당 방향으로 이동시키기
		Location += Direction * Speed * DeltaTime;
		SetActorLocation(Location);

}

결과

profile
클라이언트 프로그래머 지망생

0개의 댓글