【技术博客】Unity多人在线同步 | week9
Unity单机场景快速转换多人联机教程
简介
本教程基于Mirror实现:
Unity AssetStore链接:https://assetstore.unity.com/packages/tools/network/mirror-129321
官网:https://mirror-networking.com/
文档:https://mirror-networking.gitbook.io/docs/
场景的创建
首先我们需要一个已经实现好的单机场景,这个场景在后续将被用作多人场景,现在按CTRL+D复制一份它,重命名为GamePlay。之后我们再创建一个场景Offline和一个场景Online,分别表示大厅(此时还未连接至服务器)和房间(连接至服务器但未开始游戏)。具体来说,运行机制是首先玩家进入Offline等待,选择服务器后跳转至Online,最后开始游戏则在GamePlay中。
网络控制器
下面我们在Offline中创建一个空物体名为NetworkManager。创建一个脚本为MyNetworkManager.cs,注意创建时通过Mirror创建NetworkManager,如下图。
![image-20220501160615067](https://umeta.oss-cn-beijing.aliyuncs.com/blog/image-20220501160615067.png)
之后再将其挂载在之前创建的空物体上即可。此外还需要加上下面两个,其中NetworkManagerHUD是可视化UI,可先用其简单快速上手控制服务器的连接,后期可删除,将功能通过代码写在NetworkManager中。下面的Transport是传输协议,可选KCP(使用UDP)或Telepathy(使用TCP)。
![image-20220501160828106](https://umeta.oss-cn-beijing.aliyuncs.com/blog/image-20220501160828106.png)
网络控制器暂时先这样就完成了。
游戏玩家与物体
在游戏中所有游戏物体均要有NetworkIdentity,因此先把之前的所有物体(如玩家、子弹等需要同步的)制作为新的预制体,并加上下面这个。
![image-20220501161349143](https://umeta.oss-cn-beijing.aliyuncs.com/blog/image-20220501161349143.png)
之后加上同步位置和动画的脚本即可,如下(当然没动画的话可以只同步位置)
![image-20220501161614361](https://umeta.oss-cn-beijing.aliyuncs.com/blog/image-20220501161614361.png)
最后将我们的场景、玩家预制体、游戏物体等等放入之前做的网络控制器即可。
![image-20220501160738501](https://umeta.oss-cn-beijing.aliyuncs.com/blog/image-20220501160738501.png)
进阶
同步变量
如果有一个变量是需要同步至所有客户端的,那么这个变量是一个同步变量,同步变量只能通过服务器来修改。下面以同步自己的名字为例讲解。
首先设置该变量为同步变量,加上[SyncVar]
注解即可:
[SyncVar(hook =nameof(NameChanged))]
public string playerNameStr;
其中的hook是指当该变量改变时,本地客户端需要运行的函数
private void NameChanged(string oldStr, string newStr)
{
nameText.text = newStr;
}
比如名字需要在被服务器修改后,将头上的Text设置为修改后的值。
下面是如何让服务器修改这个值,在函数前加上[Command]
注解:
[Command]
private void CmdChangeName(string name)
{
playerNameStr = name;
}
在我们需要改这个值的时候调这个函数即可命令服务器修改这个值,修改之后所有的客户端会自动调用NameChanged,修改玩家头上的Text。
public override void OnStartLocalPlayer()
{
if (!isLocalPlayer)
{
return;
}
CmdChangeName(UserInforManager.username);
}
比如我这里是在玩家初始化的时候将名字修改为了用户名。
服务器的构建与部署
从上面来看,我们并不需要额外写服务器的代码,因为实际上服务器需要所有客户端的资源,否则无法完成沟通。但是我们也不可能手动去控制服务器,因此我们可以通过在网络控制器上加上一个脚本来控制自动开始:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
namespace Networks
{
public class AppControl : MonoBehaviour
{
public bool isServer;
void Start()
{
if(isServer)
{
GetComponent<MyMultiNetworkManager>().StartServer();
}
else
{
GetComponent<MyMultiNetworkManager>().StartClient();
}
}
}
}
在build服务器时,我们可以勾上isServer,在buildSettings里也勾上ServerBuild(这个会把渲染关闭,减小服务器的运行消耗),build后服务器便会自动开启server服务了。
其他
建议直接看Mirror中的示例,里面有几个比较简单的样例,如如何生成一个物体(炮弹之类的),计分的同步等等。