로비 관련 코드 개념

개발하는 운동인·2025년 3월 26일

기초 함수 설명 - 1

private async void Start()
{
	await UnityServices.InitializeAsync(); //유니티 서비스 초기화
    
    //로그인이 완료 될 때 이벤트 수신 
    AuthenticationService.Instance.SignedIn += () =>
    {
    	Debug.Log("로그인 " + AuthenticationService.Instance.PlayerId);
    };
    
    await AuthenticationService.Instance.SignInAnonymouslyAsync();// 익명 사용자 로그인 
}
    1. UnityServices.InitializeAsync() : 유니티에서 제공하는 서비스를 사용하기 위해 먼저 초기화 해야 함. 비동기(await)로 실행되므로 초기화가 완료 될 때까지 기다려야 함 .
  • Why? 유니티 서비스가 초기화 되지 않으면 로그인 기능을 사용할 수 없기 때문임. 초기화가 완료 되어야 로그인 했을 때 문제가 없으므로 비동기로 실행 해야 함.

    1. AuthenticationService.Instance.SignedIn += () => { ... }
      : 로그인 완료 시, 실행할 이벤트를 등록
  • why? 로그인 성공 여부를 확인하고, 현재 로그인한 플레이어 정보를 얻기 위함.

    1. await AuthenticationService.Instance.SignInAnonymouslyAsync()
      : 익명 로그인을 시도
  • why? 별도의 계정 없이도 빠르게 로그인할 수 있도록 하기 위함.(테스트용, 간편한 접속)

로비 만들기

private async void CreateLobby()
{
// 로비를 만들 수 없거나 로비 서버에 연결할 수 없는 경우 예외를 던질 수 있다. 이 예외를 발견하지 못하면 전체 게임이 중단 되므로 try-catch 사용
	try 
	{
    	string lobbyName = "MyLobby";
    	int maxPlayers = 4;
		Lobby lobby = await 			LobbyService.Instance.CreateLobbyAsync(lobbyName,maxPlayers); //로비 이름과 최대 플레이어 수 설정
    
    Debug.Log("로비 생성!! " + lobby.Name + " " + lobby.MaxPlayers);
	}
	catch(LobbyServiceException e)
    {
    	Debug.Log(e);
    }
}
    1. try - catch : 로비 생성과정에서 오류 발생 가능(서버 문제, 네트워크 불안정, 허용된 로비 개수 초과 )
  • why? 오류를 처리하지 않으면 게임이 강제 종료될 수 있기 때문

    1. LobbyService.Instance.CreateLobbyAsync(lobbyName, maxPlayers) : 지정한 이름(lobbyName)과 최대 인원(maxPlayers) 으로 새로운 로비 생성
  • why? 멀티 게임에서 플레이어들이 모일 공간(로비)가 필요하므로.

로비 검색

private async void ListLobbies()
{
	//로비 내부로 이동하여 정적 인스턴스에 액세스 
  QueryResponse queryResponse =  await Lobbies.Instance.QueryLobbiesAsync(); //매개변수 비워 두면 로비에서만 반환.
  
  Debug.Log("여러 로비 검색 : 갯수 = queryResponse.Results.Count) ;//로비 내부로 들어가서 찾은 모든 결과가 포함된 로비 목록
  
  foreach(Lobby lobby in queryResponse.Results)
  {
  		Debug.Log("순회 중 ! 로비 이름 : lobby.Name + " " + " 로비 최대 플레이어 수 : " + lobby.MaxPlayers);
  }
}
    1. QueryResponse queryResponse = await Lobbies.Instance.QueryLobbiesAsync();
      : 현재 존재하는 로비 목록을 요청하고 응답을 queryResponse에 저장
  • why? 멀티플레이어 게임에서는 기존 로비에 참가할 수 있어야 하기 때문임

    1. Debug.Log("여러 로비 검색 : 갯수 = " + queryResponse.Results.Count);
      : 검색된 로비 개수 출력
  • why? 사용자가 선택할 수 있는 로비가 얼마나 있는지 확인하기 위함

    1. foreach (Lobby lobby in queryResponse.Results) { ... }
      : 검색된 로비들을 하나씩 순회하며 출력
  • why? 플레이어가 원하는 로비를 선택할 수 있도록 리스트를 제공해야 하기 때문

로비 살아있게 만들기

  • 이 코드는 게임에서 로비의 "살아있음"을 유지하기 위해 사용됩니다. 로비가 살아있게 유지되지 않으면, 플레이어가 로비를 떠나게 될 수 있습니다.
  • 예를 들어, 서버나 로비 시스템에서 일정 시간 동안 아무런 활동이 없으면 로비가 자동으로 종료되거나 비활성화될 수 있습니다. 이를 방지하기 위해 주기적으로 서버에 "heartbeat ping"을 보내 로비가 활성 상태로 유지되도록 합니다.
    private void Update()
    {
        HandleLobbyHeartbeat();
    }

    private async void HandleLobbyHeartbeat()
    {
        if(hostLobby != null)
        {
            heartbeatTimer -= Time.deltaTime;

            if(heartbeatTimer < 0f)
            {
                float heartbeatTimerMax = 15f;
                heartbeatTimer = heartbeatTimerMax;

               await LobbyService.Instance.SendHeartbeatPingAsync(hostLobby.Id); //로비 내부로 들어가서 로비를 살아있게 만들기 위해서 작성
            }
        }
    }
  • HandleLobbyHeartbeat () 는 비동기적으로 실행됩니다 (async와 await 사용).
  • hostLobby != null 조건은 로비 객체가 null이 아닌 경우에만 코드가 실행되도록 합니다. 즉, 로비가 있을 때만 heartbeat ping을 보냅니다.
  • await LobbyService.Instance.SendHeartbeatPingAsync(hostLobby.Id);는 로비 서비스 인스턴스의 SendHeartbeatPingAsync 메서드를 호출하여, 서버에 "heartbeat ping"을 보냅니다. 이는 로비가 살아있다는 신호를 보내 서버가 해당 로비를 종료하지 않도록 합니다.

호스트 - 클라이언트 접속 부분

  • 위 과정들을 테스트 하려면, 서버로 접속해야 한다.
    1. 테스트를 위해 해당 버튼들로 나눈다.
    1. TestLobbyTutorial 스크립트에 코드를 작성한다. 다음 코드는 호스트 접속과 클라이언트 접속 관련 코드이다.
    [ServerRpc(RequireOwnership = false)] // ServerRpc는 동기 메서드여야 함
    private void CreateLobbyServerRpc()
    {
        // 비동기 작업을 별도의 메서드로 분리하여 처리
        Debug.Log("로비 생성 서버로 호출");
        CreateLobbyAsync();
    }

    [ServerRpc(RequireOwnership = false)]
    private void ListLobbiesServerRpc()
    {
        // 비동기 작업을 별도의 메서드로 분리하여 처리
        Debug.Log("로비 조회 서버로 호출");
        ListLobbiesAsync();
    }

    public void OnCreateLobbyButtonClicked()
    {
        Debug.Log("로비 생성");
        CreateLobbyServerRpc(); // 서버로 로비 생성 요청
    }

    public void OnListLobbiesButtonClicked()
    {
        Debug.Log("로비 조회");
        ListLobbiesServerRpc(); // 서버로 로비 리스트 조회 요청
    }

버튼을 통해 ServerRpc로 서버에 정보를 전달하는 코드이다.

하지만, 호스트 - 클라이언트 접속 관련 코드가 없어서 SeverRpc로 정보 전달이 되지 않는다.

    1. TestNetworkManager 스크립트 생성 후 접속 관련 코드를 작성한다.
    1. 캔버스에 부착한다.

실행 결과 - 성공

로비에 참가

    private async void JoinLobby()
    {
        try
        {
            QueryResponse queryResponse = await Lobbies.Instance.QueryLobbiesAsync(); // 로비 목록 조회

           await Lobbies.Instance.JoinLobbyByCodeAsync(queryResponse.Results[0].Id); //참가 코드로 로비에 가입할 수 있음.
        }
        catch (LobbyServiceException e)
        {
            Debug.Log(e);
        }

     
    }
    1. QueryResponse queryResponse = await Lobbies.Instance.QueryLobbiesAsync();
      : 현재 존재하는 로비 목록을 요청하고 응답을 queryResponse에 저장

Why? 멀티플레이어 게임에서는 기존 로비에 참가할 수 있어야 하기 때문임. 서버에서 존재하는 로비 목록을 조회하여 사용자가 참가할 수 있는 로비를 선택할 수 있도록 해야 함.

    1. await Lobbies.Instance.JoinLobbyByCodeAsync(queryResponse.Results[0].Id);
      : 조회한 로비 목록 중 첫 번째 로비의 ID를 사용하여 해당 로비에 참가.

Why? 사용자가 특정 로비에 참가하려면 로비의 ID가 필요함. 첫 번째 로비를 참가하는 예시로 코드가 작성되었음. (실제 앱에서는 사용자가 로비를 선택하게 됨)

    1. catch (LobbyServiceException e)
      : 로비 조회 또는 참가 중 예외가 발생하면 해당 예외를 처리하여 로그로 출력.

Why? 네트워크 요청에서 오류가 발생할 수 있기 때문에 예외를 처리하여 게임이 멈추지 않고 오류 메시지를 출력하여 디버깅을 용이하게 해야 함.

로비를 공개 or 비공개

  • 기존 로비를 생성하는 메서드에 다음 코드를 추가한다.

  • 생성될 때 비공개 로비를 만드는 것이다.

  • 실행 결과 - 비공개 로비를 만들었기 때문에 로비 목록을 조회해도 조회되질 않는다.

lobby.id

  • 설명: lobby.Id는 로비를 고유하게 식별하는 내부 식별자입니다. 이 값은 서버 측에서 로비를 추적하기 위해 사용되며, 보통 게임의 서버나 서비스에서 로비를 참조하는 데 사용됩니다.

lobby.LobbyCode

  • 설명: lobby.LobbyCode는 로비 참가 코드입니다. 이 값은 사용자가 로비에 참가할 때, 일반적으로 다른 플레이어와 공유할 수 있는 공유 가능한 코드입니다.

lobby.id는 상대적으로 문자열이 길어서 lobby.LobbyCode를 사용하여 비공개 로비에 가입할 수 있게 누구에게나 참가 코드를 보낼 수 있음

조회한 로비 목록 중 첫 번째 로비의 ID를 사용하여 해당 로비에 참가하는 것이 아닌 다른 방법

0개의 댓글