You are currently viewing 【Unity教學】2022製作多人連線遊戲的最佳選擇!Photon Fusion 02 建立連線

【Unity教學】2022製作多人連線遊戲的最佳選擇!Photon Fusion 02 建立連線

  • Post category:教學
  • Reading time:5 mins read
  • Post author:

大家好,我是Wilson,繼上次的教學之後,這次要分享的是如何快速地建立連線,並認識Fusion基本的連線架構。

領取Photon Fusion 快速上手懶人攻略

這邊幫大家準備了【Photon Fusion 快速上手懶人攻略】!

裡面介紹了Fusion的基本功能,以及Fusion同步網路狀態的3大方法,有興趣的朋友可以免費領取喔!

重點回顧

  • Network Runner是Fusion連線的核心、心臟,所有的連線都必須依賴他,因此要在最一開始時,先建立在場景上,也因為整個遊戲只需要一個Network Runner,所以Network Runner預設是一個Don ‘t Destory On Load物件
  • 每一個網路物件都需要有Network Object元件
  • 透過Runner的StartGame()方法可以開啟新的Session(房間),並傳入必要參數:
  1. GameMode:以什麼模式加入房間,可以是Server、Host、Client、AutoHostOrClient、Single
  2. Session Name:房間名稱
  3. Scene:當前的場景
  4. Scene Manager:負責處理Fusion場景控制的物件,有特殊需求的話可以自己寫,但目前我們先使用Fusion提供的NetworkSceneManagerDefault就可以了。
  • 實作INetworkRunnerCallbacks的物件會在重要的事件發生時,執行Callback的內容,如每當有玩家進入/離開房間時,會執行OnPlayerJoined/OnPlayerLeft,並傳入當前場景中的Network Runner及該名玩家的資料
  • 為了讓物件的移動更順滑,我們會將擁有網路元件的物件作為空物件,真正的視覺物件放在其底下當子物件,再把視覺物件放到網路元件裡面的Interplation Target
  • 在網路上的物件生成/消除必須使用Runner的Spawn()以及Despawn()方法。Spawn()方法可以將生成出來的網路物件的Input Authority提拱給指定玩家(PlayerRef)。
  • 使用Dictionary紀錄玩家資料以及其控制的角色物件,是為了之後方便追蹤。

Code

任何實作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 OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data) { }
public void OnSceneLoadDone(NetworkRunner runner) { }
public void OnSceneLoadStart(NetworkRunner runner) { }
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }

BasicSpawner.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Fusion;
using Fusion.Sockets;
using System;
using UnityEngine.SceneManagement;

public class BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
{
    [SerializeField]
    private NetworkRunner networkRunner = null;

    [SerializeField]
    private NetworkPrefabRef playerPrefab;

    private Dictionary<PlayerRef, NetworkObject> playerList = new Dictionary<PlayerRef, NetworkObject>();

    private void Start()
    {
        StartGame(GameMode.AutoHostOrClient);
    }

    async void StartGame(GameMode mode)
    {
        networkRunner.ProvideInput = true;

        await networkRunner.StartGame(new StartGameArgs()
        {
            GameMode = mode,
            SessionName = "Fusion Room",
            Scene = SceneManager.GetActiveScene().buildIndex,
            SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
        });
    }

    public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
    {
        Vector3 spawnPosition = Vector3.up * 2;
        NetworkObject networkPlayerObject = runner.Spawn(playerPrefab, spawnPosition, Quaternion.identity, player);

        playerList.Add(player, networkPlayerObject);
    }

    public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
    {
        if (playerList.TryGetValue(player, out NetworkObject networkObject))
        {
            runner.Despawn(networkObject);
            playerList.Remove(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 OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment<byte> data) { }
    public void OnSceneLoadDone(NetworkRunner runner) { }
    public void OnSceneLoadStart(NetworkRunner runner) { }
    public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
}

PlayerController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    
}

專案Github

有需要的朋友可以在這裡看到本次教學的專案喔!

This Post Has 2 Comments

  1. huangyaoyang

    OperationException: Plugin Mismatch requested=’FusionPlugin’ got=’Default’ (ErrorCode: 32751)

    1. Wilson Lin

      版本有正確嗎,必須是2020以上的才可以使用

Leave a Reply