OSWorlds - 게임 블로그 📌 게임 프로그래밍 📌 게임소식 🔑 로그인 📝 회원가입

언리얼 엔진 GameMode,GameState,PlayerState 차이

언리얼 엔진으로 게임을 만들다 보면 처음에는 대부분의 기능을 Character나 PlayerController 안에 넣게 됩니다. 게임 시작, 제한 시간, 점수, 킬 수, 스테이지 진행 상태까지 한 블루프린트에서 처리하는 경우도 많습니다.

싱글플레이 게임에서는 이렇게 만들어도 당장 큰 문제가 보이지 않을 수 있습니다. 하지만 프로젝트가 커지거나 멀티플레이 기능을 추가하면 “이 변수는 어디에 저장해야 하지?”라는 고민이 시작됩니다.

특히 이름이 비슷한 GameMode, GameState, PlayerState​는 초보자가 자주 혼동하는 클래스입니다. 세 클래스 모두 게임 진행과 관련되어 있지만 담당하는 범위와 네트워크에서 존재하는 위치가 다릅니다.

이번 글에서는 어려운 네트워크 용어를 최대한 줄이고, 실제 전투 게임을 예로 들어 세 클래스의 차이를 쉽게 알아보겠습니다.

💡 한 줄 정답 — GameMode는 승리 조건, 플레이어 입장, 캐릭터 스폰처럼 게임의 규칙을 서버에서 판단하는 클래스이고, GameState는 남은 시간이나 팀 점수처럼 현재 게임 상황을 모든 플레이어에게 공유하는 클래스이며, PlayerState는 플레이어 이름, 개인 점수, 킬 수처럼 한 명의 플레이어에게 속하지만 다른 플레이어도 알아야 하는 정보를 저장하는 클래스입니다.

목차

  1. Gameplay Framework란 무엇인가?
  2. GameMode의 역할
  3. GameState의 역할
  4. PlayerState의 역할
  5. 세 클래스의 차이 한눈에 보기
  6. 실제 전투 게임에서는 어떻게 나눌까?
  7. 블루프린트에서 클래스를 설정하는 방법
  8. 초보자가 자주 하는 실수
  9. 어떤 변수에 저장해야 하는지 판단하는 방법

Gameplay Framework란 무엇인가?

Gameplay Framework는 언리얼 엔진에서 게임의 기본 구조를 만들 때 사용하는 클래스 모음입니다.

Character, Pawn, PlayerController, GameMode, GameState, PlayerState 등이 모두 Gameplay Framework에 포함됩니다. 각 클래스에 역할이 나뉘어 있기 때문에 하나의 블루프린트가 모든 기능을 처리하지 않아도 됩니다.

예를 들어 플레이어 입력은 PlayerController가 처리하고, 실제로 움직이는 캐릭터는 Character가 담당합니다. 게임의 승패 규칙은 GameMode가 판단하고, 모든 플레이어가 확인해야 하는 경기 정보는 GameState가 관리합니다.

처음에는 이런 구조가 조금 복잡하게 느껴질 수 있습니다. 하지만 클래스별 역할을 정리해 두면 기능을 찾거나 오류를 수정하기가 훨씬 쉬워집니다.


GameMode는 게임의 규칙을 결정한다

GameMode는 말 그대로 게임의 진행 방식을 결정하는 클래스입니다.

예를 들어 다음과 같은 내용을 GameMode에서 처리할 수 있습니다.

  • 게임 시작 조건
  • 승리와 패배 조건
  • 제한 시간이 끝났을 때의 처리
  • 플레이어 입장과 퇴장
  • 캐릭터 스폰과 리스폰
  • 사용할 Default Pawn Class
  • 사용할 PlayerController Class
  • 사용할 GameState Class
  • 사용할 PlayerState Class

축구 경기에 비유하면 GameMode는 경기 규칙을 알고 있는 심판과 비슷합니다. 골이 들어갔는지 판단하고, 경기를 언제 시작하거나 끝낼지 결정합니다.

다만 여기서 반드시 기억해야 할 특징이 있습니다.

GameMode는 서버에만 존재한다

멀티플레이 게임에서 실제 GameMode 인스턴스는 서버에만 존재합니다. 일반 클라이언트는 서버에서 실행 중인 GameMode의 변수에 직접 접근할 수 없습니다.

싱글플레이에서는 내 컴퓨터가 서버 역할까지 함께 처리하기 때문에 Get Game Mode 노드가 자연스럽게 작동합니다. 그래서 초보자는 GameMode가 모든 환경에서 접근 가능한 클래스라고 생각하기 쉽습니다.

하지만 멀티플레이 클라이언트에서 GameMode를 가져오려고 하면 원하는 값을 얻지 못할 수 있습니다. Epic Games 공식 문서도 GameMode는 원격 클라이언트에 복제되지 않으며, 클라이언트와 공유해야 하는 정보는 GameState에 저장하도록 설명합니다. Game Mode와 Game State 공식 문서

GameMode에 저장하기 좋은 정보

다음과 같이 서버만 알고 있거나 서버에서 판단해야 하는 내용은 GameMode에 잘 어울립니다.

  • 목표 킬 수
  • 라운드 시작 조건
  • 플레이어 리스폰 규칙
  • 팀 배정 규칙
  • 보스 등장 조건
  • 승리 팀 결정
  • 게임 종료 처리

예를 들어 먼저 10킬을 달성한 팀이 승리하는 게임이라면, “10킬을 달성하면 게임을 끝낸다”라는 규칙은 GameMode에서 판단할 수 있습니다.

하지만 현재 블루팀 점수가 7점이라는 정보를 모든 플레이어의 UI에 보여주려면 GameState를 함께 사용해야 합니다.


GameState는 현재 경기 상황을 공유한다

GameState는 현재 게임이 어떤 상태인지 저장하고 모든 플레이어에게 알려 주는 클래스입니다.

GameMode가 게임 규칙을 판단하는 심판이라면, GameState는 경기장에 설치된 전광판과 비슷합니다. 전광판은 경기 규칙을 직접 결정하지 않지만 현재 점수와 남은 시간처럼 모두가 알아야 하는 정보를 보여줍니다.

GameState에는 다음과 같은 정보를 저장하기 좋습니다.

  • 현재 라운드
  • 남은 경기 시간
  • 현재 웨이브
  • 팀 점수
  • 보스 등장 여부
  • 공통 목표 진행도
  • 현재 경기 진행 상태
  • 연결된 플레이어 목록

GameState는 서버에도 존재하고 클라이언트에도 복제됩니다. 따라서 서버에서 GameState의 값을 변경하고 해당 변수를 Replicated로 설정하면 연결된 플레이어들이 같은 값을 확인할 수 있습니다.

예를 들어 서버에서 남은 시간을 60초에서 59초로 변경하면, 각 클라이언트는 복제된 GameState 값을 이용해 자신의 UI에 59초를 표시할 수 있습니다.

GameState는 규칙을 결정하는 곳이 아니다

GameState에서 모든 게임 로직을 처리해도 기능 자체는 작동할 수 있습니다. 하지만 역할을 분리한다면 승패 판단은 GameMode가 담당하고, 판단 결과를 공유하는 일은 GameState가 담당하는 편이 좋습니다.

예를 들어 전투 게임의 제한 시간이 끝났다고 가정해 보겠습니다.

  1. GameMode가 제한 시간 종료를 확인합니다.
  2. GameMode가 양 팀의 점수를 비교합니다.
  3. GameMode가 승리 팀을 결정합니다.
  4. 결과를 GameState에 저장합니다.
  5. 각 클라이언트가 GameState의 결과를 읽어 승리 또는 패배 UI를 표시합니다.

이렇게 나누면 클라이언트가 임의로 승리 조건을 판단하지 않고, 서버가 결정한 동일한 결과를 모든 플레이어에게 보여줄 수 있습니다.

PlayerArray란 무엇인가?

GameState에는 현재 게임에 참여한 PlayerState를 모아 둔 PlayerArray가 있습니다.

이를 이용하면 게임에 참가한 플레이어의 이름이나 점수, 킬 수를 순회할 수 있습니다. 멀티플레이 점수판을 만들 때 자주 사용되는 배열입니다.

Epic Games 공식 문서에 따르면 PlayerArray에는 게임에 참가한 모든 PlayerState가 포함되며, 초기 복제가 끝난 뒤에는 서버와 클라이언트 모두에서 접근할 수 있습니다. Get Player State 공식 문서


PlayerState는 한 명의 플레이어 정보를 저장한다

PlayerState는 게임에 접속한 플레이어 한 명의 상태를 나타냅니다.

PlayerController도 한 명의 플레이어를 담당하기 때문에 두 클래스를 혼동하기 쉽습니다. 간단히 나누면 PlayerController는 입력과 조작을 담당하고, PlayerState는 다른 플레이어에게도 공유해야 하는 개인 정보를 담당합니다.

PlayerState에는 다음과 같은 값을 저장하기 좋습니다.

  • 플레이어 이름
  • 개인 점수
  • 킬 수와 데스 수
  • 소속 팀
  • 준비 완료 여부
  • 선택한 캐릭터
  • 멀티플레이 랭킹 정보
  • 현재 플레이어의 경기 상태

PlayerState는 특정 Character 자체의 정보가 아닙니다. 플레이어가 조종하던 Character가 사망하고 새로운 Character로 리스폰되어도 해당 플레이어의 점수와 킬 수는 계속 유지되어야 합니다.

이런 정보는 Character에 저장하기보다 PlayerState에 저장하는 것이 안전합니다.

Character와 PlayerState의 차이

Character는 월드 안에 실제로 존재하는 캐릭터입니다. 체력, 이동 속도, 현재 공격 상태처럼 캐릭터 몸체와 직접 연결된 정보는 Character 또는 Character Component에 저장하는 것이 자연스럽습니다.

반면 PlayerState는 그 캐릭터를 조종하는 플레이어의 경기 기록입니다.

예를 들어 다음과 같이 구분할 수 있습니다.

정보저장하기 좋은 위치
현재 체력Character
현재 콤보 상태Character 또는 Combat Component
개인 킬 수PlayerState
개인 점수PlayerState
소속 팀PlayerState
플레이어 닉네임PlayerState

캐릭터가 죽으면 Character는 Destroy된 뒤 새로 생성될 수 있습니다. 킬 수나 점수를 Character에 저장했다면 리스폰 과정에서 값이 초기화될 수 있습니다.

하지만 PlayerState는 플레이어를 기준으로 관리되기 때문에 Pawn이나 Character가 교체되어도 경기 기록을 유지하는 데 적합합니다.


GameMode, GameState, PlayerState 차이 한눈에 보기

세 클래스의 차이는 “누구의 정보인지”와 “누가 접근해야 하는지”를 기준으로 생각하면 이해하기 쉽습니다.

클래스주요 역할멀티플레이 위치대표적인 정보
GameMode게임 규칙과 판정서버에만 존재승리 조건, 스폰, 리스폰, 게임 시작
GameState전체 경기 상황 공유서버와 모든 클라이언트남은 시간, 팀 점수, 현재 라운드
PlayerState플레이어 개인 상태 공유서버와 모든 클라이언트닉네임, 개인 점수, 킬 수, 소속 팀

더 간단하게 정리하면 다음과 같습니다.

  • 규칙을 판단한다면 GameMode
  • 모두가 알아야 하는 경기 정보라면 GameState
  • 한 명에게 속한 공개 정보라면 PlayerState

이 세 문장만 기억해도 변수를 어디에 만들어야 할지 훨씬 쉽게 결정할 수 있습니다.


실제 전투 게임에서는 어떻게 나눌까?

이번에는 2대2 팀 전투 게임을 만든다고 가정해 보겠습니다.

게임 규칙은 3분 동안 싸우고, 먼저 10킬을 달성한 팀이 승리하는 방식입니다. 캐릭터가 사망하면 5초 뒤에 다시 스폰됩니다.

GameMode가 담당할 내용

  • 플레이어를 두 팀으로 배정
  • 라운드 시작
  • 목표 점수 10점 확인
  • 제한 시간 종료 확인
  • 승리 팀 결정
  • 사망한 플레이어 리스폰
  • 경기 종료 처리

GameState가 담당할 내용

  • 현재 남은 시간
  • 블루팀 점수
  • 레드팀 점수
  • 현재 라운드
  • 게임 시작 여부
  • 승리한 팀
  • 현재 경기 상태

PlayerState가 담당할 내용

  • 플레이어 닉네임
  • 개인 킬 수
  • 개인 데스 수
  • 개인 점수
  • 소속 팀
  • 준비 완료 상태

Character가 담당할 내용

  • 현재 체력
  • 공격 가능 여부
  • 회피 상태
  • 현재 장착 무기
  • 이동 속도
  • 피격 상태

이렇게 역할을 나누면 캐릭터가 죽어도 개인 킬 수는 PlayerState에 남아 있습니다. 팀 점수는 GameState에 저장되어 모든 플레이어의 UI에 표시되고, 승리 여부는 서버의 GameMode가 최종적으로 판단합니다.


블루프린트에서 클래스를 설정하는 방법

GameMode, GameState, PlayerState 블루프린트를 만들었다고 해서 자동으로 서로 연결되는 것은 아닙니다. GameMode의 Class Defaults에서 사용할 클래스를 직접 지정해야 합니다.

1. GameMode 블루프린트 만들기

콘텐츠 브라우저에서 Blueprint Class를 생성하고 부모 클래스로 GameModeBase 또는 GameMode를 선택합니다.

예시 이름은 다음과 같이 만들 수 있습니다.

  • BP_CombatGameMode
  • BP_CombatGameState
  • BP_CombatPlayerState

2. GameMode에 클래스 연결하기

BP_CombatGameMode를 열고 Class Defaults에서 다음 항목을 설정합니다.

  • Game State Class: BP_CombatGameState
  • Player State Class: BP_CombatPlayerState
  • Player Controller Class: 사용할 PlayerController
  • Default Pawn Class: 사용할 Character 또는 Pawn

3. 프로젝트 기본 GameMode 설정하기

프로젝트 전체에서 사용할 GameMode는 다음 위치에서 설정할 수 있습니다.

Project Settings → Maps & Modes → Default GameMode

특정 맵에서만 다른 GameMode를 사용하려면 해당 레벨의 World Settings에서 GameMode Override를 설정하면 됩니다.

메인 메뉴와 실제 전투 레벨이 서로 다른 규칙을 사용한다면 각각 다른 GameMode를 지정하는 것도 좋은 방법입니다.


GameModeBase와 GameMode 중 무엇을 선택해야 할까?

언리얼 엔진에는 GameModeBase와 GameMode가 모두 있어서 여기서도 혼란이 생길 수 있습니다.

GameModeBase는 비교적 단순하고 가벼운 기본 클래스입니다. 일반적인 싱글플레이 게임이나 복잡한 매치 상태가 필요하지 않은 프로젝트라면 GameModeBase로 시작해도 충분합니다.

GameMode는 GameModeBase를 상속하며, 경기 대기와 시작, 진행, 종료 같은 Match State 기능이 추가되어 있습니다. 멀티플레이 슈팅 게임처럼 명확한 경기 흐름이 필요할 때 유용합니다.

클래스어울리는 상황
GameModeBase싱글플레이, 간단한 스테이지, 일반적인 게임 규칙
GameMode대기·시작·진행·종료 상태가 필요한 멀티플레이 경기

GameModeBase를 사용한다면 일반적으로 GameStateBase를 함께 사용하고, GameMode의 Match State 기능을 사용한다면 GameState를 함께 사용하는 편이 자연스럽습니다.


초보자가 자주 하는 실수

HTML Anchor: common-mistakes

GameMode의 변수를 클라이언트 UI에서 읽으려고 한다

GameMode는 멀티플레이에서 서버에만 존재합니다. 클라이언트 UI에 표시해야 하는 값은 GameState나 PlayerState로 옮겨야 합니다.

팀 점수를 PlayerState에 저장한다

개인 점수는 PlayerState가 적합하지만, 팀 전체 점수는 모든 플레이어에게 공통으로 적용되는 정보입니다. 따라서 GameState에 저장하는 편이 좋습니다.

킬 수를 Character에 저장한다

Character가 사망하고 새로 스폰되면 기존 Character의 변수도 함께 사라질 수 있습니다. 플레이어의 킬 수와 데스 수는 PlayerState에 저장하는 것이 안전합니다.

GameState에서 승리 조건을 모두 판단한다

GameState에서도 함수를 실행할 수 있지만, 최종적인 게임 규칙과 판정은 서버의 GameMode가 담당하는 편이 좋습니다. GameState는 그 결과를 공유하는 역할에 집중합니다.

변수를 만들기만 하고 Replicated 설정을 하지 않는다

GameState나 PlayerState에 변수를 만들었다고 해서 모든 클라이언트에 자동으로 같은 값이 전달되는 것은 아닙니다. 멀티플레이에서 공유할 변수는 Replicated 또는 RepNotify 설정이 필요합니다.

UI까지 자동으로 갱신하려면 RepNotify를 사용해 값이 변경됐을 때 위젯을 업데이트하는 구조도 고려할 수 있습니다.


변수 위치를 결정하는 가장 쉬운 질문

어떤 변수를 어디에 만들어야 할지 헷갈린다면 다음 순서로 질문해 보세요.

첫 번째 질문: 게임의 규칙인가?

“이 값이 승패, 스폰, 게임 시작과 관련된 서버 규칙인가?”

그렇다면 GameMode를 먼저 생각합니다.

두 번째 질문: 모든 플레이어가 알아야 하는가?

“현재 경기 전체에 적용되고 모든 플레이어의 화면에 보여야 하는가?”

그렇다면 GameState가 적합합니다.

세 번째 질문: 한 플레이어에게 속한 정보인가?

“한 명의 점수나 킬 수처럼 특정 플레이어에게 속하지만 다른 사람도 확인해야 하는가?”

그렇다면 PlayerState가 적합합니다.

네 번째 질문: 캐릭터 몸체의 현재 상태인가?

“체력이나 피격 상태처럼 현재 월드에 존재하는 캐릭터 자체의 정보인가?”

그렇다면 Character나 별도의 Actor Component에 저장하는 편이 좋습니다.


마무리

GameMode, GameState, PlayerState는 이름이 비슷하지만 역할은 분명하게 다릅니다.

GameMode는 게임의 규칙을 판단하고, GameState는 현재 경기 상황을 모든 플레이어에게 공유합니다. PlayerState는 플레이어 한 명의 점수와 킬 수처럼 개인에게 속한 경기 정보를 관리합니다.

싱글플레이에서는 세 클래스의 역할을 정확하게 나누지 않아도 게임이 작동할 수 있습니다. 하지만 프로젝트가 커지거나 멀티플레이를 구현하기 시작하면 이러한 구분이 매우 중요해집니다.

처음부터 완벽하게 나누려고 부담을 가질 필요는 없습니다. 우선 “규칙인지, 전체 정보인지, 개인 정보인지”만 구분해도 구조가 훨씬 깔끔해집니다.

다음 글에서는 블루프린트 초보자가 자주 고민하는 Blueprint Interface와 Cast To의 차이를 살펴보고, 두 기능을 각각 어떤 상황에서 사용해야 하는지 실제 상호작용 예제로 알아보겠습니다.


참고 사이트


댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤