본문 바로가기

게임 개발 공부/언리얼엔진

언리얼 엔진 5 - 기본 용어 2

어제에 이어 언리얼엔진 공식 문서에 소개된 언리얼 엔진 용어에 대해 공부하려한다.

 

플레이어 컨트롤러(Player Controller)

-플레이어의 입력을 게임 안의 상호작용으로 변환한다.

-모든 게임에는 최소 하나의 플레이어 컨트롤러가 있다.

-주로 폰이나 캐릭터에 빙의한다.

-멀티플레이어 게임의 주요한 네트워크 상호작용 지점이다.

-멀티플레이 게임에선 모든 플레이어에 대해 하나의 플레이어 컨트롤러 인스턴스를 가진다. 각 클라이언트는 자신의 플레이어에

 해당하는 플레이어 컨트롤러만을 가지고 서버와 통신하는 용도로만 사용할 수 있다.

-연관된 C++클래스는  APlayerController

 

AI컨트롤러(AI Controller)

-게임 안의 NPC를 나타내는 폰을 소유한다.

-폰과 캐릭터는 특정 플레이어 컨트롤러가 빙의했거나 스스로 AI 컨트롤러를 생성하지 말라는 명령을 받지 않았다면 기본적으로

 베이스 AI 컨트롤러에 빙의된다.

-연관된 C++ 클래스는 AAIController

 

플레이어 스테이트(Plater State)

-게임 참여자의 스테이트를 말한다.

-인간 참여자 또는 플레이어를 시뮬레이션하는 봇 등이 있다.

-논플레이어 AI의 경우 플레이어 스테이트가 없다.

-이름, 현재 레벨, 체력, 점수, 아이템 소유여부 등의 정보

-멀티플레이어 게임의 경우 모든 컴퓨터에 모든 플레이어의 플레이어 스테이트가 존재한다.

-동기화를 유지하기 위해 서버에서 클라이언트로 데이터를 리플리케이트할 수 있다.

-연관된 클래스는 APlayerState

  -리플리케이트: 본을 뜨다. 동기화. 하단에서 후술.

 

게임 모드(Game Mode)

-플레이 중인 게임의 규칙을 설정

-규칙의 예시

  -플레이어가 게임에 참여하는 방법

  -게임의 일지 정지 가능 여부

  -승리 조건 등 특정 게임 전용 행동

-프로젝트 세팅에서 디폴트 게임 모드를 설정하고 레벨별로 오버라이드할 수 있다.

-한 레벨에는 하나의 게임 모드만 존재할 수 있다.

-멀티플레이어 게임의 경우 게임 모드는 서버에만 존재하며 각 클라이언트에 규칙이 리플리케이트된다.

-연관된 C++클래스는 AGameMode

 

게임 스테이트(Game State)

-게임 내의 모든 클라이언트에 복제할 정보가 들어있는 컨테이너

-게임 스테이트의 예시

  -게임 점수에 대한 정보

  -대결이 시작됐는지 여부

  -월드에 있는 플레이어 수를 기준으로 스폰할 AI 캐릭터의 수

-멀티 플레이어 게임의 경우 게임 스테이트에 대한 로컬 인스턴스가 각 플레이어의 컴퓨터에 하나씩 존재

-로컬 게임 스테이트 인스턴스는 서버의 게임 스테이트 인스턴스에서 업데이트된 정보를 가져온다.

-연관된 C++클래스는 AGameState

 

브러시(Brush)

-큐브, 구체와 같은 3D셰이프를 묘사하는 액터

-레벨에 브러시를 배치하여 레벨 지오메트리를 정의할 수 있다.

-이를 바이너리 스페이스 파티션(Binary Space Partition) 또는 BSP 브러시라고 한다.

-레벨의 윤곽 작업을 빠르게 하고싶은 경우 등에 유용

  *더미와 비슷한듯.

 

볼륨(Volume)

-연결된 효과에 따라 용도가 달라지는 바운드된 3D 공간

-볼륨 예시

  -블로킹 볼륨(Blocking Volume): 보이지 않으며 액터가 통과하지 못하게 막는다.

  -페인 코징 볼륨(Pain Causing Volume): 오버랩되는 앱터에 시간이 지남에 따라 대미지를 준다.

  -트리거 볼륨(Trigger Volume): 액터가 들어오거나 나갈 때 이벤트를 유발하도록 프로그래밍

 

레벨(Level)

-개발자가 정의하는 게임플레이 영역

-지오메트리, 폰, 액터 등과 같이 플레이어가 보고 상호작용할 수 있는 모든 것이 포함

-언리얼 엔진은 각 레벨을 별도의 .umap 파일로 저장한다. 그에 따라 때론 맵이라고 불리기도 한다.

 

월드(World)

-게임을 구성하는 모든 레벨이 담겨있는 컨테이너

-레벨의 스트리밍과 다이내믹 액터의 스폰을 처리함.

 

공식문서에 기재되어있는건 여기까지이다. 생각보다 아직 모르거나 모호하거나 잘못알고있는 용어들이 많았다는걸 알았다. 그러나 알아야 할 용어는 앞으로도 무수히 많을 것이다. 용어는 중요하다. 용어의 의미를 아는 것만으로도 새로운 개념이나 기능을 배울 때 훨씬 도움이 된다. 앞으로도 용어의 뜻은 확실히 알고 넘어가야겠다.

 

https://dev.epicgames.com/documentation/ko-kr/unreal-engine/unreal-engine-terminology


 

번외 - 리플리케이트(Replicate)

 

플레이어 스테이트 항목에서 등장한 리플리케이트라는 용어의 의미를 살펴보니 생각보다 중요한 부분인 것 같아 ChatGPT와 함께 살짝 파고들어 봤다.

 

  • 일반적인 의미
          - 데이터를 다른 위치나 시스템으로 동일하게 복제하는 과정
          - 복제된 데이터는 원본과 일치해야 하며, 실시간 동기화를 요구할 때도 있다.

  • 언리얼 엔진에서 리플리케이트
      멀티플레이어 게임에서 객체나 데이터를 클라이언트 서버 사이에서 동기화하는 기능말한다.
         - 서버(Server): 게임의 중심이며 모든 권한을 가진다.
         - 클라이언트(Client): 서버에 연결된 사용자 장치. 서버가 관리하는 데이터를 받아서 화면에 보여준다.

      리플리케이트의 주요 역할:
         - 게임 상태 동기화: 서버의 게임 테이터를 클라이언트로 전송해 모든 플레이어에게 동일한 상태를 보여준다.
         - 객체 복제: 게임 내 캐릭터, 아이템, 총알 등 중요한 객체가 클라이언트에 동일하게 복제된다.
         - 변수 동기화: 변수의 값을 서버에서 변경하면, 클라이언트에도 즉시 반영되도록 동기화한다.

      언리얼에서 Replicate 사용 예시(아직 코딩을 배우지 않아서 추후 익히게 되면 다시 한번 체크해봐야겠다):
UCLASS()
class MYGAME_API AMyActor : public AActor
{
    GENERATED_BODY()

public:
    // 이 변수를 리플리케이트하도록 설정
    UPROPERTY(Replicated)
    int32 Health;

    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};

void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    DOREPLIFETIME(AMyActor, Health); // 변수 Health를 리플리케이트
}

       -UPROPERTY(Replicated)를 사용하면 해당 변수가 서버-클라이언트 간 동기화 된다.

       -DOREPLIFETIME은 언리얼 엔진의 리플리케이트 설정을 위한 매크로다.

 

  • 데이터베이스에서의 리플리케이트
    데이터베이스에서 Replication은 데이터를 여러 서버에 복제해서 동기화하는 과정을 의미한다. 주로 백업이나 고가용성(High Availability)을 보장하기 위해 사용된다.
  • 네트워크 및 분산 시스템
    네트워크 시스템이나 클라우드에서는 리플리케이트가 데이터를 여러 노드나 위치에 복사해서 데이터 일관성을 유지하는데 쓰인다.

  • 언리얼에서 리플리케이션 예시
    상황 설정
       - 플레이어가 대미지 10의 공격을 받았다.

    대미지 처리의 흐름
       - 입력 및 액션 발생(클라이언트)
               > 클라이언트 측에서 "플레이어가 공격당함"이라는 이벤트 발생
       - 서버에서 권한 확인 및 대미지 적용
               > 대미지 값을 서버에 전달하면 서버는 다음을 수행한다.
                    1. 현재 HP값을 가져온다.
                    2. 대미지(10)을 HP에 적용한다. (예: HP -= 10;)
                    3. 변경된 HP 값을 리플리케이트해서 클라이언트에 동기화한다.
       - 클라이언트에 동기화
               > 서버에서 변경된 HP값은 리플리케이션을 통해 클라이언트에게 전달된다.
               > 클라이언트는 이 값을 받아서 화면에 반영한다. (체력바 감소 또는 숫자 감소 등의 UI 업데이트)

    언리얼 엔진 코드 예시:
    헤더파일 (MyCharacter.h)
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    // 플레이어의 체력
    UPROPERTY(ReplicatedUsing=OnRep_Health)
    float Health;

    // 체력 초기화
    AMyCharacter();

    // 데미지를 적용하는 함수
    UFUNCTION(Server, Reliable)
    void ApplyDamage(float DamageAmount);

protected:
    // 체력이 리플리케이트될 때 호출되는 함수
    UFUNCTION()
    void OnRep_Health();

    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};

소스파일 (MyCharacter.cpp)

#include "MyCharacter.h"
#include "Net/UnrealNetwork.h"

AMyCharacter::AMyCharacter()
{
    Health = 100.0f; // 초기 체력
    bReplicates = true; // 리플리케이션 활성화
}

void AMyCharacter::ApplyDamage(float DamageAmount)
{
    if (HasAuthority()) // 서버에서만 실행
    {
        Health -= DamageAmount;
        Health = FMath::Clamp(Health, 0.0f, 100.0f); // 체력 범위 제한
        OnRep_Health(); // 클라이언트에 업데이트
    }
}

void AMyCharacter::OnRep_Health()
{
    // 체력이 변경될 때 실행: UI 업데이트 같은 동작
    UE_LOG(LogTemp, Warning, TEXT("Player Health: %f"), Health);
}

void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(AMyCharacter, Health); // 체력 리플리케이션 설정
}

 

          흐름 요약

             1. 클라이언트: 대미지 감지 후 서버에 적용 요청(ApplyDamage 함수 실행)

             2. 서버: 권한을 확인하고 HP를 계산(서버가 항상 최종 결정권을 가짐)
             3. 서버 -> 클라이언트: 변경된 HP값을 모든 플레이어에게 리플리케이트

             4. 클라이언트: 값을 반영해서 업데이트된 값을 화면에 보여줌

 

  • 서버에서 처리하는 이유
    - 클라이언트에서 처리할 시 해킹이나 치트의 가능성이 존재하기 때문이다. 그렇기에 서버는 항상 "권한"을 가지고 요청을 검증하고 결정된 값만 전달한다.

한 대 맞았다고 이렇게 복잡한 과정을 거쳐 많은 이들이 일하게 된다니.. 잡몹한테도 한대 맞기가 두려워 도망다닌 나 덕분에 쓸데없는 에너지 낭비가 일어나지 않은 것 같아서 뿌듯하다.

 

아직은 잘 모르지만 얼른 배워서 코드만 보고도 무슨 내용인지 다 알 수 있는 수준이 되고싶다는 바람과 열정이 슬쩍 물 들 듯 샘솟는다.