본격적인 온라인 환경에 들어가기 앞서, LAN 즉, 근거리 통신망에서 접속을 먼저 해보며 언리얼 엔진의 C++ 코드와 이를 블루프린트에서 활용하는 방법을 알아본다.
LAN 환경에서 게임에 접속하기 위해서는
1. 접속시 들어갈 맵(레벨)
2. 들어갈 맵을 이용할 IP 주소가 필요하다.
이를 블루프린트로만 구현하면 다음과 같다.
맵을 여는 방법에는 Open Level에서 by name과 by object reference로 나누어진다. 이는 맵을 열 때 이름으로 열 것인지, 아니면 에셋을 정해두고 해당 에셋을 열지 결정한다. 그리고 2번 키를 누르면, Console Command가 작동하는데, 여기에서 Open IP Address를 통해 해당 아이피에 접속한다.
언리얼을 이용하여 게임을 개발할 때 개발자가 처음 마주하게 되는 생각은 '이 게임을 블루프린트로 만들 것인가 아니면 C++로 만들것인가?'이다. 물론, 적재적소에 활용하는 것이 가장 좋지만, 개발 초기에 블루프린트를 이용하여 대략적인 게임을 작성해보고 C++로 기능을 확장하며 개발하는 방식도 생각해볼만하다.
이제 BP로 구현해 본 기능을 C++로 구현하고, 테스트 해보자.
ThirdPerson C++ Character 클래스에 다음과 같이 코드를 추가한다. (캐릭터 클래스에 추가하는 이유는, 단순 테스트 목적으로 플레이어의 컨트롤을 바로 받을 수 있으며 게임에 반드시 추가되기 때문이다.)
먼저 헤더파일에서는 각 함수를 UFUNCTION(BlueprintCallable)로 선언하여, BP에서 해당 함수들을 사용할 수 있게 하였다. OpenLobby의 경우, 정해진 맵을 여는 것이기 때문에 별다른 파라미터를 가지지 않지만, CallOpenLevel과 CallClientTravel은 Address, 즉 IP 주소가 필요하여 파라미터로 선언하였다.
OpenLevel과 ClientTravel의 차이는
OpenLevel의 경우 UGameplayStatics를 상속받는 함수로, 게임의 맵 혹은 레벨을 완전히 새로 열거나 싱글플레이 혹은 Server-side 멀티플레이 게임에서 사용한다.
ClientTravel의 경우 APlayerController를 상속받는 함수로, 클라이언트가 레벨이나 서버를 네트워크 상에서 이동할 때 사용하며, 대부분의 멀티플레이 방식에서 사용한다.
Feature | UGameplayStatics::OpenLevel | APlayerController::ClientTravel |
Call Type | Server-side (usually) | Client-side |
Use Case | Full level reload (single-player or multiplayer server) |
Client map/server travel (multiplayer client) |
Resets Game State | Yes ( The entire game state is reset and reloaded ) |
Not necessarily (can travel while keeping certain persistent data) |
Multiplayer Server Travel | Typically server-driven | Client-driven or server-to-server transitions |
Single Player Use | Common | Rare |
OpenLobby를 먼저 보게 되면, 레벨을 변경하기 위해서는 UWorld의 ServerTravel 함수를 사용해야 한다. 따라서 다음과 같이 UWorld라는 포인터를 생성하고, 여기에 GetWorld()를 통해 현재 월드에 대한 정보를 포인터로 저장한다.
그리고, 만일 월드가 정상적으로 작동되고 있다면(생성되어 있다면) ServerTravel을 통해 새로운 레벨을 열게된다.
여기에서 맵의 이름에 ?listen을 추가함으로써, 해당 맵은 Listen 서버 형식으로 열리게 된다.
다음으로 살펴볼 함수는 CallOpenLevel과 CallClientTravel이다.
아래 링크의 API를 참조해보면 알 수 있지만, 두 함수 모두 IP 주소를 요구한다. 따라서 파라미터로 Address 값을 받아와야 한다. FString은 언리얼에서 제공하는 String 클래스이다. 여기에서 const 키워드를 붙여줌으로써, 해당 IP 주소의 변경을 방지하였다. 참조 형식으로 전달하는 이유는 보통 Address는 긴 편인데, 이를 참조로 보내지 않을 경우 해당 문자열을 복사하여 파라미터로 보낸다. 반면 참조로 보낼 경우 주소만 보내면 해결되므로 최적화의 측면에서 이렇게 사용하였다.
OpenLevel은 다음과 같은 파라미터를 요구한다.
WorldContextObject는 레벨을 열 때 컨텍스트를 제공하는 UObject로, 보통 this를 사용한다.
WorldContextObject는 쉽게말해, World의 존재하는 객체로, 이는 UGameplayStatics에서 해당 WorldContextObjet를 통해 World를 찾게 해준다.
LevelName은 열고자 하는 레벨의 이름을 말하며,
bAbsolute는 절대 레벨 변경 여부를 나타내는 부울 값으로 기본값은 true이다.
마지막으로 Options는 레벨을 열 때 추가적으로 설정할 수 있는 옵션으로 기본값이 빈 문자열로 설정되어 있다.
따라서 앞의 다음의 코드는
UGameplayStatics::OpenLevel(this, *Address);
다음과 같이 해석되어 전달된다.
UGameplayStatics::OpenLevel(this, *Address, true, FString());
계속해서 CallClientTravel을 보자.
위 API에서도 나와있듯이, ClientTravel은 PlayerController 엑터를 상속받는다. 따라서, 먼저 PlayerController를 받아올 필요가 있다.
APlayerController 포인터를 선언하고 여기에 게임인스턴스의 첫 번째 플레이어(본인)의 플레이어 컨트롤러를 받는다.
그리고 이 플레이어 컨트롤러가 유효할 경우, 해당 플레이어 컨트롤러(본인)을 ClientTravel을 통해 Address로 보낸다.
(생략된 것들은 앞선 경우와 동일하게 파라미터 기본값이 존재한다. 직접 API를 보고 생각해보자)
TRAVEL_Absolute에는 Enum Type의 다양한 Travel Type이 들어간다.
enum ETravelType
{
TRAVEL_Absolute,
TRAVEL_Partial,
TRAVEL_Relative,
TRAVEL_MAX,
}
이는 위와 같으며, 추후 자세히 다룰 예정이다.
이렇게 구현한 코드를 블루프린트에서는 다음과 같이 호출이 가능하며,
이를 사용하여 PC와 노트북을 이용해 접속한 결과는 다음과 같다.
'Study > Unreal Engine' 카테고리의 다른 글
[Tips] Delegate (0) | 2024.10.20 |
---|---|
[Tips] TSharedPtr (0) | 2024.10.20 |
[UE5 C++ Multiplayer Shooter] #04 Session Interface Create & Join (0) | 2024.10.20 |
[UE5 C++ Multiplayer Shooter] #03 Online Subsystem 과 Online Subsystem Steam (0) | 2024.10.20 |
[UE5 C++ Multiplayer Shooter] #01 언리얼 엔진의 프레임 워크와 기초 그리고 네트워크 (0) | 2024.10.19 |