Mirror Unity联网插件学习
学习视频链接: 【在unity中利用免费Mirror插件来制作网络多人游戏】 https://www.bilibili.com/video/BV15X4y1K7V9/?share_source=copy_web&vd_source=deaf604b58cb5a6dbd34d697e9efa138
部分笔记:
08:11
so this is part of the default Mirror Ui
所以这是默认Mirror Ui的一部分,
when you're hosting
当您托管游戏客户端时,
your game client is acting as both the server and the client, so if you ever wanted to have player hosted games ,you would have like a player host a match .
你的游戏客户端既是服务器又是客户端,所以如果你想让玩家托管游戏,你会希望玩家托管一个匹配的客户端,
for a client ,
it's uh it'll connect to the ip address you give it here , and localhost just means it's your it's your own ip address
它会连接到您在这里提供的IP地址,而localhost只是意味着它是您自己的IP地址。
and then for server , only instead of hosting , like being a server and a client this would be you're just acting as a server ,
与托管不同,就像同时作为服务器和客户端一样,在这种情况下,您只是作为服务器。
so you can't really play your name you're just hosting it
所以 你不能真正玩游戏 而只是托管它
(hosting,中文名为托管。 IP与多媒体 、网络销售领域术语。 指以外包方式包揽企业和消费者的信息技术应用、相关的硬件系统、网络服务等,可分网络托管、网站托管和应用托管等。)
17:13
弄了一个cube预制体
and we'll go ahead and assign that to our network manager ,
我们会继续把它分配给我们的网络管理器
so basically that we're doing here is using the player prefab we just created
警告说 Player必须有网络标识
18:55
public class Player : MonoBehaviour 改成
public class Player : NetworkBehaviour
and the NetworkBehaviour is pretty much ,a monobehaviour but with a lot of networking functionality ,added that's coming form mirror ,
so in the player calss ....
NetworkBehaviour 差不多...,但有很多网络功能,添加了来自镜像的功能,(应该是 networkBehaviour 有一些来自mirror的功能 )
在player类....中
在HandleMovement() 检查脚本是否运行,只想让本地的玩家输入
isLocalPlayer NetworkBehaviour 提供的一个字段
21:10
这个脚本每帧执行, 如果这个脚本挂载Player身上,就会 ...
23:19
Player预制体上 添加 network transform
【第二个视频 Introduction to Networking】
【第三个视频 Multiplayer Game Architecture in Unity (Unity 中的多人游戏架构)】
00:45 在最低级别的典型多人游戏中,我们拥有负责实际发送数据的层,构成游戏在互联网上 来回移动的零点, 数据通过网络发送,用于 注入同步之类的各种事情, 玩家移动攻击,和动画粒子,影响状态等,这是多人游戏的基础。 游戏最重要的是 游戏客户端和服务器应用程序, 使用Mirror,两者都是内置的,有很多游戏在使用。 无论如何,一个单独的服务器应用程序, 会涉及所有其他用于创建游戏模拟本身的代码, 并在多人游戏的后端管理游戏状态, 为游戏提供动力的服务,因此 其中包括 对接玩家、身份验证、数据库 和第三方api等,steam或playfab ,最终 we have our fleet of dedicated servers that are used to host games,
用于托管游戏的服务器,我们需要担心 诸如此类的问题,如果突然又玩家规模激增的情况, 如何管理我们需要推出的 更新和补丁,
以及 maintenance of a fleet to make sure that the servers are running 24 7
并且 尽可能高效得 回到过去, 自己在本地管理这些服务器,但如今 你会很漂亮的 crazy to not have your fleet in the cloud
您无论如何都选择云提供商,那么您还可以获得许多令人惊叹的功能和全球分布,
考虑到维护自己的服务器有多少麻烦。
一款多人游戏,您可以看到它实际上并不是一个特定的代码程序或应用程序,而是一个需要仔细设计和构建的分布式系统,以便为玩家提供尽可能最佳的体验, 让我们看一下 一些常见的网络 用于多人游戏的拓扑,从本地多人游戏开始
本地多人游戏 (沙发多人游戏)是迄今为止最容易理解且最容易实现的, 粉碎马里奥赛车 和使命召唤游戏 都是具有本地多人游戏的示例。
local multiplayer mode 本地多人游戏模式 同一台机器上同一屏幕(例如电视)上玩的游戏如果我们回顾一下我们的构建块,这里唯一涉及的是客户端应用程序,您甚至不需要连接到互联网
这些游戏,因此不需要运输或后端或fleet ,您
构建本地多人游戏的方式与构建任何其他单人游戏的方式类似,只不过您只需要处理来自多个的输入,一个玩家玩本地多人游戏,有很多优点,
03:57 本地多人游戏的优势,例如 最小延迟不为0,因为数据正在跨设备传输,但是由于距离太近延时就会很小,以至于出于所有实际目的,认为它约为0,
因为我们没有额外的成本,(支付带宽或服务器费用,也没有与网络相关的额外费用)后端服务不依赖专用服务器, 缺点非常明显,尽管 每场比赛你最多只能有大约四名玩家,因为再多的话你的屏幕就会变得混乱,这里也有明显的面对面限制,因为你必须在同一个地方才能玩,
land games are played in the same 局域网游戏是在局域网的同一地点进行的
在以前,他们非常受欢迎,尤其在《地震》和《虚幻锦标赛》等游戏中。虽然当时的在线多人游戏还处于初级阶段,但局域网聚会仍然受到大家的喜爱。而且,许多游戏都提供了局域网模式,这意味着它并不会被时代淘汰。as for our building blocks land games 至于我们的积木陆地游戏,由于根本不使用互联网,因此不需要后端服务和车队。但是,我们需要连接多个不同的设备,以满足游戏的需求。
接下来是点对点(Peer-to-Peer)的拓扑结构,这是游戏中最有趣的方面之一。当人们在游戏环境中提到点对点时,他们通常指的是这两种拓扑结构之一。第一种是直接点对点(Direct Peer-to-Peer),其中每个玩家都与其他所有玩家相连。这是从网络角度来看的点对点的最纯粹定义。而其他的点对点拓扑实际上只是客户端服务器结构的一种变体。
直接点对点拓扑结构是多人游戏中最有趣的一方面。当人们在游戏环境中提到点对点时,他们通常指的是这两种拓扑结构之一。
第一种是直接点对点,其中每个玩家都与其他所有玩家相连。这种拓扑结构对于多人游戏来说有点混乱,因为玩家必须处理巨大的数据传输量,每个玩家都要与其他人进行通信,这会使实施变得复杂。直接点对点也无法很好地扩展,还有一些安全问题,因为每个玩家的 IP 地址都会向其他人公开。
总的来说,我不会选择直接点对点,除非有特定的用例。
相比之下,我更倾向于玩家托管的客户端-服务器结构。
接下来是玩家托管的客户端-服务器模型。在这种模型中,玩家之一同时运行客户端和服务器应用程序,并充当主机。这集中了流量,大大简化了实施。如果我们看看我们的构建块,我们将需要除了服务器群之外的所有东西,因为我们使用玩家来托管游戏。这意味着我们真的可以节省很多钱。但是,玩家托管的客户端-服务器模型也存在一些相当大的问题。
下一个问题是玩家托管的客户端-服务器模型存在一些相当大的问题。首先,每个人都没有受到公平对待,因为主机可以拥有优势。这是因为他们以零延迟运行,这取决于每个人之间的距离,有些玩家可能会完全被搞砸,而其他玩家则很幸运。(06:07)此外,如果主机愤怒退出或离开游戏,游戏要么直接掉线,要么必须处理主机迁移。这会突然中断游戏,并且再次取决于每个人所在的位置,这可能会完全破坏某些玩家的体验。主机迁移也很难正确实现。这是玩家托管的客户端-服务器模型的另一个问题。
在玩家托管的客户端-服务器模型中,另一个问题是客户端服务器存在作弊行为。 在这种类型的拓扑中,基本上不可能完全防止主机作弊,因为服务器在他们的计算机上运行,他们可以或多或少地做任何他们想做的事情。 有很少的方法可以阻止他们。我个人会尽量避免玩家托管的游戏,因为用户体验不好。 但是这里可以节省很多钱,所以我理解为什么很多游戏最后都会走这条路。最后但绝对重要的是我们有专用服务器模型。
在该模型中,我们控制和管理服务器,无论它们是在本地还是在云中。我们可以使服务器变得像我们想要的那样强大,我们可以选择我们想要的服务器数量,并且可以灵活地扩展或缩小我们的服务器数量。我们还可以控制服务器的位置,以便无论您在哪里玩游戏,都可以享受到良好的体验。由于是我们而不是玩家控制服务器,因此我们可以确保更高水平的安全性和可靠性。不幸的是,为了获得这些甜蜜的好处,我们必须付出代价,因为我们还必须部署、管理和确保我们的服务器24小时7天运行。我们还必须处理额外的复杂性。但是,如果您想为玩家提供最好的可能体验,专用服务器是必经之路。
在多人游戏中,网络拓扑结构的选择对游戏的性能和稳定性至关重要。专用服务器是提供最佳体验的千分百可行方法。
以Fall Guys为例,一款受Fall Guys启发的游戏需要满足以下要求:
每场游戏最多支持60名玩家。
实时处理游戏、运动和物理现象。
需要各种后端系统,如配对、友谊提升系统和排行榜等。
这些要求需要一个强大的后端系统来支持,以提供流畅、稳定的游戏体验。
专用服务器可以提供这样的支持,同时确保游戏的性能和稳定性。我们需要储存各种类型的数据,包括玩家的物品、皮肤、成就和统计数据。
我们还需要跟踪一些分析数据,比如参与度。参与度可以转化为每日活跃用户或每月活跃用户。此外,我们还需要追踪保留率、增长、收入等方面的数据。
如果我们想通过实时移动和物理支持每场游戏最多60名玩家,那么我们就需要使用专用服务器。
我们无法让玩家托管这种游戏玩法,否则它就会变成垃圾。
因此,我们需要一组专用游戏服务器。但是我们应该如何实现呢?
我们有很多很好的选择。如果我们选择使用云服务,这是一个很好的选择。有亚马逊游戏升降机这样的专用游戏服务器托管服务,可以很容易地在亚马逊云平台 AWS 上部署、管理和扩展服务器。这是一个很好的选择,因为我们可以获得自动化的部署、自动化的备份、自动化的恢复和自动化的监控。此外,我们还可以获得负载均衡和高可用性,这对于我们的游戏服务器来说非常重要。我们可以设置多个服务器实例,以确保即使一个服务器出现故障,其他服务器也可以继续运行。这可以大大提高游戏的可靠性和稳定性。
此外,我们还可以使用云中的其他服务来增强我们的游戏体验。例如,我们可以使用云存储来存储玩家的数据和游戏内容。我们可以使用云数据库来存储和管理玩家数据和游戏数据。我们还可以使用云中的计算服务来处理游戏逻辑和进行实时计算。
通过使用云服务,我们可以获得无限的扩展性和灵活性。我们可以根据需要增加或减少服务器数量,以满足玩家数量的变化。我们还可以根据需要快速部署新的游戏功能或内容,而无需等待长时间的硬件部署和配置。
总的来说,使用云服务可以大大简化我们的游戏开发和管理过程。我们可以专注于游戏开发和创新,而无需担心服务器部署和管理的问题。这可以让我们更加专注于游戏玩法和用户体验,从而为玩家提供更好的游戏体验。
在AWS、Azure PlayFab和谷歌云这些平台中,托管游戏服务器变得相当简单。AWS是亚马逊的云服务,Azure PlayFab则是微软提供的托管服务,两者都使得管理动态扩展的服务器群变得非常容易。谷歌云平台(GCP)也提供基于Kubernetes的游戏服务器托管服务,Kubernetes是一个在游戏行业中非常流行的技术,用于自动部署、扩展和编排服务器集群。除了这三个平台,还有很多其他的游戏服务器托管平台,但在我看来,这三个是目前为止基于生态系统功能的最佳平台。至于定价,它们中的任何一个都是合理的选择。
很难给出确切的成本,因为这取决于你的需求,但所有这三个平台(AWS、Azure PlayFab和谷歌云)或多或少都在同一个范围内。玩家身份验证是当今每个多人游戏的核心,玩家希望能够以方便和自然的方式进行身份验证。根据你的平台和分发方法,你可能需要使用最适合你的游戏的身份验证提供商。当然,你仍然可以提供传统的用户名和密码或电子邮件和密码作为选项,但在我看来,允许玩家链接其他帐户是很常见的。在我看来,PlayFab 击败了其他所有竞争者。他们提供了与 Steam、苹果、谷歌、Facebook、Twitch 等平台的集成,你不需要担心管理身份验证数据或数据库。
关于玩家身份验证和匹配服务,这是游戏后端最复杂的部分。
如果你想自己构建一个玩家身份验证和身份服务,这需要大量的工作。
匹配可能是多人游戏后端最复杂的部分,所以让我们快速回顾一下匹配过程中实际发生了什么,然后我们将讨论可用的最佳解决方案。
当一个或一组玩家想要一起玩时,一个玩家会创建一个匹配票并将其提交到匹配服务负责的匹配队列。匹配服务根据一组规则使用这些门票来填充比赛。
关于PlayFab,他们提供了与Steam、苹果、谷歌、Facebook、Twitch等平台的集成,你不需要担心管理身份验证数据或数据库。他们的API真的很好,如果你想自己构建一个玩家身份验证和身份服务,这是一个很好的选择。但是请注意,这将显着增加工作量。
玩家将享受一致的游戏体验,因为匹配服务会尝试将比赛放在具有最低延迟的服务器上。一旦潜在的比赛完成并被所有玩家接受,玩家就可以享受一致的游戏体验。匹配服务将尝试将比赛放在您的服务器队列中的一台服务器上。之后,匹配服务将向游戏服务器发送开始请求以及一些附加数据。一旦服务器收到该请求,它将启动一个新的游戏会话。当准备好接受玩家时,它会通知匹配服务。一旦游戏会话准备好,匹配器将使用连接信息和附加数据更新所有玩家门票。一旦将其转发回每个玩家的客户端,玩家将加入托管在服务器上的游戏并开始玩。
关于玩家身份验证和匹配服务,这是游戏后端最复杂的部分。如果你想自己构建一个玩家身份验证和身份服务,这需要大量的工作。匹配可能是多人游戏后端最复杂的部分,所以让我们快速回顾一下匹配过程中实际发生了什么,然后我们将讨论可用的最佳解决方案。
当一个或一组玩家想要一起玩时,一个玩家会创建一个匹配票并将其提交到匹配服务负责的匹配队列。匹配服务根据一组规则使用这些门票来填充比赛。
关于PlayFab,他们提供了与Steam、苹果、谷歌、Facebook、Twitch等平台的集成,你不需要担心管理身份验证数据或数据库。他们的API真的很好,如果你想自己构建一个玩家身份验证和身份服务,这是一个很好的选择。但是请注意,这将显着增加工作量。
所以,你可以看到这是一个非常复杂的过程,并且自己实现这个功能可能会非常困难。这就是为什么你应该使用现有的匹配服务的原因。
在我看来,最好的游戏匹配服务是亚马逊的Gamelift、Playfab和谷歌的开源框架Open Match。我知道你可能已经厌倦了一遍又一遍地听到亚马逊、微软和谷歌,但他们确实在多人游戏方面做了很多。
我们的整体架构现在看起来像这样。客户端既与匹配服务通信,也与身份验证服务通信,并在加入游戏时直接连接到我们队列中的各个服务器。这是一个非常复杂的过程,需要仔细规划和设计。
当玩家加入游戏时,我们需要某种最友好的服务来管理每个玩家的朋友列表,以及通过他们的链接帐户从Steam、Xbox、PlayStation、Facebook或其他任何地方连接朋友。具体取决于您需要哪些连接平台,您可能需要将几个不同的API拼接在一起并构建自己的服务,或者您可以选择使用playfab的无朋友服务,这非常好,并且提供了各种集成。
在我们的架构图中,我们只需将我们的朋友分组到匹配服务中,以便我们可以将其称为服务层。好的,所以排行榜类似于朋友列表,我们可以构建自己的,但一个简单的方法是开始使用。
当我们需要构建一个排行榜系统时,我们通常可以选择使用Steamworks的排行榜API或playfab的排行榜API。两者都非常出色且易于使用。然而,请注意,Steamworks API仅适用于Steam平台上的游戏。对于大型AAA级游戏,例如《英雄联盟》,由于它们处理的数据量巨大,其排名系统会更加复杂。这不仅是因为数据规模庞大,还因为实时处理的要求非常高。因此,对于大型游戏,构建一个排名系统需要更多的技术和资源投入。
当需要构建排行榜系统时,我们可以通过Steamworks的排行榜API或playfab的排行榜API进行操作。两者都非常出色且易于使用。然而,Steamworks API主要适用于Steam平台上的游戏。对于大型AAA级游戏,例如《英雄联盟》,由于处理的数据量巨大,其排名系统会更加复杂。这不仅是因为数据规模庞大,还因为实时处理的要求非常高。因此,对于大型游戏,构建一个排名系统需要更多的技术和资源投入。对于中小型游戏,我们可以使用简单的第三方解决方案来解决问题。
多人游戏的另一个核心部分是需要管理持久数据,例如玩家物品和购买、成就统计数据等。为此,我们需要使用数据库。
对于我们的游戏,我们可以使用托管在主要云平台之一上的简单 SQL 数据库。我建议使用像亚马逊 aurora、谷歌的云 sql 或 postgres 的 azure 数据库这样的服务。 这些都是托管数据库,因此我们可以自动完成许多耗时且容易出错的。任务,例如备份。由于我们不希望游戏客户端直接查询和与我们的数据库进行交互,因此我们需要使用 API 进行安全的数据访问和操作。 由于安全问题,我们将使用一个自定义的API层。这个API层将在简单的虚拟机上部署,以提供游戏数据,但以JSON格式通过HTTP。这样我们能够更轻松地访问和控制数据。在将来,我们甚至可以将这些服务分成单独的部分。每个主要的云提供商都提供虚拟机(VMS),因为数据库和API本身就是大的主题,我会就此打住,我不想在这里深入讨论。
至于分析,我个人最喜欢的是gameanalytics.com,因为它的易用性。在这个系列中,我会为每个部分制作专门的视频。当我们使用Unity大致基于Fall Guys构建我们自己的多人游戏时,我会提供专门针对每个部分的视频。我们将使用Unity和Mirror网络库。
无论如何,Mirror网络库就是这个视频的内容,我确实在这个视频中投入了大量的精力,所以我希望它对你有用,但无论如何,下面有我们的链接,所以一定要加入它,来闲逛,下次见,感谢观看。
【Synchronizing Data between Clients/Server | Unity Multiplayer Tutorial】 【在客户端/服务器之间同步数据 |Unity 多人游戏教程】
因此,随着我们继续构建多人游戏,我们将需要执行与数据同步相关的几项任务,例如同步对象属性,以及在响应事件时发送和接收消息,例如玩家加入或离开游戏,或游戏开始以及多人游戏中发生的各种其他事件。
Mirrors API 为我们提供了三种方法来实现这一点。
第一种是回调,Mirror 提供了许多回调,让我们可以连接到游戏中发生的事件,例如玩家加入或离开,对象生成或销毁,服务器启动或停止,以及各种其他事情。如果我们想连接到更一般的事件,例如客户端连接或断开连接,我们将使用网络管理器提供的回调;而对于在游戏对象级别发生的更具体的事件,我们将使用网络行为提供的回调。
Mirror 还具有命令和远程过程调用(RPC),基本上是我们在代码中调用网络上的函数的方式。如果我们希望客户端调用服务器上的方法,我们将使用命令;另一方面,如果我们希望服务器调用客户端上的方法,我们将使用 RPC,Mirror 中的这一过程非常无缝,因此每当您调用命令或 RPC 时。
差不多就是这样,当我们继续构建多人游戏时,我们将需要执行与数据同步相关的几项任务,比如同步对象属性,或在响应事件时发送和接收消息,比如玩家加入或离开游戏,或游戏开始时以及多人游戏中发生的各种其他事件。Mirrors API 为我们提供了三种方法来实现这一点。第一种是回调,Mirror 提供了许多回调,让我们可以连接到游戏中发生的事件,比如玩家加入或离开,对象生成或销毁,服务器启动或停止,以及各种其他事情。如果我们想连接到更一般的事件,比如客户端连接或断开连接,我们将使用网络管理器提供的回调;而对于在游戏对象级别发生的更具体的事件,我们将使用网络行为提供的回调。Mirror 还具有命令和远程过程调用(RPC),基本上是我们在代码中调用网络上的函数的方式。如果我们希望客户端调用服务器上的方法,我们将使用命令;另一方面,如果我们希望服务器调用客户端上的方法,我们将使用 RPC,Mirror 中的这一过程非常无缝,因此每当您调用命令或 RPC 时,它几乎与调用任何其他方法完全相同,所有的序列化和传输层面的事务都在底层为我们处理。
然而,Mirrors API 仍然为我们提供了一种更低级别的方式来直接在客户端和服务器之间发送消息,这在我们需要优化性能或处理一些非常复杂的数据结构时非常有用。很多人认为一旦选择了 Mirror,就会受到很大的限制,但实际上它非常灵活,因为您总是有这个选项,如果想要使用更底层的原语来实现一些东西。
在这个视频中,我们将介绍回调、命令和RPC,而在后续的视频中,我们将讨论低级网络消息和序列化。您可以在GitHub上找到所有的代码,我在下面链接了项目存储库。我们还有一个社区 Discord 服务器,所以欢迎加入并随时提问。
那么,Mirror 是如何跟踪游戏中每个网络对象的呢?
这就是网络身份组件的作用。当带有网络身份组件的对象被生成时,Mirror 会为该网络身份(NetworkIdentity)分配一个Net ID,这是一个无符号整数,Mirror 在客户端和服务器之间传递消息时使用,以确定向哪个对象发送消息。
您必须在运行时在每个Prefab上放置一个网络身份组件,以便告诉Mirror哪些对象需要同步。这也是为什么网络身份组件中有一个服务器专用选项的原因。如果选择此选项,Mirror 将仅在服务器上生成此游戏对象,而不会在任何客户端上生成,这在许多情况下都非常方便。
在我们开始传递数据之前,我们需要了解网络授权(Network Authority)的概念。为什么我们需要了解这一点呢?因为我们必须能够确定在任何给定对象的状态方面,谁是真相的最终来源,以便确保所有人都在同一页面上。
在Mirror中,要么客户端拥有一个对象,要么服务器拥有它。
默认情况下,服务器拥有所有对象,但我们可以将授权移交给客户端,以便他们能够控制某些需要控制的东西,比如玩家输入。我们有三种方式可以将对象的授权交给客户端。
我们可以使用NetworkServer.AddForConnection
生成一个玩家对象,在这种情况下,与该连接关联的客户端将自动获得对玩家对象的授权。
我们还可以在对象生成时将授权交给客户端,此时我们只需传入与客户端相关联的连接,然后使用NetworkServer.Spawn
响应此游戏对象。
最后,我们可以通过在NetworkIdentity
类上使用AssignClientAuthority
方法来将授权交给客户端。
在这里,我们在要授予授权的对象的NetworkIdentity
上调用此方法,并传入与客户端相关联的连接。
如果我们想从客户端收回对象的授权,我们可以使用RemoveClientAuthority
方法,但我们不能从玩家对象中移除授权,因此在这种情况下,我们将使用NetworkServer.ReplacePlayerForConnection
来替换玩家对象。
好的,让我们快速浏览一下这些回调,这样您就能了解有哪些可用,但所有这些都在API参考中,所以无需记住其中任何一个。
对于网络管理器,如果我们想要在这些事件发生时调用自定义代码,我们需要创建一个新的脚本,继承自网络管理器。所以将来请记住这一点。
现在在服务器上,这是我们可以使用的网络管理器的回调。
我们有OnStartServer
和OnServerSceneChanged
,这些与服务器启动或场景更改相关。
我们有OnServerConnect
、OnServerReady
和OnServerAddPlayer
,这些与客户端连接、准备就绪以及玩家对象生成相关。
我们还有OnServerDisconnect
和OnStopServer
,这些与客户端断开连接和服务器停止相关。
在客户端上,这些是回调。
我们有OnStartClient
、OnClientConnect
、OnClientChangeScene
和OnClientSceneChanged
,这些都与客户端启动并连接 以及场景更改有关,
在这个类中,我们将使用我之前提到的一些回调,只是为了看看它们是如何工作的,以及我们如何连接到它们。
首先,我想连接的是OnStartServer
回调,在这里我们可以写一些像“服务器已启动”的东西。
public class MyNetworkManager : NetworkManager
{
public override void OnStartServer()
{
Debug.Log("Server started");
}
public override void OnStopServer()
{
Debug.Log("Server stopped");
}
public override void OnClientConnect(NetworkConnection conn)
{
Debug.Log("Connected to server");
}
public override void OnClientDisconnect(NetworkConnection conn)
{
Debug.Log("Disconnected from server");
}
}
接下来,我们返回Unity,创建一个空的游戏对象,将脚本MyNetworkManager
拖入其中。还需要NetworkManagerHUD
,用于提供主机、加入客户端和作为服务器启动的按钮。将Player Prefab分配到空的Player Prefab插槽中。
然后,我们在Unity中点击播放,创建两个编辑器窗口,一个主机,一个加入。在主机窗口中,我们应该能够看到OnStartServer
和OnClientConnect
回调的消息。
接着,我们在加入的窗口中加入客户端,应该能够看到OnClientConnect
的消息。
最后,我们停止服务器,应该能够看到OnStopServer
和OnClientDisconnect
的消息。
通过这个简单的示例,你应该能够看到如何使用Mirror的回调来处理服务器和客户端的生命周期事件。这样,我们可以方便地通过自己的逻辑响应这些事件,而不必从零开始实现所有这些回调。
产生在左侧、在右侧生成,而在客户端,我将继续按X键,我们可以看到我们已经向服务器发送了“ola”的消息,这在客户端上刚刚被记录,然后在服务器的日志中,我们可以看到我们收到了来自客户端的“ola”消息。因此,命令设置起来相当迅速简便,相信我,你将一直在使用它们,我知道这有点刻意的例子,但我认为它传达了要点。所以我们已经看过了如何从客户端调用函数并在服务器上运行,但反过来呢?从服务器调用函数并使其在客户端上运行呢?好吧,我们有两种方法可以做到这一点,在Mirror中,第一种方法是使用Client RPCs,Client RPC调用是从服务器上的对象发送到客户端上的对象的,它们可以从任何已经生成了带有网络身份的服务器对象发送,与命令一样,对于Client RPC调用,我们不必担心安全性和权限,因为服务器具有权限,所以任何服务器对象都可以调用客户端RPC。创建客户端RPC与创建命令一样简单,我们只需要将ClientRPC属性添加到方法中,现在当在服务器上调用此方法时,此方法将在客户端上运行。您可能会想,好吧,我们运行该功能的客户端是哪个?所有这些吗?其中一些吗?好吧,这取决于谁正在观察对象,根据对象的网络可见性,默认情况下,每个人都在观察对象,所以每个人都得到了该调用,但正如您现在可能在思考的那样,这不是很高效,答案是在某些情况下是的,例如,假设我们的玩家有一个物品清单,我们拾取一个物品,假设该信息通过服务器作为客户端RPC发送给所有人,但只有我们的清单得到了更新,因此如果我们是唯一能看到更改结果的人,因为我们是唯一能打开我们的清单并查看里面内容的人,那么为什么其他人也会收到该信息?这不是浪费吗?好吧,是的,这是浪费,在这种情况下,修复非常简单,但总的来说,网络可见性可能变得非常复杂,而Mirror确实有这方面的解决方案,但我现在将保持简短,并且我们将所有这些留到将来的视频中,无论如何,客户端RPCs对参数数据类型有与命令相同的限制,但再次,10次中有9次它对您来说不应该是个问题。好的,让我们继续尝试客户端RPCs。所以我将打开玩家脚本再次在我们的玩家类下面,我将创建一个名为tooHigh的新方法,在这里我们将记录我们太高的消息,让我们将其设置为客户端RPC,所以为了重申,该方法在服务器上被调用,但实际上在所有客户端上运行。在Update中,让我们检查我们是否在服务器上运行,并检查对象的当前位置是否在y级别以上,比如说50,如果是真的,那么我们将调用tooHigh,所以这里发生的是基本上每当我们的玩家游戏对象太高,或者我猜是在y轴上方50,就会在服务器上调用这个tooHigh方法,并在所有客户端上运行,我们应该看到“太高”的消息在控制台上打印出来,当我们实际运行它时。让我们试试吧。回到Unity,再次点击两个编辑器上的播放按钮,就像之前一样,我将在左边的编辑器上托管,在右边作为客户端加入,我将准备好,以便我们都生成了,所以在右边的编辑器上,我将继续上升,直到我们得到那个消息,你可以看到它有点刷屏,这不应该发生,所以让我们清除一下,看起来我们没问题,我们只是在左边的编辑器中打开场景视图,这样你就可以看到发生了什么,所以我将继续上升,上升,上升,上升,上升,当我们越过那个阈值时,消息开始弹出,当我们回去时,它们停止,所以看起来它显然是在运作,而且由于我们在左边的编辑器上运行,这意味着我们既是服务器也是客户端,所以如果你想知道为什么消息会出现在两个控制台上,这就是原因,所以我只是想指出,我们在这里做的事情实际上非常愚蠢,我们不应该在update循环中调用客户端RPC,因为我们基本上是在网络上传播消息,这实际上是一个非常糟糕的实践,所以我只是想要删除它,但我认为你对整体的想法有所了解,好吧,现在目标RPCs是我们可以从服务器调用函数并使其在一个目标客户端上运行的另一种方法,尽管与客户端RPC不同,目标RPCs仅在一个单独的目标客户端上调用,而不是在每个客户端上,我们可以使用TargetRPC属性将函数转换为TargetRPC,就像我们为命令和客
户端RPC所做的一样,TargetRPC函数由我们在服务器上的对象上的代码调用,然后在与我们提供的网络连接对应的客户端上调用,因此如果我们的TargetRPC方法的第一个参数是一个网络连接对象,那么在服务器上调用此方法时,将在与该连接相关联的客户端上调用TargetRPC,如果第一个参数是任何其他类型,则拥有包含我们的TargetRPC的脚本的对象的客户端将是接收消息的客户端,所以它有点隐含现在如果我们回到我们的代码,并尝试自己尝试下面的命令,让我们在我们的命令下面创建一个名为replyOla的新方法reply ola并在这里我们将记录我们已经从服务器收到的ola,让我们将其转换为TargetRPC通过添加该属性因此这里发生的是每当在我们的客户端上按下x键时,它应该记录我们正在向服务器发送ola然后在我们的客户端上调用这个ola命令这里的代码将在服务器上运行,因此在服务器上我们应该看到收到来自客户端的ola然后我们调用这个TargetRPC reply ola的代码将在包含此对象的客户端上运行与我们提供的连接对应,所以我们应该在该客户端的控制台上看到来自服务器的ola收到的消息,现在我们将在右编辑器上再次按下x,你会看到我们已经发送ola到服务器服务器已收到ola来自客户端,客户端已收到来自服务器的ola,所以我们已经向服务器发送了一些东西,而服务器已经回应了我们所以这种使用命令进行通信然后使用TargetRPC回到在第一次使用命令的客户端进行回复的模型,是你将在所有地方看到的模型,所以希望这更好地说明了命令和RPC是什么以及它们在Mirror中是如何使用的。总之,这涵盖了Mirror提供的所有远程操作,简单回顾一下,我们有命令,它们由客户端调用并在服务器上运行,有客户端RPC,它们由服务器调用,并在所有客户端上运行,您知道有一个风险,由于我们可以配置为。