# Photon Fusion 102
Photon Fusion 102은 Photon 홈페이지의 기술문서에 있는 Fusion 튜토리얼 중 한 단계를 말합니다.
# 방만들기, 접속하기
Photon Fusion 네트워크의 주체는 <NetworkRunner> 입니다.
NetworkRunner의 멤버 함수인 StartGame(StartGameArgs args) 로
Fusion 네트워크를 시작할 수 있습니다.
private NetworkRunner _runner; // 러너 변수를 선언하고
_runner = gameObject.AddComponent<NetworkRunner>(); // 객체를 생성합니다.
_runner.ProvideInput = true; // 이 클라이언트에서 입력을 한다는 뜻
await _runner.StartGame(new StartGameArgs()
{
GameMode = mode, // 서버 혹은 클라이언트 등
SessionName = "TestRoom",
//Scene = SceneManager.GetActiveScene().buildIndex,
//SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
});
'방 만들기' 버튼에는 Host mode로
'방 들어가기' 버튼에는 Client mode로 StartGame을 호출하면 됩니다.
주석처리한 부분은 씬 관리를 위한 부분이나 Fusion 100에서 실질적으로 사용하지 않습니다.
주석처리하여도 실행하는데 문제는 없습니다.
# INetworkRunnerCallbacks 인터페이스
NetworkRunner가 C#스크립트와 상호작용하기 위해서 구현해야할 인터페이스입니다.
INetworkRunnerCallbacks 인터페이스에는 아래와 같이
다양한 상황에 호출되는 함수들이 있습니다.
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) { }
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player) { }
public void OnInput(NetworkRunner runner, NetworkInput input);
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { }
public void OnConnectedToServer(NetworkRunner runner) { }
public void OnDisconnectedFromServer(NetworkRunner runner) { }
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { }
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) { }
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken);
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data) { }
public void OnSceneLoadDone(NetworkRunner runner) { }
public void OnSceneLoadStart(NetworkRunner runner) { }
NetworkRunner 객체가 게임을 시작하여 세션을 생성하였다면 처음에는 방을 만든 호스트가 입장하게 될 것입니다.
그 다음 클라이언트 하나가 게임을 시작해서 세션에 입장하게 될 것입니다.
이 처럼 세션에 플레이어가 입장할 때 호출되는 함수, 그리고 퇴장할 때 호출되는 함수는 다음과 같습니다.
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
입장할 때의 NetworkRunner 객체와 플레이어의 정보를 인수로 받아옵니다.
게임이 Host mode이기 때문에 호스트만 새 개체를 생성할 수 있도록 합니다.
// 입장
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
// 누군가가 입장하면 호스트를 담당하는 runner가 플레이어의 아바타 생성을 담당합니다.
if (runner.IsServer)
{
Vector3 spawnPosition = new Vector3((player.RawEncoded % runner.Config.Simulation.DefaultPlayers) * 3, 1, 0);
// Instantiate()의 Fusion 버전으로 생각하면 됩니다.
// 네트워크 오브젝트로 생성합니다.
NetworkObject networkPlayerObject = runner.Spawn(_playerPrefab, spawnPosition, Quaternion.identity, player);
_spawnedCharacters.Add(player, networkPlayerObject);
}
}
// 퇴장
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
{
if(_spawnedCharacters.TryGetValue(player, out NetworkObject networkObject))
{
// Destroy()의 Fusion 버전
runner.Despawn(networkObject);
_spawnedCharacters.Remove(player);
}
}
# 입력 수집
입력이 들어올 때 호출되는 INetworkRunnerCallbacks 의 함수는 다음과 같습니다.
public void OnInput(NetworkRunner runner, NetworkInput input);
인수로 NetworkRunner와 함께 NetworkInput이 들어오는데
NetworkInput이 동작하기 위해서 INetworkInput 인터페이스를 구현한 구조체가 필요합니다.
public struct NetworkInputData : INetworkInput // OnInput()을 위한 인터페이스입니다.
{
public const byte MOUSEBUTTON1 = 0x01;
public const byte MOUSEBUTTON2 = 0x02;
public byte buttons;
public Vector3 direction;
}
INetworkInput 인터페이스가 위에 정의된 NetworkInputData 구조체를
OnInput()의 인수로 사용하도록 해줍니다.
그리고 OnInput() 함수를 구현합니다.
public void OnInput(NetworkRunner runner, NetworkInput input)
{
var data = new NetworkInputData();
if (Input.GetKey(KeyCode.W)) data.direction += Vector3.forward;
if (Input.GetKey(KeyCode.S)) data.direction += Vector3.back;
if (Input.GetKey(KeyCode.A)) data.direction += Vector3.left;
if (Input.GetKey(KeyCode.D)) data.direction += Vector3.right;
if (_mouseButton0) data.buttons |= NetworkInputData.MOUSEBUTTON1;
if (_mouseButton1) data.buttons |= NetworkInputData.MOUSEBUTTON2;
_mouseButton0 = false;
_mouseButton1 = false;
input.Set(data);
}
input의 Set() 인수로 INetworkInput 을 구현한 NetWorkInputData 구조체 형태로 넘어갑니다.
# 입력 적용하기
각 아바타들이 정확하게 상호작용하기 위해서 각자의 스크립트에서 독립적으로 돌아가는 MonoBehaviour 대신
Fusion에서 제공하는 NetworkBehaviour 를 상속받아야 합니다.
NetworkBehaviour 는 MonoBehaviour 를 상속받았습니다.
NetworkBehaviour를 상속받으면 FixedUpdateNetwork를 사용할 수 있습니다.
public class Player : NetworkBehaviour
{
public override void FixedUpdateNetwork(){}
}
FixedUpdateNetwork는 MonoBehaviour의 update와 다르게
네트워크 상태가 적용된 시뮬레이션 틱에서 호출됩니다.
그리고 NetworkBehaviour는 위 틱에 대한 입력을 얻을 수 있는
GetInput() 메서드를 제공합니다.
마지막으로 NetworkCharacterControllerPrototype 컴포넌트를 통해서
플레이어의 아바타를 움직이면 됩니다.
public override void FixedUpdateNetwork()
{
if (GetInput(out NetworkInputData data))
{
data.direction.Normalize();
_cc.Move(5*data.direction*Runner.DeltaTime);
}
}
'게임 개발 > 유니티' 카테고리의 다른 글
[유니티] Input.GetKey() 한글로 입력해도 동작하게 하고 싶다면 (0) | 2023.01.16 |
---|---|
[유니티/셰이더] 순차적 체커보드 패턴 Procedural checkerboard pattern (1) | 2022.12.24 |
[유니티/셰이더] 커스텀 셰이더 기초 (1) | 2022.12.23 |
[유니티] Photon Fusion 103 간단 요약 (0) | 2022.12.22 |
[유니티] 게임 패널에 GUI 띄우기 (0) | 2022.12.15 |