도로 위 한 점 → 다음 점으로 이동시키기

  1. 지금 차가 도로의 어디쯤 있는지 
  2. 그 위치의 월드 좌표가 어디인지

알아야 함

 

USplineComponent::GetLocationAtDistanceAlongSpline 공식 문서

FVector GetLocationAtDistanceAlongSpline(
    float Distance,
    ESplineCoordinateSpace::Type CoordinateSpace
) const;

 

스플라인 시작점부터 Distance(거리)만큼 떨어진 곳의 위치를 반환한다

 

이러면 도로 위 위치를 거리(Distance) 하나로 표현할 수 있음

  • Distance = 0 → 시작점
  • Distance = 100 → 100cm 진행
  • Distance = SplineLength → 끝점

언리얼 좌표계 정리:

  • 인덱스 기반: 점 0, 점 1, 점 2... (불연속)
  • 거리 기반: 0cm, 50cm, 137cm... (연속) ← 이게 더 좋아 보임

거리 기반이 좋은 이유:

  • 차량이 점과 점 사이에 있을 때도 표현 가능
  • 곡선 보간을 직접 안 해도 됨 (보간: 두 점(또는 두 값) 사이의 중간 값을 비율에 따라 계산해서 자연스럽게 채워 넣는 것)
  • 한 변수만으로 전체 진행도 추적 가능
// SplineFollowerComponent.h
private:
    /* 도로 시작점부터 차량 현재 위치까지의 거리 (cm) */
    float CurrentDistance = 0.f;

 

어떤 변수를 클래스에 둬야 하지?가 헷갈렸는데, "매 프레임 유지되어야 하는 상태값"이 멤버 변수라는 걸 이해함. 함수 안의 지역 변수는 매번 사라지니까.


일단 단순하게 물리는 신경 안 쓰고, 차의 위치를 매 프레임 도로 위로 점프시켜보기.

 

void TickComponent(float DeltaTime, ...)
{
    // 1. 진행도를 조금씩 늘림 (1초에 1000cm = 10m/s 속도로)
    CurrentDistance += DeltaTime * 1000.f;

    // 2. 그 거리에 해당하는 도로 위 위치 가져오기
    USplineComponent* Spline = TargetRoad->GetSplineComponent();
    FVector NewLocation = Spline->GetLocationAtDistanceAlongSpline(
        CurrentDistance,
        ESplineCoordinateSpace::World
    );

    // 3. 차 위치를 거기로 강제 설정
    OwnerPawn->SetActorLocation(NewLocation);
}

 

문제점: 

 

  • 차가 옆을 보고 있다 (회전이 안 됨)
  • 도로 끝에 도달하면 계속 직선으로 날아감

 

문제 1 해결: 차의 방향 도로에 맞추기

GetDirectionAtDistanceAlongSpline 문서

FVector GetDirectionAtDistanceAlongSpline(
    float Distance,
    ESplineCoordinateSpace::Type CoordinateSpace
) const;

 

위치뿐 아니라 그 지점에서의 진행 방향도 가져올 수 있다

FVector NewDirection = Spline->GetDirectionAtDistanceAlongSpline(...);

 

회전 맞추기 FVector::Rotation() 공식 문서

 
 
FRotator NewRotation = NewDirection.Rotation();
OwnerPawn->SetActorRotation(NewRotation);

 

벡터를 그냥 .Rotation() 하면 회전값이 나온다.

이제 차가 도로 방향을 바라보면서 움직인다

 

 

문제 2 해결: 도로 끝 도달 처리

// 도로 전체 길이 가져오기
float TotalLength = Spline->GetSplineLength();

if (CurrentDistance >= TotalLength)
{
    // 끝 도달! 어떻게 처리하지?
    // 옵션 A: 처음으로 돌아가기 (순환)
    // 옵션 B: 멈추기
    // 옵션 C: 그대로 두기
}

 

순환 도로(트랙 같은 거)는 옵션 A, 일반 도로는 옵션 B가 자연스러울듯

IsClosedLoop() 함수

if (Spline->IsClosedLoop())
{
    // 순환: Distance를 도로 길이로 나눈 나머지 사용
    CurrentDistance = FMath::Fmod(CurrentDistance, TotalLength);
}
else if (CurrentDistance >= TotalLength - 100.f)  // 100cm 남으면 끝났다고 판단
{
    // 일반: 멈추기
    return;
}

 

FMath::Fmod는 실수형 나머지 연산. 정수형 % 연산자랑 비슷.

 

  • 누적 거리가 1000m가 되었을 때: 1000 나누기 1000의 나머지 = 0m (다시 출발선!)
  • 누적 거리가 1050m가 되었을 때: 1050 나누기 1000의 나머지 = 50m (두 번째 바퀴의 50m 지점)
  • 누적 거리가 2300m가 되었을 때: 2300 나누기 1000의 나머지 = 300m (세 번째 바퀴의 300m 지점)

이런 느낌

 

 


USplineComponent 함수들

GetLocationAtDistanceAlongSpline 거리 → 월드 위치 링크
GetDirectionAtDistanceAlongSpline 거리 → 진행 방향 링크
GetSplineLength 도로 전체 길이 링크
IsClosedLoop 순환 도로 여부 링크

FMath / FVector 함수들

FMath::Fmod 실수형 나머지 연산 (순환 처리)
FVector::Rotation() 방향 벡터 → FRotator 변환

 

함수 이름 해석법

GetLocationAtDistanceAlongSpline 

-> 도로를 따라(AlongSpline) 거리(Distance)에서의 위치(Location)를 가져온다(Get)

 

+ Recent posts