Sparta Unreal 부트캠프 89일차

정찬호·2026년 4월 8일

코딩 테스트 — 프로그래머스 삼각 달팽이

풀이 접근

삼각형 배열을 1차원 배열로 펼친 뒤, 달팽이가 이동하는 세 방향(왼쪽 아래, 오른쪽, 왼쪽 위)을 반복하며 값을 채우는 방식으로 구현했습니다.

초기에 반복 횟수를 ceil(n/4)로 설정했는데, 이는 달팽이가 방향을 꺾으며 안으로 파고드는 껍질(Layer)의 수가 약 n/4일 것이라는 추측했기 때문입니다. 하지만 실제로 Layer의 수는 n/3에 가깝기 때문에, n/4로 설정하면 n이 커질수록 달팽이가 안쪽에 도달하기 전에 반복문이 종료된다고 합니다.

반복 횟수를 n으로 넉넉하게 설정하자 정답을 받을 수 있었습니다. 범위를 벗어나거나 이미 채워진 인덱스에는 덮어씌우지 않는 방어 로직을 작성해 두었기에 오답을 피할 수 있었습니다.

vector solution(int n) {
    vector answer;
    int answerSize = 0;
    for(int i = 1; i <= n; i++) answerSize += i;
    answer.resize(answerSize, 0);

    int currentIdx = 1;
    int leftDown = 0, bottomRight = 0, leftUp = 0;

    for(int i = 0; i < n; i++)
    {
        leftDown = leftUp;
        for(int j = i; j < n - i; j++)
        {
            if(leftDown + j < answerSize && answer[leftDown + j] == 0)
            { leftDown += j; answer[leftDown] = currentIdx++; }
        }

        bottomRight = leftDown;
        for(int j = 0; j < n - i * 2; j++)
        {
            if(bottomRight + 1 < answerSize && answer[bottomRight + 1] == 0)
            { bottomRight++; answer[bottomRight] = currentIdx++; }
        }

        leftUp = bottomRight;
        for(int j = n - i; j > i; j--)
        {
            if(leftUp - j > 0 && answer[leftUp - j] == 0)
            { leftUp -= j; answer[leftUp] = currentIdx++; }
        }
    }
    return answer;
}
테스트 1 〉	통과 (0.01ms, 4.14MB)
테스트 2 〉	통과 (0.01ms, 3.67MB)
테스트 3 〉	통과 (0.01ms, 4.2MB)
테스트 4 〉	통과 (1.00ms, 4.67MB)
테스트 5 〉	통과 (1.08ms, 4.68MB)
테스트 6 〉	통과 (1.11ms, 4.79MB)
테스트 7 〉	통과 (180.38ms, 107MB)
테스트 8 〉	통과 (156.96ms, 107MB)
테스트 9 〉	통과 (156.20ms, 107MB)

n이 커질수록 시간과 메모리가 급격히 늘어나는 것으로 보입니다. 개선의 여지가 있어 보입니다.

팀 프로젝트 — Unreal Engine 멀티플레이어 게임

트러블슈팅 — Citizen → Gimmick 상호작용 버그

원인 분석

VGEquipmentComponent::Interact()는 클라이언트에서 실행되어 레이캐스트로 기믹 액터를 탐지한 뒤, Execute_OnInteract()클라이언트에서 직접 호출하게 되어있습니다.

문제는 기믹의 실제 상태 변경 로직이 HasAuthority() 가드로 보호되어 있다는 점입니다.
[Client] Interact()
→ SweepSingleByChannel로 기믹 탐지
→ Execute_OnInteract() ← 클라이언트에서 직접 호출
→ AVGMissionGimmickBase::OnInteractWith()
→ if (!HasAuthority()) return; ← Authority 없음 → 즉시 리턴

수정 방법

VGMissionGimmickBase에 Server RPC를 추가해 클라이언트가 서버에 요청을 위임하도록 수정했습니다. VGEquipmentComponent는 건드리지 않고 Mission 파일 범위 내에서 해결할 수 있는 방법이었지만 아직 상호작용이 정상적으로 동작하고 있지 않습니다.

void AVGMissionGimmickBase::OnInteractWith(AVGCharacterBase* Interactor)
{
    if (!HasAuthority())
    {
        Server_Interact(Interactor); // 클라이언트는 서버에 위임
        return;
    }
    if (!CanInteractWith(Interactor)) return;
    OnGimmickInteracted.Broadcast(this, Interactor);
}

void AVGMissionGimmickBase::Server_Interact_Implementation(AVGCharacterBase* Interactor)
{
    if (!CanInteractWith(Interactor)) return;
    OnGimmickInteracted.Broadcast(this, Interactor);
}

자식 기믹 클래스(Lever, Chest, Altar 등)는 RPC 함수를 재정의해서 사용합니다.


설계 결정 — 미션 보상 로직

"누가 완료했는가" 추적 문제

후보로 검토한 방법들은 다음과 같습니다.

  • 기존 OnGimmickStateChanged 델리게이트에 Interactor 인자 추가 → 영향 범위가 너무 넓어 배제
  • 기믹이 소속 미션 포인터를 직접 보유 → 강결합이라 배제
  • 별도 Interactor 델리게이트 추가 → 채택

보상 로직의 위치는 MissionSubsystem이 아닌 MissionBase 로 결정했습니다. 미션마다 보상 조건이 다를 수 있고, 서브시스템은 조율자 역할에 집중하는 것이 SRP 원칙에 맞기 때문입니다.

OnRep_CurrentStateTag 역할 정리

기존 코드는 OnRep_ 안에서 HasAuthority()를 체크하며 서버 측 연쇄 처리까지 담당하고 있었습니다. OnRep_은 클라이언트 피드백 콜백이므로 서버 로직이 섞이면 실행 경로가 불명확해집니다.

// 변경 후
void AVGMissionBase::CompleteMission()
{
 ...
 SetMissionState(VigilantMissionTags::MissionCompleted);
    for (AVGMissionGimmickBase* Gimmick : MissionGimmicks)
        Gimmick->SetStateTag(VigilantMissionTags::GimmickCompleted); // 서버 연쇄 처리
    SpawnRewardItems(Contributors);
}

void AVGMissionBase::OnRep_CurrentStateTag()
{
    OnMissionStateChanged.Broadcast(GetMissionID(), CurrentStateTag); // 클라이언트 피드백만
}

오늘 작업 내역 요약

  • Altar 기믹 수정: Carry 아이템 1개 → 복수 배치 지원 (FVGAltarPlacementSlot 배열 도입)
  • 미션 데이터를 UVGMissionDataAsset으로 분리 (MissionID, MissionDescription, MissionTypeTag, RewardItemClass, TimeLimit)
  • 클라이언트 미션 등록 트리거를 OnRep_MissionID 방식에서 BeginPlay 방식으로 변경
  • Gimmick 상호작용 버그 원인 파악 및 팀원 공유
  • OnRep_CurrentStateTag 역할 정리 및 서버/클라이언트 로직 분리 설계 확정
  • 미션 보상 로직 설계 확정 (기여자 추적 델리게이트 추가, 보상 책임은 MissionBase)
profile
게임 개발 지망생입니다.

0개의 댓글