컨베이어 벨트를 설치할 때 보이는 고스트 프리뷰에 방향 화살표를 추가하고, 이 화살표가 실제 설치 후 컨베이어의 흐름 방향과 일치하도록 수정했다.

기존에는 컨베이어를 설치하기 전에 고스트 프리뷰만 보고는 아이템이 어느 방향으로 흐를지 알기 어려웠다. 특히 컨베이어 벨트는 주변 벨트나 설비와 이어질 때 자동으로 흐름 방향이 바뀌기 때문에, 단순히 현재 회전 방향만 표시하는 방식으로는 실제 설치 결과와 프리뷰가 달라질 수 있었다.


기존 문제

처음에는 컨베이어 고스트 프리뷰에 화살표를 표시하는 방식만 생각했다.
현재 설치하려는 건물이 컨베이어라면 화살표를 보이고, 컨베이어가 아니라면 숨기는 구조였다.

if (bIsConveyorPreview)
{
    CurrentPreviewActor->ShowDirectionArrow();
}
else
{
    CurrentPreviewActor->HideDirectionArrow();
}

이 방식은 “컨베이어일 때 화살표를 보여준다”는 목적은 달성할 수 있었다.
하지만 실제 컨베이어는 설치 후 주변 벨트나 설비를 보고 흐름 방향을 자동으로 결정한다.

Belt->ApplyPlacementFlow(bCornerFlipPlacement);

즉, 프리뷰 화살표는 기본 방향을 가리키고 있는데, 실제 설치 후에는 주변 연결 상태에 따라 흐름 방향이 달라질 수 있었다.
플레이어 입장에서는 프리뷰에서 본 방향과 설치 후 실제 방향이 다르게 느껴질 수 있는 문제가 있었다.


방향 추론 로직 분리

기존 방향 추론 로직은 AKOConveyorBelt 내부에 있었다.
하지만 고스트 프리뷰는 실제 컨베이어 Actor가 아니라 AKOGhostPreview이기 때문에, 컨베이어의 멤버 함수를 그대로 사용하는 구조는 적절하지 않았다.

그래서 방향 추론 로직을 별도의 공용 Resolver로 분리했다.

FKOConveyorFlowResolver::TryResolveStraightReverse(...)
FKOConveyorFlowResolver::TryResolveCornerFlip(...)

이제 실제 컨베이어와 고스트 프리뷰가 같은 방향 계산 로직을 사용할 수 있다.

실제 컨베이어
→ 설치된 위치와 회전을 기준으로 Resolver 호출

고스트 프리뷰
→ 설치 예정 위치와 회전을 기준으로 Resolver 호출

이 구조로 바꾸면 프리뷰와 실제 설치 결과가 서로 다른 기준으로 방향을 계산하는 문제를 줄일 수 있다.


이웃 셀 역할 판정

방향을 자동으로 추론하려면 먼저 주변 셀에 있는 Actor가 어떤 역할인지 판단해야 한다.

+1 : 업스트림
     나에게 아이템을 보내는 쪽

-1 : 다운스트림
     내가 아이템을 보내야 하는 쪽

 0 : 모호함
     방향을 결정할 수 없는 상태

이웃이 컨베이어라면 해당 벨트가 현재 셀을 향해 출력하는지, 또는 현재 셀에서 입력받는지를 검사한다.

if (Belt->OutputsToCell(MyCell)) return +1;

if (Belt->InputsFromCell(MyCell)) return -1;

이웃이 설비라면 Source/Sink 여부를 기준으로 판단한다.

if (bHasSource && !bHasSink) return +1;

if (bHasSink && !bHasSource) return -1;

출력만 가능한 설비는 현재 컨베이어에게 아이템을 공급하는 쪽이므로 업스트림으로 본다.
반대로 입력만 가능한 설비는 현재 컨베이어가 아이템을 보내야 하는 쪽이므로 다운스트림으로 본다.


직선 컨베이어 방향 계산

직선 컨베이어는 기본적으로 현재 Forward 방향으로 흐른다.
하지만 주변 연결에 따라 반대로 흘러야 할 수도 있다.

const bool bWantForward = (RoleBack > 0) || (RoleFront < 0);
const bool bWantReverse = (RoleFront > 0) || (RoleBack < 0);

뒤쪽이 업스트림이거나 앞쪽이 다운스트림이면 현재 방향 그대로 흐르는 것이 자연스럽다.
반대로 앞쪽이 업스트림이거나 뒤쪽이 다운스트림이면 역방향으로 흐르는 것이 맞다.

자동 추론이 성공하면 그 결과를 사용하고, 실패하면 기본 방향을 유지한다.

const bool bFinalReverse = bResolved ? bResolvedReverse : false;

따라서 직선 컨베이어의 화살표는 다음처럼 결정된다.

reverse=false → 0도
reverse=true  → 180도

L자 컨베이어 방향 계산

L자 컨베이어는 직선 컨베이어처럼 단순히 180도 반전되는 구조가 아니다.
두 다리 중 어느 쪽이 입구이고 어느 쪽이 출구인지가 바뀐다.

const bool bWantFalse = (RoleB > 0) || (RoleA < 0);
const bool bWantTrue = (RoleA > 0) || (RoleB < 0);

flip = false일 때는 Side 쪽에서 들어와 Forward 쪽으로 나간다.
반대로 flip = true일 때는 Forward 쪽에서 들어와 Side 쪽으로 나간다.

자동 추론에 성공하면 그 값을 사용하고, 추론할 수 없다면 기존 수동 flip 값을 사용한다.

const bool bFinalFlip = bResolved ? bResolvedFlip : bCornerFlipPlacement;

L자 컨베이어의 화살표는 출구 방향에 맞춰 다음처럼 결정된다.

flip = false → 0도
flip = true  → 90도

고스트 프리뷰 화살표 회전 적용

고스트 프리뷰의 화살표 함수는 추가 회전값을 받을 수 있게 수정했다.

FRotator FinalRotation = DirectionArrowRelativeRotation;
FinalRotation.Yaw += AdditionalYaw;

DirectionArrowComponent->SetRelativeRotation(FinalRotation);

기본 화살표 회전값에 AdditionalYaw를 더해 최종 방향을 결정한다.

AdditionalYaw = 0도   → 기본 방향
AdditionalYaw = 90도  → L자 벨트의 Side 방향
AdditionalYaw = 180도 → 직선 벨트의 역방향

프리뷰에서 예상 방향 계산

고스트 프리뷰에서는 현재 설치 예정 셀과 회전값을 기준으로 방향을 계산한다.

const FIntPoint MyCell = CurrentAnchor;
const FIntPoint Forward = GetPreviewForwardStep();
const FIntPoint Side = GetPreviewSideStep();

그 후 컨베이어 형태에 따라 다른 방식으로 화살표 회전값을 반환한다.

if (BeltCDO->GetShape() == EKOBeltShape::Corner)
{
    return bFinalFlip ? 90.0f : 0.0f;
}

return bFinalReverse ? 180.0f : 0.0f;

직선 컨베이어는 reverse 여부에 따라 0도 또는 180도를 반환하고, L자 컨베이어는 flip 여부에 따라 0도 또는 90도를 반환한다.


실제 컨베이어와 프리뷰의 계산 기준 통일

실제 컨베이어와 고스트 프리뷰가 같은 Resolver를 사용하도록 만들었다.

실제 설치 방향 결정
= FKOConveyorFlowResolver

프리뷰 화살표 방향 결정
= FKOConveyorFlowResolver

실제 컨베이어는 설치된 Actor의 위치와 회전을 기준으로 Resolver를 호출한다.
고스트 프리뷰는 설치 예정 셀과 현재 회전값을 기준으로 Resolver를 호출한다.

계산 기준이 같아졌기 때문에, 고스트 프리뷰에서 본 화살표 방향과 실제 설치 후 흐름 방향이 일치하게 된다.


정리

기존에는 컨베이어 고스트 프리뷰가 단순히 현재 회전 방향만 보여줬기 때문에, 주변 벨트와 이어지는 경우 실제 설치 후 방향이 달라질 수 있었다.

수정 후에는 주변 벨트와 설비의 연결 상태를 프리뷰 단계에서 미리 반영되도록 하였다.

실제 컨베이어와 고스트 프리뷰가 같은 흐름 추론 로직을 사용하게 하여, 프리뷰 화살표가 설치 후 실제 흐름 방향과 일치하도록 개선하였다.

 

결과적으로 컨베이어 라인을 이어 붙일 때 설치 방향을 더 직관적으로 확인할 수 있게 되었고, 잘못된 방향으로 설치하는 상황을 줄일 수 있게 하였다.