Mirror网络库插件使用6

游戏对象

网络游戏对象

需要在玩家间同步,附加了NetworkIdentity组件的游戏对象。
非网络游戏对象

不需要在玩家间进行同步,没有附加NetworkIdentity组件的游戏对象。

玩家游戏对象

玩家游戏对象属于网络游戏对象。

在每个客户端上,属于该客户端的玩家对象被标记为本地玩家,其余玩家对象为远程副本。

本地玩家标识:isLocalPlayer(NetworkBehaviour上属性)是真。

玩家游戏对象在其他客户端有一个自己的副本对象。

服务器持有所有玩家,负责状态计算和同步。

示例:

服务器有所有客户端的副本;

客户端1有本机角色player1和远程角色player2;

客户端2有本机角色player2和远程角色player1。

自定义角色生成

默认情况下,Mirror的NetworkManager会自动生成Player角色。

这导致一个问题,如果player预制体是一个模型,那么所有客户端的player都是一样的。

自定义角色生成可以解决这个问题。

示例:点击UI,创建不同的player

  1. 新建场景,创建空对象,命名为NetworkManager,添加组件SpawnSampleNetworkManager,NetworkManagerHUD,KcpTransport;
  2. 创建cube,capsule,sphere作为不同的player,分别添加组件NetworkIdentity,移除场景中的player;
  3. 新建空对象,命名为PlayerSelector,添加组件PlayerSelector;
  4. NetworkManager对象设置KcpTransport,角色列表;
  5. 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;
    }
}
相关推荐
JAVA面经实录91722 分钟前
网络编程基础(Java Web/分布式前置·完整版)(十一)
java·前端·网络
記億揺晃着的那天12 小时前
NAS 内网域名访问为什么需要浏览器授权
网络·nginx·js·nas
chunmiao303212 小时前
DeepSeek V4-Pro 正式版上线,API 8月17日起分时调价
网络·安全
迪康Defender14 小时前
AI 重构终端安全运营:智能分析中枢 AI Insight 模块架构与落地场景深度解析
运维·网络·人工智能·其他·安全·重构·架构
0x5315 小时前
Java网络编程(二)
java·服务器·网络
西安景驰电子17 小时前
《PTP精确时间协议系列》第一篇:从原理到应用,全面解读IEEE 1588
linux·运维·服务器·开发语言·网络·windows·php
ZGi.ai17 小时前
多模型回答不稳定:路由规则与评测方法
网络·人工智能·大模型评测·多模型·模型路由·zgi·模型网关
80s77718 小时前
独享住宅IP、长效代理ip是什么?有哪些作用?
网络·网络协议·tcp/ip
IPdodo_18 小时前
静态 IP、住宅 IP 和固定出口有什么区别?开发场景选型指南
服务器·网络·网络协议·tcp/ip·代理ip
_ZHOURUI_H_19 小时前
Unity TCP底层极限拆解:粘包、半包、CRC、序列号、双缓冲到底怎么一起工作的?
网络·网络协议·tcp/ip·游戏·unity·游戏引擎·游戏开发