시작하기

SDK와 프로젝트 세팅을 한다.

https://doc.photonengine.com/ko-kr/fusion/current/fusion-100/fusion-101

 

Fusion 101 - 시작하기 | Photon Engine

 

doc.photonengine.com

 

씬 설정하기

https://doc.photonengine.com/ko-kr/fusion/current/fusion-100/fusion-102

 

Fusion 102 - 씬 설정하기 | Photon Engine

 

doc.photonengine.com

 

포톤 퓨전은 INetworkRunnerCallbacks를 사용하여 동기화 작업을 하는 것 같다.

프로젝트를 따라가다가 async라는 개념이 나오는데 코루틴과 비슷한 개념이라고 한다.

async, await, Task를 이용하여 어떤 작업을 순차적으로 실행할 때, 동시에 실행할 때 코루틴 보다 간단하게 만들 수 있다.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

 

Asynchronous programming in C#

An overview of the C# language support for asynchronous programming using async, await, Task, and Task

learn.microsoft.com

async void StartGame(GameMode mode)
{
    // GameMode
    // 1. 싱글 2. 쉐어드 - 포톤 클라우드 이용(사용자는 클라이언트) 3. 서버(게임 서버를 직접 지원하고 원격 플레이어만 허용)
    // 4. 호스트(로컬 플레이어를 허용하는 게임서버) 5. 클라이언트(호스트나 게임 모드에 클라이언트로 시작)
    // 6. 자동(첫 번째 접속시 호스트 모드, 나중 접속시 클라이언트 모드)
    
    // NetworkRunner : 플레이어와 관련된 변수들을 가지고있는 클래스
    _runner = gameObject.AddComponent<NetworkRunner>();
    // PlayerRef와 INetworkInput을 받는 여부
    _runner.ProvideInput = true;

    // NetworkRunner.StartGame(StartGameArgs args) : 매치메이킹 세팅을 해주는 메서드
    // 비동기로 NetworkRunner.StartGame(StartGameArgs args) 실행
    await _runner.StartGame(new StartGameArgs
    {
        GameMode = mode,
        SessionName = "TestRoom", // 세션 이름(클라이언트와 서버 세션 이름)
        Scene = SceneManager.GetActiveScene().buildIndex, // Scene은 구조체인 SceneRef?타입
        // NetworkSceneManagerDefault : 비동기 씬 관련 메서드가 포함된 클래스
        SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>(), // SceneManager INetworkSceneManager 타입이다.
    });
}

여기서 예시는 포톤 펀처럼 호스트와 클라이언트가 포톤 클라우드에 요청하고 응답받는 식으로 진행된다. (게임 모드에 따라 달라짐)

void OnGUI()
{
    if (!_runner)
    {
        if (GUI.Button(new Rect(0, 0, 200, 40), "Host"))
        {
            StartGame(GameMode.Host);
        }

        if (GUI.Button(new Rect(0, 40, 20, 40), "Join"))
        {
            StartGame(GameMode.Client);
        }
    }
}

Network Object

포톤 펀의 PhotonView처럼 고유한 ID를 가지고 있고 객체의 생성과 파괴 등을 추적한다.

https://doc.photonengine.com/ko-kr/fusion/current/manual/network-object/network-object

 

네트워크 객체 | Photon Engine

 

doc.photonengine.com

포톤 퓨전에는 Network Character Contoller Prototype처럼 이름 그대로 Prototype을 지원하는데 네트워크에서 Character Controller를 다루는 이동 관련된 부분을 미리 만들어 놓은 스크립트이다.

- NetworkTransform을 상속받는데 Transform의 위치를 동기화 시켜주는 메서드가 들어있다.

- InterPolation Target에 움직일 게임 오브젝트를 넣어주기만 하면 된다.

플레이어 세션 연결과 연결 해제시 콜백

- 생성과 파괴를 구현(딕셔너리에 저장하여 추적)

public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
    // 연결중이면
    if (runner.IsServer)
    {
        // 특정한 위치 저장
        Vector3 spawnPosition =
            new Vector3((player.RawEncoded % runner.Config.Simulation.DefaultPlayers) * 3, 1, 0);
        // NetworkRunner.Spawn이 네트워크 Instantitate와 비슷한 역할인데 추가로 PlayerRef를 받는다.
        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))
    {
        // 파괴 후 반환
        runner.Despawn(networkObject);
        _spawnedCharacters.Remove(player);
    }
}

클라이언트가 직접 네트워크 객체의 상태를 바꾸는 것이 아닌 호스트가 클라이언트로부터 입력을 받아 다음 상태를 예측하여 갱신하는 식으로 작동한다.

유저의 입력을 받기위해 입력을 담을 공간을 만들어주어야 한다.

INetworkInput을 상속받는 NetworkInputData에 public 변수를 만들고 인스턴싱해 키 입력을 받아놓고(여기선 Vector3) 인자로 받은 NetworkInput에 Set해주는 방식으로 플레이어의 데이터 입력을 저장한다.

public struct NetworkInputData : INetworkInput
{
    public Vector3 direction;
}
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;
    
    input.Set(data);
}

MonoBehaviour를 상속받는 퓨전의 컴포넌트로 입력을 틱 단위로 받기 위해 FixedUpdateNetwork에 GetInput<T>(out T input)으로 입력이 들어왔는지 확인한다.(입력이 들어오면 true를 안 들어오면 false를 반환)

* 이전에 입력을 담을 변수를 정의한 NetworkInputdata가 out으로 지역변수로 사용되어 data에 접근하여 방향을 Normailize하고 그 값을 NetworkCharacterControllerPrototype의 Move에 담아 이동시킨다.

- Runner는 NetworkBehaviour을 상속하는 SimulationBehaviour의 변수이다. (NetworkRunner 클래스)

- Runner.DeltaTime은 FixedDeltaTime처럼 고정된 DeltaTime이다.

public class Player : NetworkBehaviour
{
    NetworkCharacterControllerPrototype _cc;

    void Awake()
    {
        _cc = GetComponent<NetworkCharacterControllerPrototype>();
    }

    public override void FixedUpdateNetwork()
    {
        if (GetInput(out NetworkInputData data))
        {
            data.direction.Normalize();
            _cc.Move(5 * data.direction * Runner.DeltaTime);
        }
        
    }
}

'공부 모음 > 포톤 퓨전 시작해보기' 카테고리의 다른 글

포톤 퓨전 원격 프로시져 호출(RPC)  (0) 2022.12.09
포톤 퓨전 속성 변경  (0) 2022.12.09
포톤 퓨전 물리  (2) 2022.12.08
포톤 퓨전 Prediction  (0) 2022.12.08

+ Recent posts