ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 유니티 스팀 멀티 연동하기 - 2. 로비
    Unity 2023. 10. 13. 21:00
    728x90

    [유니티 스팀 멀티 연동하기 - 1. 사전 설정]

     

     

    앞서 사전 설정을 완료했다면 다음은 로비의 구현이다.

    로비를 구현하려면 관리할 매니저 클래스가 필요한데, 그냥 NetworkManager를 수정할 수는 없으니, NetworkManager를 상속받은 클래스를 하나 만들도록 한다.

    기본 형태는 다음과 같다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Mirror;
    using Steamworks;
    using UnityEngine.SceneManagement;
     
    public class CustomNetworkManager : NetworkManager
    {
        [SerializeField]
        private PlayerObjectController GamePlayerPrefab;
     
        public List<Player Object Controller> GamePlayers { get; } = new List<PlayerObjectController>();
     
        //서버에 사람 추가될 때
        public override void OnServerAddPlayer(NetworkConnectionToClient conn)
        {
            //base.OnServerAddPlayer(conn);
            if(SceneManager.GetActiveScene().name == "Lobby")
            {
                PlayerController GamePlayerInstance = Instantiate(GamePlayerPrefab);            
                GamePlayerInstance.ConnectionID = conn.connectionId;
                GamePlayerInstance.PlayerIdNumber = GamePlayers.Count + 1;
                GamePlayerInstance.PlayerSteamID = (ulong)SteamMatchmaking.GetLobbyMemberByIndex((CSteamID)SteamLobby.Instance.CurrentLobbyID, GamePlayers.Count);
     
                NetworkServer.AddPlayerForConnection(conn, GamePlayerInstance.gameObject);
            }
        }
     
        //로비와 게임이 씬이 같지 않을 경우라면 사용
        public void StartGame()
        {                
            ServerChangeScene(Constant.SCENE_GAME);
        }
     
        //클라이언트가 연결 끊겼을 때
        public override void OnClientDisconnect()
        {
            base.OnClientDisconnect();
        }
     
        //서버가 연결 끊겼을 때
        public override void OnServerDisconnect(NetworkConnectionToClient conn)
        {
            base.OnServerDisconnect(conn);
        }
    }
    cs



    이것을 베이스로 현재 진행하고 있는 프로젝트에 맞춰 수정해야 한다.

    GamePlayerInstance 부분에서 오류가 날텐데, 아래 내용에서 PlayerObjectController 스크립트 작성 후에 해결될 것이다.

    이 글에 사용된 예시 프로젝트는 로비와 게임 씬이 일체형인 프로젝트기 때문에 일체형이 아니라면 수정이 반드시 필요하다.
    작성을 완료했다면 NetworkManager 같은 이름으로 게임오브젝트를 하나 만들고, 스크립트를 컴포넌트로 추가한다.
    추가 후, FizzySteamworks도 컴포넌트로 같이 추가해둔다.





    로비에 입장하면, 각 클라이언트를 구분하기 위해서라도 각각 하나의 게임오브젝트가 필요하다.
    스크립트상 플레이어 게임오브젝트의 생성은 GamePlayerPrefab이 대신하고 있다.
    적당히 빈 게임오브젝트에 Network Identity 컴포넌트를 추가한 프리팹을 만들고(컴포넌트를 추가하지 않으면 할당이 안 된다), Player Prefab이라고 적힌 곳에 넣어둔다.
    대신 Game Player Prefab이라고 적힌 곳에 플레이어 게임오브젝트로 사용할 프리팹을 넣는다.

    Registered Spawnable Prefabs에도 등록해둔다.

    플레이어 게임오브젝트로 사용할 프리팹은 Network Identity 컴포넌트가 필수로 들어가야 한다.

    플레이어 게임오브젝트의 자세한 작성 방법은 다음 글에서 다루도록 한다.

    우선은 테스트하려면 칸을 비워둘 수 없기 때문에, 이름을 PlayerObject로 지어두고 프리팹으로 만든다.

    Network Identity 컴포넌트를 넣어준다.

    다음으로 PlayerObjectContoller 스크립트를 넣어줘야 한다.

    내용은 MonoBehaviour 대신 NetworkBehaviour를 상속받도록 바꿔주고, 아래 사진의 세 개의 변수를 작성한다.

    그리고 NetworkManager를 받아올 Manager 변수와, 2개의 메소드를 추가해둔다.

    Start()에는 DontDestroyOnLoad(this.gameObject); 만 추가해주어도 된다.

     

     

        private CustomNetworkManager manager;
        private CustomNetworkManager Manager
        {
            get
            {
                if (manager != null)
                {
                    return manager;
                }
                return manager = CustomNetworkManager.singleton as CustomNetworkManager;
            }
        }
        public override void OnStartClient()
        {
            Manager.GamePlayers.Add(this);
        }
    
        public override void OnStopClient()
        {
            Manager.GamePlayers.Remove(this);
        }

     

     

     

    다음으로는 실제로 로비의 작동을 담당할 클래스이다.

    이름을 SteamLobby로 짓고 다음과 같이 작성한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using Mirror;
    using Steamworks;
    using UnityEngine.UI;
    using System;
     
    public class SteamLobby : MonoBehaviour
    {
        public static SteamLobby Instance;
     
        protected Callback<LobbyCreated_t> LobbyCreated;
        protected Callback<GameLobbyJoinRequested_t> JoinRequest;
        protected Callback<LobbyEnter_t> LobbyEntered;
     
        public ulong CurrentLobbyID;
        private const string HostAddressKey = "CustomHostAddress";
        private CustomNetworkManager manager;
     
        private void Start()
        {
            if (!SteamManager.Initialized)
                return;
     
            if (Instance == null)
                Instance = this;
     
            manager = GetComponent<CustomNetworkManager>();
     
            LobbyCreated = Callback<LobbyCreated_t>.Create(OnLobbyCreated);
            JoinRequest = Callback<GameLobbyJoinRequested_t>.Create(OnJoinRequest);
            LobbyEntered = Callback<LobbyEnter_t>.Create(OnLobbyEntered);
        }
     
        //버튼 등으로 로비 호스트할 때 실행
        public void HostLobby()
        {
            SteamMatchmaking.CreateLobby(ELobbyType.k_ELobbyTypeFriendsOnly, manager.maxConnections);
        }
     
        //로비가 생성되었을 때 콜백
        private void OnLobbyCreated(LobbyCreated_t callback)
        {
            if (callback.m_eResult != EResult.k_EResultOK)
                return;
     
            Debug.Log("로비 생성 성공");
     
            manager.StartHost();
     
            SteamMatchmaking.SetLobbyData(new CSteamID(callback.m_ulSteamIDLobby), HostAddressKey, SteamUser.GetSteamID().ToString());
            SteamMatchmaking.SetLobbyData(new CSteamID(callback.m_ulSteamIDLobby), "name", SteamFriends.GetPersonaName().ToString() + "'s Lobby");
     
        }
        
        //로비 참여 시 콜백
        private void OnJoinRequest(GameLobbyJoinRequested_t callback)
        {
            Debug.Log("로비 참여 요청");
            SteamMatchmaking.JoinLobby(callback.m_steamIDLobby);
        }
     
        //로비 입장 시 
        private void OnLobbyEntered(LobbyEnter_t callback)
        {
     
            CurrentLobbyID = callback.m_ulSteamIDLobby;
     
            if (NetworkServer.active)
                return;
     
            manager.networkAddress = SteamMatchmaking.GetLobbyData(new CSteamID(callback.m_ulSteamIDLobby), HostAddressKey);
     
            manager.StartClient();
        }
        
    }
     
    cs


    만든 후, NetworkManager 게임오브젝트에 이것 역시 같이 컴포넌트로 추가한다.

     

    여기까지 작성한 후 테스트 시 HostLobby()를 실행하면, 로비가 성공적으로 생성되었을 때 친구 초대 및 초대받은 친구의 로비 참여가 가능하다.

    접속이 잘 되는지 테스트를 위해 플레이어 게임오브젝트에 Sprite Renderer를 넣고, 임의의 스프라이트를 하나 넣어두면 좋다.

     

    테스트 하는 방법은 아래의 링크를 참조하면 된다.

     

     

     

    728x90

    댓글

Designed by Tistory.