Unity3D-同一个局域网联机
同一个局域网内联机
联机如何实现?
服务器判断:
玩家 a 移动,在其他玩家眼里也会动。一般通过一个中心服务器 Server 实现,首先玩家 a 的客户端 clientA 向 Server
发送控制移动的输入,Server 判断玩家 a 能否移动,Server 判断完毕后,将结果发送给 ClientA 和 ClientB 等其他
客户端。客户端接收到消息后再渲染出动画。问题就是有网络延迟。
客户端判断:
玩家 a 移动,在自己的客户端中判断是否能移动,然后将移动的消息传给 Server,但是 Server 不需要传回 ClinetA。
然后 Server 更新自己的信息,再同步发送到 ClientB 等其他客户端。问题就是客户端可以发送 Server 虚假的信息,
也就是外挂。
同步
多个客户端描述的同一个游戏场景,再 clinetA 中玩家 a,b,c 的坐标和 ClinetB 中 a,b,c 的坐标应该是一致的,
由于有网络延迟的存在,不可能完全一致。
例如由于网络延迟的原因会造成玩家不同的运动轨迹
权衡利弊后根据某个玩家的状态去同步其他玩家
实现
在 unity 中实现了很多网络通信的包,除了 Server 和 Clinet 外,还有一个 host。host 就是主机,即 Server 和 Client 合二为一
安装网络资源包
com.unity.netcode.gameobjects(需要更新到 Unity 2021.3 及以后版本才能看到)
- 工具栏:Windows->Package Manager
- 左上角改为: Unity Registry,找到对应的包,右下角 install(已经安装则显示 Remove)
配置网络组件
创建空 Object,命名为 NetworkManager 管理所有需要联机同步的物体,添加组件(add component) NetwortkManager
此时可能 NetworkManager 会有两个警告:安装包 Multiplaers Tools(按照上文方法);选择 NetworkTrnasport 后即可消除
添加需要同步的元素 Player
在 Assets 里创建一个文件夹 Prefabs,将 Player 拖到这个文件夹里,此时可以删除掉左侧的 Player
如果在 Clinet 中摧毁了一棵树,ClientB 怎么知道摧毁的是树而不是车?所以所有需要网络同步的物体需要有一个唯一 id
给 Player 添加一个 NetworkObject 组件,就会有一个全局哈希值作为唯一编号
添加 Player 到 NetworkPrefabs,在 Default Network Prefabs
在 Player 组件中再 add component 一个 Network Transform,用于选择需要同步的信息
根据提示,在 Player 组件中再 add component 一个 Network Rigidbody
此时 unity 可以自动帮我们同步 Player
除了同步玩家以外,还需要同步 Camera,双击Player,在Camera里同样也添加一个 Network Transform,用于选择需要同步的信息。
另外 Camera 的父组件 Player 已经有一个唯一编号,所以 Camera 不需要唯一编号
实现开局创建自动创建角色
点击 NetworkManager,将 Player 拖到 Player Perfab 上
此时点击运行游戏,会发现黑屏,原因是因为 Camera 是在 Player 上,开局并没有创建角色就没有 Camera
添加一个 Camera 用作展示初始界面,调整角度位置
开始运行游戏,点击左侧 Don’tDestroyOnload,点击 NetworkManager,右侧会出现三个选项:
startHost、StartServer 和 StartClinet
点击 starthost 发现自动创建了一个 Player,但是位置是初始位置,可以把Environment的纵坐标往下移动2个单位
添加 ui,把 startHost、StartServer 和 StartClinet 作为按钮放入到游戏里。右键新建一个 ui/canvas.
重命名为 menuUI。
在 canvas 里添加按钮,右键 MenuUI 新建 Button,如果有提示需要 import 就按照提示 import
此时运行游戏
写按钮的逻辑:
给 NetworkManager 添加一个脚本 NetworkManagerUI
1 | using System.Collections; |
此时点击相应的 button 就有相应的操作
禁用非本地玩家的组件
此时直接运行 host 和 client,会发现两个角色会同时移动,并且 unity 中显示有多个 Audio 被使用的警告
原因是在一个 Player 中,没有禁用其他 Player 的输入控制和 Camera;并且开始菜单的 Camera 和本地 Player 的 Cameara 也会有冲突
在 Player 中添加一段脚本 PlayerSetup 解决此问题
1 | using System.Collections; |
将需要被禁用的组件拖到列表中:
注意代码sceneCamera = Camera.main;
需要把SceneCamera的tag改为main
此时开启两个窗口运行游戏,发现一个能移动,一个不行,这是因为unity默认是以服务器判断方式。Unity默认不信任客户端,没有授权,需要自己写一段脚本打开授权
在Assets/Scripts/Network/里新建一个脚本ClientNetworkTransform.cs
1 | // 引入必要的命名空间 |
代码含义:重载NetWorkTransform
中的授权函数
所以,要将用到NetWorkTransform
的地方改为ClientNetWorkTransform
Player:
删除 Network RigidBody
和Network Trnasform
添加 ClientNetworkTransform
和Network RigidBody
此时就实现了本地联机并且多个Player都可以移动