카테고리 없음

Oblivio 아이템 설계 및 개발: 어둠 속의 파밍과 시각적 피드백

eclipse2 2026. 5. 13. 00:12

플레이어가 생존하기 위해 끊임없이 맵을 뒤져야 하는 만큼, 파밍(Farming)의 편의성과 아이템 상호작용 시스템은 생존 호러 게임의 쾌적함을 결정짓는 중요한 요소다.

1. 상호작용 가능한 아이템 베이스(AOblivioItemBase) 구축

모든 아이템의 부모가 되는 베이스 클래스를 설계했다.

  • 접근 감지: 아이템에 USphereComponent를 부착하여 일정 반경 내로 플레이어가 들어오면(OnSphereOverlap) 감지하도록 구현했다.
  • 감지된 아이템은 플레이어 캐릭터의 SetNearbyItem 함수를 통해 등록되며, 이후 플레이어가 상호작용 키(E)를 누르면 레이캐스트를 통해 아이템을 획득하는 구조로 연결했다.

2. Custom Depth를 활용한 아이템 외곽선(Outline) 효과

가장 공을 들인 부분이다. 맵이 워낙 어둡다 보니 플레이어가 아이템을 코앞에 두고도 지나치는 일이 잦았다.

  • 플레이어가 아이템 주변 스피어 콜리전에 닿으면, ItemMesh->SetRenderCustomDepth(true)를 호출하여 해당 아이템만 렌더링 패스에서 분리되도록 만들었다.
  • 범위를 벗어나면(OnSphereEndOverlap) 다시 Custom Depth를 꺼서 외곽선이 사라지게 하여, "이 아이템과 상호작용할 수 있다"는 확실한 피드백을 주었다.

3. 트러블슈팅: 포스트 프로세스 머테리얼 직접 구현

  • 문제: 처음에는 마켓플레이스에서 가져온 외곽선 에셋을 썼으나, 일반 머테리얼을 포스트 프로세스 볼륨에 억지로 집어넣어 화면에 렌더링 되지 않는 심각한 오류가 있었다.
  • 해결: 의존성을 버리고 SceneTexture(CustomDepth) 노드와 UV Offset 수학 연산(Add, Subtract, Lerp)을 결합하여 가볍고 완벽하게 작동하는 외곽선 전용 포스트 프로세스 머테리얼(M_Outline_PP)을 5분 만에 직접 제작하여 해결했다. 데이터 타입 충돌(float4 vs float3) 문제도 Component Mask를 사용해 깔끔하게 제어했다.

코드:

1. Custom Depth를 활용한 외곽선 트리거 (OblivioItemBase.cpp)

void AOblivioItemBase::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor && OtherActor != this)
    {
        if (AOblivioCharacter* Player = Cast<AOblivioCharacter>(OtherActor))
        {
            Player->SetNearbyItem(this); // 상호작용 UI 연동용
            
            // 외곽선 하이라이트(Custom Depth) 활성화
            ItemMesh->SetRenderCustomDepth(true);
            ItemMesh->SetCustomDepthStencilValue(255);
        }
    }
}

void AOblivioItemBase::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
    if (AOblivioCharacter* Player = Cast<AOblivioCharacter>(OtherActor))
    {
        Player->SetNearbyItem(nullptr);
        
        // 범위를 벗어나면 외곽선 하이라이트 비활성화
        ItemMesh->SetRenderCustomDepth(false);
    }
}