icon
2장 : 언리얼 C++ 기초

게임 루프와 주요 클래스 구조


이전 절에서 C++ 클래스를 생성하고 블루프린트로 확장하는 경험을 통해 언리얼 엔진의 유연한 개발 방식을 맛보셨을 겁니다. 이제 여러분이 만든 액터와 클래스들이 게임 내에서 어떻게 생명을 얻고 동작하는지 이해하기 위해, 언리얼 엔진의 게임 루프(Game Loop) 와 이를 구성하는 주요 클래스들의 구조를 살펴보는 시간을 갖겠습니다. 이 개념들은 언리얼 엔진의 동작 원리를 깊이 이해하고, 나중에 복잡한 게임 로직을 설계할 때 중요한 기반이 될 것입니다.


게임 루프: 게임의 심장 박동

모든 게임은 기본적으로 무한 반복되는 주기를 가지고 동작합니다. 이를 게임 루프라고 부릅니다. 언리얼 엔진도 마찬가지로, 정해진 순서에 따라 매 프레임(Frame)마다 일련의 작업들을 수행하며 게임 세계를 업데이트합니다. 이 루프는 플레이어의 입력 처리, AI 업데이트, 물리 시뮬레이션, 애니메이션, 렌더링 등 게임 내의 모든 변화를 제어합니다.

언리얼 엔진의 게임 루프는 다음과 같은 주요 단계로 구성됩니다. (간략화된 형태)

  1. 입력 처리 (Input Processing): 키보드, 마우스, 게임패드 등 플레이어의 입력을 감지하고 처리합니다.
  2. 게임 로직 업데이트 (Game Logic Update)
    • 틱(Tick) 함수 호출: 월드에 존재하는 대부분의 액터(AActor)와 컴포넌트(UActorComponent)의 Tick 함수가 호출되어 각자의 로직을 업데이트합니다. 이 함수는 이전 프레임으로부터 경과된 시간(DeltaTime)을 인자로 받아 일관된 속도로 동작을 수행하도록 합니다.
    • 물리 시뮬레이션: 액터들의 충돌 감지 및 반응, 중력 적용 등 물리 엔진이 게임 세계를 업데이트합니다.
    • AI 업데이트: 인공지능 캐릭터들이 환경을 인지하고 다음 행동을 결정합니다.
  3. 렌더링 (Rendering): 업데이트된 게임 월드의 상태를 바탕으로 3D 장면을 화면에 그립니다. 카메라의 시점에 따라 모델, 텍스처, 조명, 셰이더 등을 계산하여 최종 이미지를 만듭니다.
  4. 사운드 업데이트 (Sound Update): 배경 음악, 효과음 등 게임 내의 사운드를 업데이트하고 재생합니다.
  5. 네트워크 동기화 (Networking Synchronization): 멀티플레이어 게임의 경우, 서버와 클라이언트 간의 게임 상태를 동기화합니다.

이 모든 과정이 매우 짧은 시간(보통 1/30초 또는 1/60초) 안에 반복적으로 이루어지며, 이를 통해 우리가 보는 부드러운 게임 화면이 만들어집니다. 여러분이 AActor::Tick(float DeltaTime) 함수에 코드를 작성하면, 그 코드가 바로 이 '게임 로직 업데이트' 단계의 핵심 부분에서 매 프레임마다 실행되는 것입니다.


주요 클래스 구조와 역할

언리얼 엔진의 게임 루프와 밀접하게 연관되어 게임의 전반적인 흐름을 제어하는 몇 가지 핵심 클래스들이 있습니다. 이 클래스들은 특정 역할을 전담하며, 서로 유기적으로 협력하여 하나의 게임을 완성합니다.

UGameInstance

  • 역할: UGameInstance게임 전체의 수명 주기 동안 유지되는 가장 상위 레벨의 객체입니다. 게임이 시작될 때 생성되어 게임이 종료될 때까지 단 하나만 존재합니다(싱글톤).
  • 특징: 레벨이 변경되어도 파괴되지 않기 때문에, 여러 레벨에 걸쳐 유지되어야 하는 데이터(예: 플레이어 진행 상황, 설정, 영구적인 네트워크 연결 등)를 저장하고 관리하는 데 이상적입니다.
  • 활용: 게임 전반에 걸친 데이터 관리, 세션 관리, 로딩 화면 전환, 설정 저장/로드 등에 사용됩니다.

AGameModeBase / AGameMode

  • 역할: AGameModeBase (또는 더 구체적인 게임 유형에 맞는 AGameMode)는 게임의 규칙과 흐름을 정의하는 클래스입니다. 예를 들어, 어떤 캐릭터 클래스를 사용할지, 플레이어의 스폰 지점은 어디인지, 점수 계산 방식은 무엇인지, 게임의 승리/패배 조건은 무엇인지 등을 설정합니다.
  • 특징: AGameMode서버에서만 존재하며, 클라이언트에는 복제되지 않습니다. 이는 게임 규칙이 서버에서 단일하게 관리되어야 함을 의미합니다. 클라이언트에서는 AGameStateBase (후술)가 게임 상태 정보를 공유받습니다.
  • 활용: 게임 모드 변경, 플레이어 접속/종료 처리, 게임 시작/종료 로직, UI 초기화 등에 사용됩니다. 여러분이 만드는 게임의 규칙이 달라질 때마다 새로운 AGameMode 클래스를 만들게 될 것입니다.

AGameStateBase / AGameState

  • 역할: AGameStateBase (또는 AGameState)는 게임의 현재 상태 정보를 모든 클라이언트와 공유하는 역할을 합니다. 즉, 게임의 규칙(AGameMode)에 따라 변동되는 플레이어 점수, 남은 시간, 현재 라운드, 참여 플레이어 목록 등과 같은 정보를 담고, 이를 모든 플레이어에게 전달합니다.
  • 특징: AGameState는 서버와 모든 클라이언트에 복제되어 존재합니다. 이를 통해 클라이언트는 서버의 게임 상태를 파악하고 그에 맞는 UI를 표시하거나 동작을 수행할 수 있습니다.
  • 활용: 점수판 업데이트, 라운드 정보 표시, 게임 진행 상태 표시 등에 사용됩니다.

APlayerController

  • 역할: APlayerController플레이어의 입력을 처리하고, 해당 플레이어가 조종하는 APawn 또는 ACharacter를 제어하는 클래스입니다. 키보드, 마우스, 게임패드 등의 입력 이벤트를 받고, 이를 게임 로직으로 변환하여 캐릭터를 움직이거나 상호작용하게 만듭니다.
  • 특징: 각 플레이어마다 하나씩 존재하며, 서버와 해당 클라이언트 모두에 존재합니다. AI가 제어하는 캐릭터는 AAIController가 담당합니다.
  • 활용: 캐릭터 이동, 카메라 제어, UI 상호작용, 인벤토리 관리, 무기 발사 등 플레이어와 관련된 거의 모든 입력 및 상호작용 로직에 관여합니다.

APawn / ACharacter

  • 역할: APawnAPlayerControllerAAIController에 의해 '빙의(Possess)'되어 제어될 수 있는 액터의 기본 클래스입니다. 즉, 플레이어나 AI가 월드 내에서 조종할 수 있는 실제 객체를 나타냅니다. ACharacterAPawn을 상속받으며, 사람 형태의 이동과 관련된 복잡한 로직(걷기, 뛰기, 점프, 웅크리기 등)을 구현하는 데 특화되어 있습니다.
  • 특징: 폰은 월드에 배치되며, 변환 정보를 가집니다. ACharacter는 자체적으로 UCharacterMovementComponent를 포함하여 복잡한 이동을 쉽게 처리할 수 있습니다.
  • 활용: 플레이어 캐릭터, 적 AI, 차량, 비행기 등 게임 내에서 플레이어 또는 AI에 의해 움직이거나 상호작용할 수 있는 모든 대상을 만들 때 사용됩니다.

UActorComponent / USceneComponent

  • 역할: UActorComponent는 액터에 특정 기능을 부여하는 모듈이며, USceneComponentUActorComponent를 상속받아 3D 공간 내에서 위치, 회전, 스케일 정보를 가지는 컴포넌트입니다.
  • 특징: 액터에 부착되어 기능을 확장하는 역할을 합니다. 액터 하나에 여러 컴포넌트를 붙여 복잡한 기능을 조립할 수 있습니다. 예를 들어, UStaticMeshComponent(3D 모델), UCameraComponent(카메라 시점), UParticleSystemComponent(파티클 효과), UAudioComponent(사운드) 등이 있습니다.
  • 활용: 액터의 시각적 표현, 충돌 감지, 물리 시뮬레이션, 카메라, 사운드, 커스텀 로직 등 특정 모듈화된 기능을 구현할 때 사용됩니다.

클래스 간의 관계도 (간략화)

[게임 실행]

(싱글톤) UGameInstance  (게임 전체 관리, 레벨 변경 시 유지)
   ↓ (레벨 로드 시)
AGameModeBase (게임 규칙 정의, 서버 전용)
   ↓ (AGameModeBase에 의해 생성/관리)
AGameStateBase (게임 상태 공유, 서버/클라이언트 복제)
   ↓ (플레이어 접속 시)
APlayerController (플레이어 입력 처리, 플레이어 당 하나)
   ↓ (APlayerController에 의해 빙의)
APawn / ACharacter (월드 내 실제 플레이어/AI 객체)
   ↓ (APawn/ACharacter에 부착되어 기능 확장)
UActorComponent / USceneComponent (액터의 모듈화된 기능)
   ↑ (모든 UObject 기반 클래스)
UObject (언리얼 객체 시스템의 기본, 가비지 컬렉션, 반사 시스템 등)

이러한 클래스들의 구조와 역할을 이해하는 것은 언리얼 엔진에서 C++ 코드를 작성할 때 '무엇을 어디에 구현해야 하는가'에 대한 명확한 가이드라인을 제공합니다. 이제 여러분은 단순히 코드를 작성하는 것을 넘어, 언리얼 엔진이 어떻게 동작하는지에 대한 큰 그림을 그릴 수 있게 되었습니다.


게임 루프와 주요 클래스들의 구조를 이해하셨기를 바랍니다. 이 지식은 앞으로 여러분이 언리얼 엔진으로 복잡한 게임 시스템을 설계하고 구현하는 데 매우 중요한 밑거름이 될 것입니다. 다음 절에서는 이 클래스들을 활용하여 액터의 수명 주기 함수들(BeginPlay, Tick, EndPlay 등)에 대해 더 자세히 알아보고 실제 코드를 작성해보는 시간을 가질 것입니다. 준비되셨나요?