【Unity网络游戏学习笔记】(3) 快速创建你的第一个Mirror服务/客户端游戏(二) 您所在的位置:网站首页 魔戒ios下载 【Unity网络游戏学习笔记】(3) 快速创建你的第一个Mirror服务/客户端游戏(二)

【Unity网络游戏学习笔记】(3) 快速创建你的第一个Mirror服务/客户端游戏(二)

2024-06-02 06:43| 来源: 网络整理| 查看: 265

前言

  断更了大半年但依然有人看就继续忙里偷闲更新好了。。。最近一直在用Mirror做一些大的小的联网游戏,所以自己对Mirror的新功能/已有功能有了更深的理解,所以这一系列的笔记在短期内会着重于Mirror相关的内容。

简介

在前文中,我们初步完成了Mirror联网游戏插件的第一个小示例的一部分:

服务端开启后,多个玩家可以从他们的客户端游戏中连接进去

客户端连接成功后,每个玩家能且只能控制其游戏角色(一个方块)

我们接下来开始用代码完成剩余的部分:

玩家在他们的键盘上按下WSAD后,服务端让其移动,并将他们的位置实时同步到其它客户端中

玩家按下空格键后,服务端为它们的角色随机变色,并将颜色同步到所有客户端上

我们首先完成第三个

3. 移动并同步玩家NetworkTransform组件

在上一个笔记中,如果你是细心的读者,你可能会尝试去在Inspector面板中拖动生成的两个玩家。然而你会发现,这可能并没有什么卵用 — 无论在哪个端(服务端/客户端)改变物体的位置,其位置都不能在其他客户端上面同步。

这是因为联网游戏中数据同步一直是一个比较复杂的过程,尤其是对于物体位置等这种需要实时同步的数据。在下一节中,我们会更详细的介绍数据同步相关的内容。

在Mirror中,不同数据有时有不同的同步方法,而Transform组件的同步就是其中一个例子。在Mirror中,如果想同步Transform组件,则该物体必须挂载NetworkTransform组件。NetworkTransform组件的具体使用会在未来介绍,但现在我们为我们的玩家Prefab挂载上该组件:

可以看到 NetworkTransform 中有很多属性(如果你用的是旧版本Mirror那么东西会稍微少一些)。在这节中我们仅介绍几个比较重要的:

Authority:操作权限。如果Client Authority被勾上,那么**只有在客户端改变物体Transform时才会同步Transform,且服务端无权改变物体的Transform;反之亦然。**从反作弊的角度来看,通常不勾上是更好的选择,即只有服务端有权限改变物体的Transform — 但是从个人最近制作的几个项目的经验上来看,有不少类型的游戏并不适合这么做,具体原因我们会留到以后讨论。但我们现在先不勾上它

Sync Position / Sync Rotation:是否同步位置/旋转。如果不勾上的话,如果服务端改变的物体的位置/旋转,客户端将不会有反映。所以我们这里都勾上

Interpolation:是否进行补间动画。这个意思是,通常由于网络延迟等问题客户端可能出现丢包的情况,即没有来得及/能够同步服务端的位置/旋转。如果不勾上的话,物体会在客户端这里发射”瞬移“的情况。如果勾上的话,物体将会平滑地移动过去。

其他属性我们会留到专门将NetworkTransform的时候再讲。

所以我们现在要做的就是维持他现在的样子即可。现在我们进入游戏,并在Unity这里开启Server,然后在Inspector面板中随意拖动物体,我们就能看到客户端这边的物体的位置也能同步了:

需要注意的是,由于我们的NetworkTransform是ServerAuthority的,所以在客户端上改变位置是不会同步到其他客户端的

使用代码操作物体位置

我们现在来使用代码来改变物体的位置(WSAD控制)

我们正常创建脚本,命名为Player,并将其挂载在玩家身上。

由于联网游戏数据和操作权限的问题,服务端和客户端的代码一般是要单独处理的 — 即服务端的代码只能让服务端运行,客户端的代码只能让客户端运行。而Mirror为我们提供了这样的一套框架,以及服务端与客户端来回直接的调用,省去了很多我们的时间。

我们首先来梳理一下逻辑。如果要用代码控制玩家移动,我们需要做什么:

游戏要接收来自玩家的输入。玩家来自客户端,所以这部分的代码必须由客户端执行

客户端收到输入后,需要将输入的键位或移动的方向传递给服务端

服务端受到客户端的输入后,验证客户端输入的合法性,然后改变物体的位置

由于NetworkTransform组件,服务端改变的位置会直接同步到客户端上。

OK,看上去比单机游戏复杂了不少,因为这过程中多出了服务端与客户端执行代码的分离与调用。我们一步一步来。

首先,我们需要让脚本继承NetworkBehavior类。可以把NetworkBehavior想象成联网的MonoBehavior,即所有需要同步数据或分离客户端/服务端代码的脚本都需要继承这个类以获取这个功能。在Mirror中,NetworkBehavior继承MonoBehavior。

我们首先接受客户端的输入。我们先正常写一个Update函数,然后使用如下代码:

HasAuthority, IsClient, IsServer, IsLocalPlayer

hasAuthority是NetworkBehavior中自带的一个属性,其代表 ”如果当前玩家(端)对该物体持有权限,则返回true“。换句人话说,如果在一个玩家的机子上,这个玩家对这个物体有操作的权限,则返回true。

什么是操作的权限?在Mirror中,服务端可以将一个NetworkIdentity的connectionToClient属性设置为一个客户端。在设置完成后,这个物体就视为”属于“这个客户端了,即这个客户端对该物体有权限。如果一个客户端对一个物体有权限,那么它下面所有脚本的hasAuthority就是true。Mirror的玩家Prefab的权限是默认给”属于这个玩家Prefab的玩家的“,因此不用手动给权限。

换句话来说,对于你来说,你的玩家Prefab的权限是你自己,但是对于其他人来说,在他们游戏中你的Prefab的这个脚本的这个hasAuthority就是false。

同样的道理,在mirror中还有isClient, isServer这样的属性,分别代表是否在客户端上和是否在服务端上。需要注意的是 isClient和hasAuthority一般都在客户端上生效,它们唯一的区别是isClient不看权限,而hasAuthority必须在有权限的玩家的机子上才是true。换句话说,对于其他玩家来说,你的玩家Prefab的isClient也是true。

在Mirror中还有一个isLocalPlayer的属性。这个属性代表该物体是否是当前玩家的玩家Prefab。其效果和我们前面写hasAuthority是一模一样的,但是该属性只在玩家Prefab的脚本上才会生效。

客户端控制代码

话说了那么多,终于可以继续写操作代码了。我们首先先用非常传统的方法获得操作轴。

于是我们接受客户端输入的代码就搞定了。

接下来,我们需要将h和v的值传递给服务端。可能会有盆友联想到前面的isServer,然后直接把h和v声明到外面,再写一个判断。但是这是不行滴 — 因为对于远在某处的服务器来说,从它的视角看,它的h和v依然是0,因为现在的h和v仅仅是在客户端上做变化而已。所以我们要真正地传递我们的数据给服务器。

Mirror为数据传递提供了解决方案,其官方名字为”Remote Action“(远程操作?)。听上去很高级但实际上就是打了特殊特性(标记)的函数。依旧先贴代码后解释 — 我们创建一个这样的函数:

可以看到,这种写法和我们在单机游戏中的写法的唯一区别就是我们移动玩家的函数头上多了一个[Command] 特性。这个[Command] 特性在Mirror中指的是该函数只能被客户端调用,且只能在服务端上运行,且其参数相当于客户端所传递的信息。 在Mirror中,有很多类似的这样的消息传递的远处操作,且它们都对参数的类型有部分限制,这些都会留到之后再讲。

除此之外,还有一个非常容易忽视的点就是:在Mirror中,所有带有[Command]特性的函数的名字开头必须是Cmd!否则会出现无法成功调用的问题。

我们现在梳理一下逻辑 — 在Update中,如果我们是操作这个玩家物体的玩家,则脚本会获取到我们的输入轴,随后调用CmdMovePlayer函数。调用这个函数的过程相当于把这两个参数传递给服务端,并且通知服务端执行该函数,即改变物体的位置。由于NetworkTransform组件,物体的位置会在其他客户端中同步。我们看一下效果:

除了不小心把速度调太大了以外,其他看上去都很nice的样子。

细心的读者可能会发现,我们在实际步骤中少了服务端验证客户端的步骤。在正式游戏中,验证来自客户端传递的参数是很重要的一个步骤。所有通过客户端执行的操作实际上都需谨慎处理 — 最理想(避免作弊)的代码通常是由服务端执行尽可能多的运算,但由于游戏不可避免地需要接收用户的输入,客户端代码与客户端与服务端的调用也是无法避免的。因此,为防止客户端使用作弊插件/硬件甚至反编译注入非法参数,服务端需要验证客户端参数的合法性,这一步骤通常是比较复杂的。因此在这一系列中我通常会跳过这一步骤,但在实际开发中一定需要避免。

总结

   在本篇中,我们终于写下了学习Mirror以来的第一个脚本,了解了一些获取当前权限的属性(isClient,hasAuthority等),并且学习了第一个客户端-服务端远程操作特性[Command]。在下一篇中,我们将通过变色的案例了解我们自己写的脚本中的数据(变量)是如何像NetworkTransform那样在服务端/其他客户端间同步的。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有