어제에 이어 언리얼엔진 공식 문서에 소개된 언리얼 엔진 용어에 대해 공부하려한다.
플레이어 컨트롤러(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. 클라이언트: 값을 반영해서 업데이트된 값을 화면에 보여줌
- 서버에서 처리하는 이유
- 클라이언트에서 처리할 시 해킹이나 치트의 가능성이 존재하기 때문이다. 그렇기에 서버는 항상 "권한"을 가지고 요청을 검증하고 결정된 값만 전달한다.
한 대 맞았다고 이렇게 복잡한 과정을 거쳐 많은 이들이 일하게 된다니.. 잡몹한테도 한대 맞기가 두려워 도망다닌 나 덕분에 쓸데없는 에너지 낭비가 일어나지 않은 것 같아서 뿌듯하다.
아직은 잘 모르지만 얼른 배워서 코드만 보고도 무슨 내용인지 다 알 수 있는 수준이 되고싶다는 바람과 열정이 슬쩍 물 들 듯 샘솟는다.
'게임 개발 공부 > 언리얼엔진' 카테고리의 다른 글
| UE5 - Git lfs (0) | 2025.01.07 |
|---|---|
| 언리얼 엔진 5 - 캐릭터 애니메이션 (2) | 2024.12.20 |
| 언리얼 엔진 5 - 블루프린트를 이용한 플레이어 캐릭터 무브먼트 작성 (3) | 2024.12.19 |
| 언리얼 엔진 5 - 블루프린트 기초 (4) | 2024.12.18 |
| 언리얼 엔진 5 - 기본 용어 1 (5) | 2024.12.16 |