본문 바로가기
공부/언리얼 엔진

개발일지: 언리얼 엔진 튜토리얼 시스템 개발 - 블루프린트, 입력 처리, Enum 활용

by Excidus 2023. 3. 10.

언리얼 엔진(Unreal Engine)을 공부하며 진행한 프로젝트로, 튜토리얼 시스템과 키보드 기반 카메라 움직임 제한 기능을 개발했다. 이번 프로젝트는 블루프린트를 활용한 게임 로직 구현과 입력 처리, 그리고 최적화에 초점을 맞췄다. 여러 시행착오를 겪으며 새로운 개념을 익히고, 선배의 조언으로 문제를 해결한 경험을 기록했다.

1. 프로젝트 개요

  • 프로젝트 목표: 언리얼 엔진의 블루프린트를 활용해 튜토리얼 시스템을 구현하고, 키보드로 조작하는 카메라 움직임에 경계 제한을 추가한다.
  • 주요 기능:
    • 튜토리얼 시스템: 플레이어가 튜토리얼 단계를 순차적으로 진행하도록 Enum과 인덱스를 활용한 UI 버튼 제어 로직을 구현.
    • 카메라 움직임: 키보드 입력으로 카메라를 이동하되, 지정된 범위를 벗어나지 않도록 제한.
  • 구현 환경: Unreal Engine 5, 블루프린트 비주얼 스크립팅.
  • 배포: 현재 로컬 테스트 단계이며, 최종적으로 프로젝트 빌드 후 팀 내 공유 예정.

2. 학습 내용

블루프린트 SET

  • 정의: SET 노드는 컴포넌트를 참조하거나 값을 저장하는 데 사용된다. 값 갱신이나 변경이 필요 없는 경우에는 사용하지 않는 것이 좋다.
  • 구현 경험: 초기에는 모든 컴포넌트 참조에 SET을 사용했으나, 불필요한 연산이 발생했다. 최적화를 위해 필요한 경우에만 SET을 사용하도록 수정했다.
  • 배운 점: SET은 편리하지만, 무분별한 사용은 성능 저하를 유발한다. 최적화를 위해 최소화해야 한다.

입력 처리: Axis Input vs Action Input

  • Axis Input: 연속적인 입력을 처리한다. 예: 키보드의 방향키나 조이스틱.
  • Action Input: 단발성 입력을 처리한다. 대표적으로 마우스 휠이나 클릭이 있다.
  • 구현 경험: 카메라 이동에 Axis Input을 사용해 부드러운 이동을 구현했다. 점프 같은 단발성 동작에는 Action Input을 적용했다.
  • 배운 점: 입력 유형에 따라 적절한 매핑을 선택하는 것이 플레이어 경험에 중요하다.

Pawn과 Actor

  • Pawn: 언리얼 엔진 레벨에 배치 가능한 요소로, 플레이어 또는 AI가 조작할 수 있는 객체.
  • Actor: 모든 조작 가능한 객체의 베이스 클래스. Pawn은 Actor의 하위 클래스다.
  • 구현 경험: 플레이어 캐릭터를 Pawn으로 설정하고, PlayerController로 조작했다.
  • 배운 점: PawnActor의 계층 구조를 이해하면 객체 설계가 간결해진다.

GetControlledPawn vs Get Player Pawn

  • GetControlledPawn: 현재 PlayerController가 조작하는 Pawn을 반환한다. 대상은 Controller.
  • Get Player Pawn: 지정된 플레이어 인덱스의 Pawn을 반환한다. 원격 클라이언트의 경우 PlayerController가 없으면 동작하지 않을 수 있다. 대상은 Gameplay Statics.
  • 구현 경험: GetControlledPawn을 사용해 플레이어 캐릭터를 참조했다. 반복 호출을 줄이기 위해 참조를 변수에 저장했다.
  • 배운 점: 두 노드 중 하나로 통일하고, 불필요한 Get 호출을 최소화하면 성능이 향상된다.

3. 개발 과정

튜토리얼 시스템

  • 구현:
    1. Enum 생성: 튜토리얼의 각 단계를 구분하기 위해 Enum을 정의했다. 예: Intro, Movement, Interaction.
    2. Classification Index: Vector2D 변수를 사용해 startIndexendIndex를 저장, 각 Enum 단계의 시작과 끝을 정의했다.
    3. Enum 처리 함수: Enum 값을 받아 startIndexendIndex를 설정하고, currentIndexstartIndex로 초기화했다.
    4. startIndex = ClassificationIndex[Enum].X endIndex = ClassificationIndex[Enum].Y currentIndex = startIndex
    5. UpdateEnum 함수: UI 버튼 표시를 제어했다.
      • currentIndex == startIndex: 다음 버튼(>)만 표시.
      • currentIndex == endIndex: 이전 버튼(<)과 종료 버튼(X) 표시.
      • 그 외: 이전 버튼(<)과 다음 버튼(>) 표시.
  • 구현 경험: Enum과 인덱스를 연결하는 아이디어가 처음엔 복잡했지만, 선배의 조언으로 명확해졌다. 초기에는 모든 버튼이 표시되는 버그가 발생했다. currentIndex 초기화 로직을 점검하며 디버깅 중이다.
  • 배운 점: Enum과 인덱스를 활용하면 복잡한 상태 관리가 간결해진다. 디버깅은 로직의 세부 흐름을 확인하는 데 필수적이다.

카메라 움직임 제한

  • 구현: Axis Input을 사용해 키보드로 카메라를 이동하도록 설정했다. Clamp 노드를 활용해 카메라의 위치를 지정된 범위로 제한했다.
  • 구현 경험: 초기에는 카메라가 경계를 벗어나는 문제가 있었다. World Location 값을 기준으로 제한 범위를 설정해 해결했다.
  • 배운 점: Clamp과 좌표 계산은 카메라 제어의 핵심이다. 월드 좌표와 로컬 좌표의 차이를 명확히 이해해야 한다.

4. 개발 중 주요 이슈와 해결

  • 버튼 표시 버그: 튜토리얼 시작 시 모든 버튼이 표시되었다. currentIndex 초기화 로직을 확인하며 디버깅 중이다. 조건문과 변수 상태를 로그로 추적해 원인을 파악하고 있다.
  • 카메라 경계 오류: 카메라가 제한 범위를 벗어났다. Clamp 노드의 입력값을 월드 좌표로 조정해 문제를 해결했다.
  • 성능 저하: 불필요한 SETGet 호출로 연산이 비효율적이었다. 참조를 변수에 저장하고, SET 사용을 최소화해 최적화했다.

5. 마무리

이번 언리얼 엔진 프로젝트를 통해 블루프린트의 강력함과 입력 처리, 상태 관리의 중요성을 체감했다. 특히 Enum과 인덱스를 활용한 튜토리얼 시스템은 복잡한 로직을 간결하게 구현하는 좋은 경험이었다. 선배의 조언으로 문제를 빠르게 해결하며, 창의적인 문제 해결 능력을 키워야겠다는 동기를 얻었다. 다음 단계로는 현재 버튼 표시 버그를 수정하고, 사운드와 애니메이션을 추가해 튜토리얼의 완성도를 높일 계획이다.