일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Photon Fusion
- meta
- 길건너 친구들
- 가상현실
- 멀티플레이
- input system
- 팀 프로젝트
- XR
- 유니티 GUI
- 앱 배포
- VR
- CGV
- 유니티
- 포트폴리오
- 모작
- 드래곤 플라이트 모작
- 팀프로젝트
- Oculus
- 개발
- 유니티 Json 데이터 연동
- 개발일지
- 오큘러스
- HAPTIC
- 오브젝트 풀링
- 유니티 UI
- meta xr
- 드래곤 플라이트
- ChatGPT
- OVR
- 연습
- Today
- Total
EasyCastleUNITY
CGV 개발일지 6 (멀티, 랜덤한 방 번호 만들기) 본문
Photon Fusion 세팅
기존에 자주 사용되던 Pun이 Legacy가 됨에 따라, 최근 Photon 측에서 밀고 있는 Fusion을 통해 멀티를 구현해보고자 합니다.
먼저 Photon Fusion 환경을 세팅해보겠습니다.
위 링크로 들어가 상단의 SDK를 클릭합니다.
위 사진처럼 설정하고
Get Fusion SDK 버튼을 클릭합니다.
클릭하여 넘어가면
위와 같은 화면이 나오고, 해당 sdk를 다운로드 합니다.
그리고 다운 받은 SDK를 유니티 프로젝트에 Import 합니다.
Import를 마치면, 위 사진 처럼 Fusion Hub 창이 생기는데,
이 창에서, 자신이 만든 Fusion APP id를 등록하여 사용하면 됩니다.
앱을 만드는 방법은,
https://www.photonengine.com/ko-kr
로 들어가, 로그인 한 다음
관리화면으로 이동을 클릭하면
위와 같은 창이 나오고, 새 애플리케이션 만들기를 누른다음,
위 사진처럼 Photon 종류를 Fusion을 선택하고 애플리케이션 이름을 작성하고 작성하기 버튼을 클릭합니다.
그러면
위 사진처럼 App이 만들어지게 됩니다. 이 app의 id를 복사하여 Fusion Hub의 Setup에 붙여넣으면 fusion 세팅이 완료됩니다.
https://doc.photonengine.com/ko-kr/fusion/current/tutorials/host-mode-basics/2-setting-up-a-scene
세팅이 완료된 후, 위 링크에 있는 기술문서를 참고하며, 만들어보았습니다.
저희 프로젝트에서는 VR 플레이어가 호스트인데, vr 플레이어가 방을 만들면, 랜덤한 방 번호가 지정됩니다.
이 랜덤한 방 번호를 만들고 접속하는 것을 R&D 해보겠습니다.
먼저 Fusion에서는 실행하기 위해, StartGame 메서드가 NetworkRunner에서 호출이 되어야 합니다.
또한 저는 Host와 Client가 시작하는 방법이 다르기에 각각 다른 방법으로 연결할 수 있도록 만들어 보겠습니다.
먼저 공통적으로 가지는 NetworkManager라는 스크립트를 작성하였습니다.
먼저 INetworkRunnerCallbacks 인터페이스를 상속 받아 구현해주었습니다.
그 다음 어디서나 접근이 가능하게 싱글톤으로 만들어 줍니다.
그리고 NetworkRunner를 받아오고 있으므로 NetworkManager 게임 오브젝트의 NetworkRunner 컴포넌트를 assign합니다.
그리고 플레이어 들어옴과 나가는 것을 파악하기 위해 OnPlayerJoined와 OnPlayerLeft를 사용하여, 로그를 찍습니다.
using Fusion;
using Fusion.Sockets;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NetworkManager : MonoBehaviour, INetworkRunnerCallbacks
{
public static NetworkManager Instance { get; private set; }
public NetworkRunner Runner { get => runner;}
private NetworkRunner runner;
private void Awake()
{
//있으면서, 있는 것이 내가 아니면(다른애임)
if (Instance != null && Instance !=this) Destroy(this.gameObject);
else Instance = this;
runner = GetComponent<NetworkRunner>();
runner.AddCallbacks(this);
}
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
if (runner.IsServer && player == runner.LocalPlayer)
{
Debug.Log("Host 들어옴");
}
else
{
Debug.Log("Client 들어옴");
}
}
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
{
if (runner.IsServer && player == runner.LocalPlayer)
{
Debug.Log("Host 나감");
}
else
{
Debug.Log("Client 나감");
}
}
#region Not use Runner Callbacks
public void OnConnectedToServer(NetworkRunner runner)
{
}
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason)
{
}
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token)
{
}
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data)
{
}
public void OnDisconnectedFromServer(NetworkRunner runner)
{
}
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken)
{
}
public void OnInput(NetworkRunner runner, NetworkInput input)
{
}
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input)
{
}
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data)
{
}
public void OnSceneLoadDone(NetworkRunner runner)
{
}
public void OnSceneLoadStart(NetworkRunner runner)
{
}
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
{
}
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason)
{
}
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message)
{
}
#endregion
}
이렇게 기본적인 NetworkManager가 만들어집니다.
그리고 Host와 Client가 달라야 되기에 StartGame하는 방식을 다르게 해보겠습니다.
Host StartGame
using Fusion;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class HostMain : MonoBehaviour
{
[SerializeField] private GameMode gameMode;
[SerializeField] private Button btnEnterRoom;
[SerializeField] private string roomName;
[SerializeField] private TMP_Text txtRoomNum;
// Start is called before the first frame update
void Start()
{
this.btnEnterRoom.onClick.AddListener(() =>
{
Debug.LogFormat("Enter Room : {0}", gameMode);
StartGame();
});
}
private async void StartGame()
{
Debug.Log("StartGame");
int roomNumber = UnityEngine.Random.Range(1000, 10000); //1000~9999
this.roomName = roomNumber.ToString();
this.txtRoomNum.text = roomNumber.ToString();
var args = new StartGameArgs()
{
GameMode = gameMode,
SessionName = roomName,
SceneManager = this.gameObject.AddComponent<NetworkSceneManagerDefault>(),
Scene = SceneManager.GetActiveScene().buildIndex
};
var result = await NetworkManager.Instance.Runner.StartGame(args);
if (result.Ok)
{
Debug.Log("OK");
}
else
{
Debug.Log(result.ErrorMessage);
}
}
}
HostMain을 위와 같이 작성하고, Scene을
이 상태로 만들었습니다.
Client StartGame
using Fusion;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ClientMain : MonoBehaviour
{
[SerializeField] private GameMode gameMode;
[SerializeField] private Button btnEnterRoom;
[SerializeField] private string roomName;
[SerializeField] private TMP_InputField input;
// Start is called before the first frame update
void Start()
{
this.btnEnterRoom.onClick.AddListener(() =>
{
Debug.LogFormat("Enter Room : {0}", gameMode);
this.roomName = this.input.text;
StartGame();
});
}
private async void StartGame()
{
Debug.Log("StartGame");
var args = new StartGameArgs()
{
GameMode = gameMode,
SessionName = roomName,
SceneManager = this.gameObject.AddComponent<NetworkSceneManagerDefault>(),
Scene = SceneManager.GetActiveScene().buildIndex
};
var result = await NetworkManager.Instance.Runner.StartGame(args);
if (result.Ok)
{
Debug.Log("OK");
}
else
{
Debug.Log(result.ErrorMessage);
}
}
}
Client Main을 위와 같이 작성하고
이 상태로 만들었습니다.
그리고 시험해보기 위해, Client 모드인 상태로 빌드를 하였습니다.
이렇게 들어가면 랜덤한 방 번호로 방이 생성되고, Client가 들어가고 나오는 것이 찍히는 것을 확인할 수 있었습니다.
'CGV(Castle Giant Virtual) 프로젝트 일지' 카테고리의 다른 글
CGV 개발일지8 (VR 플레이어 손, 머리 위치 동기화) (0) | 2023.12.13 |
---|---|
CGV 개발일지 7 (주제 변경) (1) | 2023.12.11 |
CGV 개발일지 5 (Throw Object 개선 하기) (0) | 2023.11.25 |
CGV 개발일지 4 (OVR Grab을 통해 잡은 물체를 통해 다른 물체 치기) (4) | 2023.11.25 |
CGV 개발일지 3 (OVR 기능 활용하여 테스트) (1) | 2023.11.25 |