3 분 소요

Intro

게임의 대부분은 멀티플레이를 지원한다.

꼭 멀티가 아니더라도, 랭킹과 같은 시스템에서 다른 플레이어와 같은 요소를 공유하게된다.

이번 포스팅에서는 유니티에서 멀티를 구현하는 방법에 알아보았다.


멀티플레이 환경을 구축하기 위해서는 “서버”가 필요하다.

서버를 구축하고 유지하는데 드는 비용은 개인이 부담하기 어렵기에, 서버를 빌려주는 여러 플랫폼을 사용한다.

유니티에서 사용하는 대표적인 플랫폼은 “Photon”“Mirror”이다.

여기에서는 Photon을 활용해보려고한다.

다운로드

에셋 스토어에서 다음 에셋을 다운로드한다.

무료버전과 유료버전이 있는데,

무료버전은 최대 20명, 유료버전은 최대 100명까지 입장할 수 있다고한다.

유료버전 Photon Unity NetWorking

무료버전 Photon Unity NetWorking

세팅

Package Manager 에서 다운로드 받은 PUN2를 프로젝트에 임포트한다.

image

PUN Setup 창이 나오는데, 여기에 AppId를 넣어주어야한다.

AppId는 아래 사이트에서 발급받으면된다.

Photon Engine Site

간단한 회원가입을 진행한 뒤 아래의 새 어플리케이션 만들기를 클릭한다.

image

그럼 아래 화면으로 이동하는데

image

  • Photon 종류를 “PUN” 으로 해준다. Photon Unity Networking의 약자로, 유니티에 최적화 되어있다.

  • 애플리케이션 이름은 현재 진행중인 프로젝트의 이름을 기입하면된다.

  • URL은 현재 프로젝트 홈페이지 주소를 넣어주면된다. 없으면 안넣어도된다.

image

작성하기를 누르면 내가만든 Pun 애플리케이션을 확인할 수 있고, AppID 부분이 보일것이다.

이 AppID를 PUN Setup 창에 기입해주자.

image

이후 SetUp Project를 누르면 세팅은 완료가된다.

Server Settings

[Windows] - [Photon Unity Networking] - [Highlight Server Settings] 에서

PhotonServerSettings 파일을 볼 수 있다.

image

기본값 그대로 사용해도 되지만, 서버를 커스터마이징 하고싶다면 건드리면된다.


  • App ID PUN/Chat : AppID들은 각 게임 타이틀을 구분하기 위해 Photon Cloud에 의해 사용된다.
    • PUN 연결을 위해 AppId를 사용한다.
  • App Version : App Version은 게임 버전의 일부분이다.
    • 다른 게임 버전 값을 가지고 있는 클라이언트들은 서로 분리된다.
  • Use NameServer : 이전 Photon 서버 인스턴스에 연결할 때, 클라이언트는 네임 서버 대신 마스터 서버에 직접 연결한다. 이 값은 그자체로 호스팅을 할 경우에만 체크를 해제한다.

  • Fixed Region : Cloud에 연결할 때 PUN은 기본값으로 최적의 지역을 선택한다.
    • 특정 지역으로 연결이 필요할 때 지역코드를 입력하면 최적 지역 선택는 꺼진다.
  • Server : 자체 Photon 서버를 호스팅할 때 사용하는 옵션.
    • Phonton Server SDK를 다운받고, 클라이언트를 직접 마스터 서버에 접속시키기 위해 Use NameServer 옵션을 해제한다.
  • Port, Protocol : Photon은 하나의 세션에 여러개의 서버를 사요하기 위해 구축되었다.
    • Photon Cloud에 연결한다면 이 값을 0으로 두어야한다.
    • Protocol의 기본값은 UDP(신뢰할 수 있는 프로토콜) 이지만 TCP와 WebSockets를 지원한다.
    • UDP 권장
  • Lobby Statistics : 로비 통계를 받기위한 옵션

  • Networking Logging : 저수준 Photon 코드의 로깅을 제어.
    • 필요한 경우가 아니라면 Error로 설정
  • Support Logger : 연결, 매치메이킹 또는 룸에서 발생하는 작업을 추적할 때 사용.
    • 이 옵션을 선택하면 스크립트가 콜백에 등록되고 게임 디버깅에 도움이되는 중요 정보를 기록한다.
  • Run In Background : 애플리케이션이 백그라운드에 있을 때 플레이어가 실행되어야 하는지 여부 결정

  • RPC 목록 : 룸 내의 다른 클라이언트 상의 메소드를 호출 할 수 있도록 해준다.

사용방법

PUN2 에셋을 임포트하면 프로젝트 폴더에 “Photon” 폴더가 생성된다.

이 폴더 안에는 Photon 라이브러리 코드와 샘플 코드가 들어있다.

먼저, Photon의 동작 원리는 다음과 같다.


  1. Photon Cloud 서버에 접속한다.
    • Photon Cloud는 플레이어간 데이터를 중계하는 서버다.
    • Master Server는 접속 및 로비, 룸 목록을 관리한다.
  2. 로비에 입장한다.
    • 로비는 플레이어들이 대기하는 가상의 공간이다.
    • 방을 생성하거나 참가할 수 있는 곳이다.
  3. 방(Room)을 생성하거나 참가한다.
    • 플레이어들이 실제로 게임을 하는 공간이다.
    • 데이터를 주고받는 실질적인 단위.
  4. Room 안에서 플레이어 간의 데이터를 동기화한다.
    • 플레이어는 각 클라이언트를 대표하는 Photon의 플레이어 객체다.
    • Player Id, Actor Number 등으로 관리된다.


서버접속


서버에 접속하는 방법은 간단하다.

PhotonNetwork.ConnectUsingSettings();

위 코드를 Start 또는 Awake 함수에서 호출하면 Photon Cloud 서버에 접속할 수 있다.

기본 설정이라면 자동으로 로비에 입장된다.

public override void OnJoinedLobby()
{
    Debug.Log("로비 입장 성공");
    
    RoomOptions rm = new RoomOptions();
    rm.MaxPlayers = 2;
    PhotonNetwork.JoinOrCreateRoom("My Room", rm, TypedLobby.Default);
}

OnJoinedLobby() 함수는 로비에 입장하면 실행되는 함수이다.

로비에 입장하면 방에 접속하거나, 방을 만들어야한다.

PhotonNetwork.CreateRoom("RoomName", roomOptions, TypedLobby.Default);  // 방 생성

PhotonNetwork.JoinRoom("RoomName"); // 방 입장 시도

방을 만들땐 방이름, 옵션, 타입을 정해 생성하고(방은 각기 다른 이름으로)

방에 접속할 때는 방이름으로 접속한다.

이 두가지를 합친것이 JoinOrCreateRoom() 함수이다.

방이 존재한다면 Join, 없다면 Create 한다.

아래는 네트워킹을 관리하는 NetWorkManager 클래스 예시이다.

using Photon.Pun;       // PUN2 핵심 네임스페이스
using Photon.Realtime;  // 룸, 로비, 플레이어 관리용

public class NetworkManager : MonoBehaviourPunCallbacks
{
    void Start()
    {
        PhontonNetwork.ConnectUsingSettings();  // 서버 접속
    }

    // 로비 참가 함수
    public override void OnJoinedLobby()
    {
        Debug.Log("로비 접속 완료!!");

        RoomOptions rm = new RoomOptions();
        rm.MaxPlayers = 2;  // 최대 플레이어 설정
        PhotonNetwork.JoinOrCreateRoom("New Room", rm, Typedlobby.Default); // 룸 생성 또는 참가
    }

    // 룸 참가 함수
    public override void OnJoinedRoom()
    {
        Debug.Log("방 입장 완료!!");
        
        // 플레이어 프리팹 생성
        PhotonNetwork.Instantiate("PlayerPrefab", Vector3.zero, Quaternion.identity);
    }
}

태그: ,

카테고리:

업데이트:

댓글남기기