Controller에서 레벨을 열거나, UParticleSystemComponent를 사용한 파티클 생성, 월드에 배치되어있는 액터를 검색하기 등등 다양한 경우에서 인스턴스화 하지않은 UGameplayStatics를 사용하게 되었습니다.

게임 프로젝트를 제작하며 계속되서 사용되는 정적으로 사용되는 해당 클래스가 어떠한 기능을 하는지 알아보게되었으며,

학습한 자료들을 이번 포스팅에 작성하겠습니다.

 

UGameplayStatics

  • 게임 플레이 관련 유틸리티 함수를 제공하는 정적(Static) 클래스
    • 유틸리티 기능을 빠르게 호출하며, 대부분 전역적인 게임 월드에 의존한다.
    • 따라서 매번 객체를 만들지 않고 정적 클래스 및 함수로 설계되어 빠르게 호출 할 수 있다.
  • 인스턴스를 생성하지 않고 직접 호출한다.
    • UGameplayStatics::FunctionName()
  • 오디오, 내비게이션, 액터 생성,파괴, 게임 레벨 관리, 데미지/충돌 처리, 세이브/로드 등 게임 제작에 필요한 시스템들을 쉽게 사용할 수 있도록 도와준다.
    • 공통 기능들을 쉽게 호출할 수 있도록 설계된 유틸리티 클래스
  • 엔진의 다양한 시스템과 통합되어있어 AI, UI, Physcis등과 연계가 가능하다.
  • 빠르고 간편하게 사용할 수 있으며, 객체 생성이 불필요하여 메모리 관리 시 용이하다.
    • 동적 환경에서 객체를 만들고 삭제하는 메모리 생성값을 줄여 오버헤드를 줄일 수 있다.
  • 남용하거나 잘못된 사용시 성능적으로 문제가 발생 할 수 있다.
    • Ex) GetAllActorsOfClass : 월드에 배치된 모든 액터들을 검색한다.

 

UGameplayStatics::Function(...)

오디오 / 사운드

  • PlaySoundAtLocation
    • 특정 위치에서 사운드 재생
  • PlaySound2D
    • 2D 사운드 재생
  • SpawnSoundAtLocation
    • 게임 내 특정 위치에 사운드 생성, 재생

 

위치 / 내비게이션

  • GetPlayerPawn
    • 특정 플레이어의 Pawn 반환한다.
  • GetPlayerCharacter
    • 특정 플레이어의 Character 반환한다.
  • GetAllActorsOfClass
    • 특정 클래스의 모든 액터를 반환한다.
  • GetActorOfClass
    • 특정 클래스의 첫번째 액터 반환
  • ProjectPointToNavigation
    • 특정 지점을 내비게이션 메시상의 유효한 위치로 변환한다.

 

액터 생성/ 파괴

  • SpawnActor
    • 게임 월드에 새로운 액터 동적으로 생성
    • GetWorld()->SpawnActor와 동일하다.
    • GetWorld()->SpawnActorDeferred  = BeginDeferredActorSpawnFromClass 
  • DestroyActor
    • 특정 액터 삭제

 

게임 흐름 및 레벨 관리

  • OpenLevel
    • 특정 레벨을 불러온다.
  • GetCurrentLevelName
    • 현재 레벨의 이름을 반환한다.
  • SetGamePaused
    • 게임을 일시정지 / 해제한다
  • SetGlobalTimeDilation
    • 게임의 전체적인 시간의 흐름을 조정한다.

 

데미지 및 충돌처리

  • ApplyDamage
    • 액터에 피해를 가한다.
  • ApplyRadialDamage
    • 특정 반경 내에 있는 모든 액터에 피해를 가한다.
  • ApplyPointDamage
    • 특정 지점에서 한개의 액터에게만 피해를 가한다.

 

카메라 및 뷰 관련 기능

  • GetPlayerCameraManager
    • 특정 플레이어의 CameraManager 반환
  • SetGlobalTimeDilation
    • 전체 게임 속도를 조정하여 슬로우 모션 또는 빠른 진행 효과 연출

 

세이브 / 로드

  • CreateSaveGameObject
    • 세이브 데이터 객체 생성
  • SaveGameSlot
    • 데이터를 특정 슬룻에 저장
  • LoadGameFromSlot
    • 특정 슬룻에서 저장된 데이터를 불러온다.

토이프로젝트를 준비하며 프로젝트 설계시 고려해야하는 부분이 여러가지 있었습니다.

객체 관리, 게임모드, UI 등등 다양한 부분에서 설계를 해야했지만, 게임 장르 및 플레이 타입에 대해 가장 먼저 고민하게 되었습니다.

그 중 멀티플레이를 목적으로한 프로젝트 개발을 결정하게 되었으며, 멀티플레이 환경에서 서버-클라이언트간 어떻게

데이터를 처리하는지에 대해 알아보며 언리얼의 RPC, 리플리케이션, POD 등 다양한 용어들을 학습하게 되었습니다.

그 중 가장 멀티플레이 환경에서 데이터를 동기화하는 방법인 리플리케이션에 대해 알아보도록 하겠습니다.

 

리플리케이션 (Replication)

  • 멀티플레이어 환경을 구축할 때 서버와 클라이언트 간의 데이터를 동기화 하는 기능
  • 서버가 권한(Server Authority)을 가지며, 이를 기반으로 리플리케이션 시스템 사용
    • 게임 서버가 진짜 상태를 결정하고, 이를 클라이언트에 전송하는 방식
    • Ex) Player1 이동 -> 서버 : 이동에 대한 결과 -> Player 2,3,4... 에게 반영 (동기화)
    • 객체의 속성, 위치, 애니메이션 등 필요한 정보를 클라이언트에 전송
    • 클라이언트는 서버의 정보를 기반으로 화면을 업데이트 한다.
    • 해당 과정을 통해 중요한 게임 로직은 서버에서 실행되며, 클라이언트들은 서버에서 데이터를 받아 로컬에서 표시하는 역할을 한다.
  • 리플리케이션은 액터(Actor)를 기준으로  실행된다. 
  • 리플리케이션 대상은 Object, Component, Property, Function이 될 수 있다.
    • Object : 캐릭터, 아이템, 차량 등
    • Component : Mesh, Audio, Collision 등
    • Property : 객체의 위치, 속도, 체력, 점수 등
    • Function(RPC) : 문열기, 공격 이벤트, 총 발사
  • RPC : 데이터 통신
  • Replicated, Replicated Notify : 데이터 복제

 

리플리케이션 설정 방법 ,종류

 

1. 변수 리플리케이션 (Property Replication)

  • UPROPERTY(Replicated) 설정
  • GetLifetimeReplicateProps 함수 내 리플리케이션 변수 등록
  • Replicated Notify 설정

 

// UPROPERTY Replicated

UPROPERTY(Replicated)
int32 PlayerHealth;

// GetLifetimeReplicatedProps

void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(AMyCharacter, PlayerHealth);
}

// Rep Notify
UPROPERTY(ReplicatedUsing = OnRep_PlayerHealth)
int32 PlayerHealth;

UFUNCTION()
void OnRep_PlayerHealth()
{
    // 체력 값이 변경될 때 실행할 로직
}

 

 

2. 함수 리플리케이션 (Func Replication) / RPC(Remote Procedure Call)

  • UFUNCTION(Server/Client/Multicast, Reliable)
    • Server : 서버에서만 실행. (Client -> Server)
      • 공격 요청, 스킬 사용 등의 로직
    • Client : 클라이언트에서만 실행. (Server -> Target Client)
      • HUD 업데이트
    • MultiCast : 서버에서 호출, 모든 클라이언트에 실행 (Server -> All Client)
      • 폭발 이벡트, 애니메이션 재생, 게임 결과 등의 로직
// Server RPC
UFUNCTION(Server, Reliable, WithValidation)
void ServerFire();

// Client RPC
UFUNCTION(NetMulticast, Reliable)
void MulticastExplosion();

// Multicast RPC
UFUNCTION(Client, Reliable)
void ClientShowHUD();

 

 

 

3. 액터 리플리케이션

  • 생성자 { bReplicates = true; , SetReplicateMovement(true);}
    • bReplicates = false시 모든 플레이어가 권한(Authority)를 가지게 되며, 플레이어 1이 이동시 다른 플레이어들도 이동한다.
    • 해당 액터의 Movement를 Replicated하게 해준다.

액터 스폰시 SetReplicates(true);

 

// Constructor Replicated Settings
AMyActor::AMyActor()
{
    bReplicates = true; // 서버가 Authority를 가지게 한다. 서버에 정보를 알리고 모든 Client에 전파할 수 있다.
    SetReplicateMovement(true)  // 해당 액터의 Movement를 Replicated한다.
}

// 액터 스폰시 Replicated
AYourActor::Func()
{
    AMyActor* SpawnedActor = GetWorld()->SpawnActor<AMyActor>(MyActorClass, SpawnLocation, SpawnRotation);
    SpawnedActor->SetReplicates(true);
}

 

 

 

Replicated VS Replicated Notify VS RPC

기능 Replicated Replicated Notify (RepNotify) RPC (Remote Procedure Call)
설명 동기화를 통한 데이터 복제 복제 후 특정 시점에 지정한 함수 호출 즉시 함수 호출, 통신 방식
데이터
변경 방식
서버에서 변경하면 클라이언트가 자동으로 반영 서버에서 변경하면 클라이언트가 반영 + 추가 함수 실행 클라이언트 또는 서버에서 직접 함수 실행
변경 감지 기능   복제된 시점에서OnRep_Func() 호출  
동기화
시점
서버에서 변경되면 다음 네트워크 업데이트 시 자동 동기화 서버에서 변경되면 다음 네트워크 업데이트 시 자동 동기화 후 함수 실행 함수가 호출되는 즉시
사용 예시 플레이어 체력, 점수, 탄약 개수 등 체력 변경 시 UI 업데이트, 특수 효과 실행 공격 실행, 문 열기,
이펙트 재생

 

스파르타 코딩클럽 내 프로젝트를 진행하며 액터를 스폰시키는 프로젝트가 있었습니다.

프로젝트를 진행하며 런타임 환경 내 액터를 스폰시키기위해 SpawnActor함수를 호출하며 동시에 추상클래스를 기반으로 확장성있는 액터 구조를 설계하였지만, 공통 프로퍼티를 설정하던 중 SpawnActor를 사용할 경우 BeginPlay가 바로 호출되어 추가로 설정할 수 없던 문제가 있었습니다.

해당 경우를 해결하기위해 SpawnActorDeferred를 사용하게 되었으며, 이를 계기로 기존의 SpawnActor와의 차이점 및 특징에 대해 알아보겠습니다.

 

SpawnActor + 오브젝트 생성

 

SpawnActorDeferred<T>

  • 기존의 SpawnActor은 액터가 생성되며, 즉시 BeginPlay()가 실행된다.
  • 생성된 액터에 추가적인 설정을 적용하며, FinishSpawning()을 호출하여 액터를 생성 할 수 있다.
  • 생성하는 액터에 대해 컴포넌트 및 프로퍼티들을 추가/변경이 가능하다.
  • Spawn시킨 후, 작업(추가적인 설정) 진행 후 FinishSpawning()을 사용한 BeginPlay()를 실행하는 구조.
  • Parameters
    • UClass* class : 생성할 액터 클래스
    • FTransform const& Transform : 액터의 초기 위치 및 회전 값
    • AActor* Owner = nullptr : 생성된 액터의 소유자(Owner)
    • APawn* Instigator : 생성된 액터의 행위자(Ex) 공격을 가한 Pawn)
    • ESpawnActorCollisionHandlingMethod CollisionHandlingOverride : 충돌 시 스폰 방식 설정
      • AlwaysSpawn : 충돌 여부와 상관없이 무조건 스폰
      • AdjustIfPossibleButAlwaysSpawn : 충돌 위치를 조정하고 무조건 스폰
      • AdjustIfPossibleButDon'tSpawnIfColliding : 충돌된 위치를 조정, 그래도 충돌시 스폰하지 않는다.
      • DontSpawnIfColliding : 충돌하는 경우 스폰하지 않는다.

 

예시코드

void AMoveActorSpawner::SpawnActorSettingWithRand(TSubclassOf<AMoveActorBase>& SpawnData)
{
	AMoveActorBase* SpawnActor = GetWorld()->SpawnActorDeferred<AMoveActorBase>(SpawnData, FTransform(FRotator::ZeroRotator, FVector::ZeroVector), this, nullptr,
		ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn);

	if (SpawnActor)
	{
		// ..액터 생성 전에 확인하고 싶은 로직
		// .. 추가 설정하고 싶은 로직
		SpawnActor->FinishSpawning(FTransform(FRotator::ZeroRotator, FVector::ZeroVector));
	}
}

 

 

FActorSpawnParameters

  • SpawnActorDeferred/SpawnActor에서 스폰 관련 옵션을 설정 할 수 있는 구조체
  • SpawnActor를 사용하여 지연시 Timer 또는 FActorSpawnParameters 내 bDeferConstruction = true 방식을 통해 스폰을 지연 시킬 수 있다.
  • SpawnActor + bDeferConstruction = true가 SpawnActorDeferred.

 

+ Recent posts