游戏对象
网络游戏对象 :
需要在玩家间同步,附加了NetworkIdentity组件的游戏对象。
非网络游戏对象 :
不需要在玩家间进行同步,没有附加NetworkIdentity组件的游戏对象。
玩家游戏对象
玩家游戏对象属于网络游戏对象。
在每个客户端上,属于该客户端的玩家对象被标记为本地玩家,其余玩家对象为远程副本。
本地玩家标识:isLocalPlayer(NetworkBehaviour上属性)是真。
玩家游戏对象在其他客户端有一个自己的副本对象。
服务器持有所有玩家,负责状态计算和同步。
示例:
服务器有所有客户端的副本;
客户端1有本机角色player1和远程角色player2;
客户端2有本机角色player2和远程角色player1。

自定义角色生成
默认情况下,Mirror的NetworkManager会自动生成Player角色。
这导致一个问题,如果player预制体是一个模型,那么所有客户端的player都是一样的。
自定义角色生成可以解决这个问题。
示例:点击UI,创建不同的player
- 新建场景,创建空对象,命名为NetworkManager,添加组件SpawnSampleNetworkManager,NetworkManagerHUD,KcpTransport;
- 创建cube,capsule,sphere作为不同的player,分别添加组件NetworkIdentity,移除场景中的player;
- 新建空对象,命名为PlayerSelector,添加组件PlayerSelector;
- NetworkManager对象设置KcpTransport,角色列表;
- PlayerSelector对象引用Networkmanager。
注意:
player预制体可以手动添加到Registered Sapwnable Prefabs列表中;
也可以使用代码动态添加player。
如果没有上述任一操作,客户端不会生成对应的对象。
脚本
SpawnMessage用于传递用户选择的playerIndex
csharp
using Mirror;
public struct SpawnMessage : NetworkMessage
{
public int prefabIndex;
}
SpawnSampleNetworkManager中注册角色预制体列表,注册角色生成逻辑,触发客户端断开事件;
csharp
using System;
using Mirror;
using UnityEngine;
public class SpawnSampleNetworkManager : NetworkManager
{
[Serializable]
public class SpawnPlayer
{
public GameObject playerPrefab;
public Vector3 spawnPosition;
}
[Header("角色列表")]
public SpawnPlayer[] playerPrefabs;
public event Action OnClientDisconnectAction;
public override void Awake()
{
base.Awake();
//玩家预制体加入spawnPrefabs
for (int i = 0; i < playerPrefabs.Length; i++)
{
if (!spawnPrefabs.Contains(playerPrefabs[i].playerPrefab))
spawnPrefabs.Add(playerPrefabs[i].playerPrefab);
}
}
public override void OnStartServer()
{
NetworkServer.RegisterHandler<SpawnMessage>(OnSpawnMessage);
}
private void OnSpawnMessage(NetworkConnectionToClient client, SpawnMessage message)
{
if (message.prefabIndex < 0 || message.prefabIndex >= playerPrefabs.Length)
{
Debug.LogError($"Invalid prefab index {message.prefabIndex}");
return;
}
SpawnPlayer spwanPlayer = playerPrefabs[message.prefabIndex];
GameObject player = Instantiate(spwanPlayer.playerPrefab, spwanPlayer.spawnPosition, Quaternion.identity);
NetworkServer.AddPlayerForConnection(client, player);
}
public override void OnStopServer()
{
NetworkServer.UnregisterHandler<SpawnMessage>();
}
public override void OnClientDisconnect()
{
OnClientDisconnectAction?.Invoke();
}
}
PlayerSelector使用OnGUI绘制UI,用户点击UI创建不同的player,客户端断开连接重置选择。
csharp
using System;
using Mirror;
using UnityEngine;
[Serializable]
public class PlayerSelector : MonoBehaviour
{
[SerializeField] SpawnSampleNetworkManager manager;
private bool hasSelectedPlayer = false;
public Vector2 offest;
void OnEnable()
{
manager.OnClientDisconnectAction += OnClientDisconnected;
}
void OnDisable()
{
manager.OnClientDisconnectAction -= OnClientDisconnected;
}
private void OnClientDisconnected()
{
hasSelectedPlayer = false;
}
private void OnGUI()
{
if (hasSelectedPlayer == false && NetworkClient.isConnected)
{
GUILayout.BeginArea(new Rect(offest.x, offest.y, 100f, Screen.height));
if (GUILayout.Button("选择角色1"))
SendMessageToServer(0);
if (GUILayout.Button("选择角色2"))
SendMessageToServer(1);
if (GUILayout.Button("选择角色3"))
SendMessageToServer(2);
GUILayout.EndArea();
}
}
private void SendMessageToServer(int index)
{
if (hasSelectedPlayer == true)
return;
SpawnMessage message = new SpawnMessage
{
prefabIndex = index
};
NetworkClient.Send(message);
hasSelectedPlayer = true;
}
}