Unity Mirror NetworkManager初识

devtools/2024/10/22 13:59:18/

文章目录

      • Network Manager网络管理器
        • 什么是网络管理器?
        • 通过Transports进行定制化网络连接管理
        • 自定义连接地址和端口号
        • Game State Management游戏状态管理
        • Network Manager HUD
        • 玩家预制体及其生成控制
        • Spawn Prefabs其他预制体注册
        • Scene Management场景管理

Network Manager网络管理器

什么是网络管理器?

网络管理器是一个封装了各种各样网络相关管理代码的脚本文件,它包括但不限于启动或关闭服务、生成角色、玩家状态身份管理等功能,是一个十分强大的脚本文件。

Network Manager是一个单例类型脚本组件,因此在同一个场景中只允许出现一次。

通过Transports进行定制化网络连接管理

transport为官方预留出来的自定义网络连接接口组件,他可以设置为任何继承于Transport类的类型,以便于我们自己来设置连接方式。

Mirror自带网络连接为基于UDPKCP连接,除此之外我们还可以自己通过导入API等方式实现其他链接方式,例如通过Steam连接等等。

如果是直接添加Network Manager脚本到管理器Game Object之上,可以在属性栏中的Network Info->Transport进行设置,如果是继承该脚本进行自定义逻辑修改可以直接通过更改transport的值进行修改:

image-20241017173548616

transport = 对应Transport脚本组件;
自定义连接地址和端口号

在同样一栏中的Network Address中可以设置需要进行连接的服务器IP地址,默认为localhost即本机IP,同样也可以在脚本中修改networkAddress的值直接进行修改,他在官方脚本中定义如下:

/// <summary>向客户端开放的服务器地址。</summary>
[FormerlySerializedAs("m_NetworkAddress")]
[Tooltip("客户端应连接到服务器的网络地址。服务器端不会将其用于任何用途。")]
public string networkAddress = "localhost";
Game State Management游戏状态管理

该部分被定义在Network Manager脚本中,需要手动调用不同的方法来实现不同的启动状态。在脚本中,提供了三个方法表示以客户端启动、以专用服务器启动和同时作为服务器和客户端启动,分别为StartClientStartServer StartHost,并且官方在书写这些函数时已经将初始化函数作为一部分写入函数中,直接调用就可以创建对应服务。

例如我们可以通过自定义方法来设置通过传入参数来选择启动方式:

public void StartSomething(int state)
{if (state == 0)StartHost();else if (state == 1)StartServer();else if (state == 2)StartClient();
}
Network Manager HUD

这个组件作为测试中快速通过游戏内UI启动服务器的辅助组件,它的本质也是修改Network Manager中的networkAddress、调用对应的启动函数来实现,额外增加了绘制UI的代码。

Network Manager HUD中用于获取Network Manager的部分代码:

image-20241021112542164

Network Manager HUD中用于设置networkAddress的代码片段:

image-20241021112635476

Network Manager HUD中用于启动服务的代码片段:

image-20241021112733626

玩家预制体及其生成控制

因为几乎绝大多数可联机游戏都会有一个可供操作的玩家角色,所以官方直接设置了玩家预制体属性用于生成游戏内玩家对象,并且该预制体不能为空,否则将会发生报错。

image-20241021120610830

除了玩家预制体的设置外,还可以对其生成位置、是否自动生成进行设置,在Inspector窗口中如下图所示:

image-20241021114346809

在源码中则分别对应:

/// <summary>在服务器上创建玩家对象时使用的默认预制体。</summary>
// 玩家对象在服务器上的 AddPlayer() 默认处理程序中创建。
// 实现 OnServerAddPlayer 方法可以覆盖此行为。
[Header("Player Object")]
[FormerlySerializedAs("m_PlayerPrefab")]
[Tooltip("玩家对象的预制体。预制体必须包含 Network Identity 组件。可以是一个空的游戏对象或一个完整的角色。")]
public GameObject playerPrefab;/// <summary>启用后,在连接和场景变化时自动创建玩家对象。</summary>
[FormerlySerializedAs("m_AutoCreatePlayer")]
[Tooltip("场景变化后,Mirror 是否应自动生成玩家?")]
public bool autoCreatePlayer = true;/// <summary>玩家生成的位置。</summary>
[FormerlySerializedAs("m_PlayerSpawnMethod")]
[Tooltip("按轮询顺序或随机顺序选择起始位置")]
public PlayerSpawnMethod playerSpawnMethod;

在代码中也可以对他们进行直接的控制,例如通过修改对应具体值等等。

除了使用默认方式自动进行生成外,我们可以手动去生成对应的预制体,在源码中可以找到客户端连接时生成玩家预制体的代码,代码中直接生成了玩家预制体并设置了基础信息,然后便添加到连接管理中,具体添加逻辑则在分部类Network Server之中(其中涉及到的Network Start Position将在后面同名组件讲解)。我们可以对其进行更改,如更改为连接不显示玩家或不加载玩家预制体,在其他地方进行加载:

/// <summary>当客户端请求添加玩家时在服务器上调用。默认添加 playerPrefab。可以被重写。</summary>
// 该函数的默认实现是从 playerPrefab 创建一个新的玩家对象。
public virtual void OnServerAddPlayer(NetworkConnectionToClient conn)
{Transform startPos = GetStartPosition();GameObject player = startPos != null? Instantiate(playerPrefab, startPos.position, startPos.rotation): Instantiate(playerPrefab);// 实例化一个 "Player" 预制体后,默认名称为 "Player(clone)"// => 在名称后面附加连接ID对于调试非常有用!player.name = $"{playerPrefab.name} [connId={conn.connectionId}]";NetworkServer.AddPlayerForConnection(conn, player);
}

而在客户端中,生成玩家预制体总的来讲就是调用AddPlayer函数来注册并验证是否注册成功,但是需要进行条件是否合适判定。

/// <summary>当客户端连接到服务器时调用。默认情况下,它将客户端设置为就绪状态并添加一个玩家。</summary>
public virtual void OnClientConnect()
{// OnClientConnect 默认调用 AddPlayer,但在有在线/离线场景的情况下不应这样做。// 因此我们需要 clientLoadedScene 标志来防止这种情况。if (!clientLoadedScene){// 通常,Ready/AddPlayer 是由场景加载完成触发的。// 如果没有加载场景,则在这里调用 Ready/AddPlayer。if (!NetworkClient.ready)NetworkClient.Ready();if (autoCreatePlayer)NetworkClient.AddPlayer();}
}
Spawn Prefabs其他预制体注册

在多人游戏中,所有需要在游戏中生成的预制体都需要进行注册,官方的原话为:

If you have one Network Manager that is persisted through scenes via Don’t Destroy On Load (DDOL), you need to register all prefabs to it which might be spawned in any scene. If you have a separate Network Manager in each scene, you only need to register the prefabs relevant for that scene.

注册的位置在Inspector中最末尾:

image-20241021141033311

我们也可以手动对他进行注册会在其他位置进行注册,注册的代码为:

 NetworkClient.RegisterPrefab(prefab);
Scene Management场景管理

Inspector窗口中默认会有两个场景参数,第一个为离线场景,第二个为进入游戏后首次加载的场景(可以理解为联机大厅等),在下面还有一个参数,用于设置离线或短线时延迟显示的时间,在这之中可以进行一些特殊处理。

image-20241021144527183

在源码中对应部分如下:

/// <summary>在离线时(启动/断开连接/关闭)自动切换到此场景。</summary>
[Header("Scene Management")]
[Scene]
[FormerlySerializedAs("m_OfflineScene")]
[Tooltip("当客户端或服务器停止时,Mirror 将切换到的场景")]
public string offlineScene = "";/// <summary>在上线时(连接后/启动服务器后)自动切换到此场景。</summary>
[Scene]
[FormerlySerializedAs("m_OnlineScene")]
[Tooltip("当服务器启动时,Mirror 将切换到的场景。客户端在连接时会收到一条场景消息以加载服务器当前的场景。")]
public string onlineScene = "";[Range(0, 60), Tooltip("断开连接后可选的延迟,用于显示 '连接丢失...' 消息或类似内容,然后再加载离线场景,这在大型项目中可能需要较长时间。")]
public float offlineSceneLoadDelay = 0;

在需要进行尝尽切换时,可以通过调用ServerChangeScene(string newSceneName)函数来进行切换,它会将onlineScene自动更新为切换到的场景,也可以重写函数自定义场景切换。


http://www.ppmy.cn/devtools/127851.html

相关文章

重新阅读《马说》,感悟“伯乐相马”背后的被选择与选择的大智慧

“初闻不识曲中意&#xff0c;再听已是曲终人”。世有伯乐&#xff0c;然后有千里马。千里马常有&#xff0c;而伯乐不常有。无论你是考研考公等考试大军中的一员&#xff0c;还是已步入社会的打工人或者领导&#xff0c;当你面临被人选择或者选择人时&#xff0c;皆可从《马说…

九种排序,一次满足

我们在算法题进行练习提升时&#xff0c;经常会看到题目要求数据从大到小输出&#xff0c;从小到大输出&#xff0c;前一半从小到大输出&#xff0c;后一半从大到小输出等&#xff0c;那么这时候就需要用到排序算法&#xff0c;通过排序算法将数据按照一定的顺序进行排序。本文…

15分钟学Go 第8天:控制结构 - 循环

第8天&#xff1a;控制结构 - 循环 在Go语言中&#xff0c;循环是一种基本的控制结构&#xff0c;用于重复执行一段代码。今天我们将深入了解Go语言中的for循环&#xff0c;包括它的各种用法、语法结构、以及如何在实践中有效地应用循环。 1. for 循环的基本概念 for循环是G…

2024自动化测试面试真题(附答案)!

一、编程语法题 1 、 python 有哪些数据类型 python 数据类型有很多&#xff0c;基本数据类型有整型&#xff08;数字&#xff09;、字符串、元组、列表、字典和布尔类型等 2 、怎么将两个字典合并 调用字典的 update 方法&#xff0c;合并 2 个字典。 3 、 json.l python 如…

Java之继承抽象类用法实例(三十一)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

基于深度学习的AI生成式人脸图像鉴别原理

随着深度学习的发展&#xff0c;生成式AI模型&#xff08;如GANs&#xff09;能够生成高质量的逼真人脸图像。这些生成式模型在娱乐、艺术等领域发挥着重要作用&#xff0c;但同时也带来了对虚假信息、深伪图像&#xff08;deepfake&#xff09;的担忧。因此&#xff0c;如何鉴…

react18中如何实现同步的setState来实现所见即所得的效果

在react项目中&#xff0c;实现添加列表项&#xff0c;最后一项自动显示在可视区域范围&#xff01;&#xff01; 实现效果 代码实现 import { useState, useRef } from "react"; import { flushSync } from "react-dom"; function FlushSyncRef() {con…

怎么快速定位bug?怎么编写测试用例?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 作为一名测试人员如果连常见的系统问题都不知道如何分析&#xff0c;频繁将前端人员问题指派给后端人员&#xff0c;后端人员问题指派给前端人员&#xff0c;那么在…