Unity——Mirror学习(01)

1.下载

Mirror是一个简单高效的开源的unity多人游戏网络框架,Mirror在Unity商店中是免费的,因此直接加入自己的资源库并在导入即可。

官方API地址:https://mirror-networking.gitbook.io/docs

2.使用

1.创建场景的网络管理器

网络管理器是多人游戏的核心控制组件。网络管理器是多人游戏的核心控制组件。

在起始场景中创建一个空游戏对象,然后添加新创建的网络管理器组件。在起始场景中创建一个空游戏对象,然后添加新创建的网络管理器组件。

 注:如果没有获取到kcp transport组件,手动添加。

2.创建一个玩家

建立一个cube作为玩家。

添加networkIdentity作为在网络同步的唯一标识。

 

只有挂载了networkIdentity,网络中枢才能识别到这个物件,并对之进行同步。接下来将Cube作为一个预制体保存,并在场景中删除,后拖拽预制体到网络中枢的Player Prefab插槽中,以后它的产生就完全依靠网络中枢在连接到主机后自动生成。

注:如果角色预制体托不进player prefab栏,可能是没有挂在network identity组件

添加Network Transform,同步网络中联网游戏对象的位置、旋转和缩放。

 Mirror 目前提供2种Network Transform:

  • Reliable:低带宽,与Rpcs/Cmds/等相同的延迟。

  • Unreliable:高带宽,极低延迟

使用Reliable除非需要超低延迟。

 3.添加玩家初始生成位置

创建几个空物体作为玩家的初始生成位置,添加Network Start PositionNetwork,控制玩家的生成位置要控制玩家的生成位置。

根据Network Manager里面Player Spawn Method(玩家生成方法设置):

1.Random:生成为随机(可能相同的生成位置将被两个或更多玩家使用)

2.Round Robin:循环(使用每个可用位置,直到客户端数超过生成点数)。

4.玩家控制

网络同步需要注意的一些事情:

1.需要用到联网功能的脚本中都要添加using Mirror来使用相应API,并且继承NetworkBehaviour而不是MonoBehaviour。

2.涉及到玩家输入时,首先先要进行isLocalPlayer的判断

为控制游戏对象,添加一个脚本为PlayerControl.cs,继承NetworkBehaviour。

Start函数——>重写OnStartLocalPlayer函数。(OnStartLocalPlayer:仅在client执行,当脚本所在物体为玩家角色时调用,用来设置跟踪相机,角色初始化等)

    public override void OnStartLocalPlayer()
    {
        //摄像机与角色绑定
        Camera.main.transform.SetParent(transform);
        Camera.main.transform.localPosition = Vector3.zero;

        //player初始化
        //player 名称的位置,大小
        name.transform.localPosition = new Vector3(0, -0.3f, 0.6f);
        name.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);

        //随机生成颜色和名字
        ChangedColorAndName();
    }

数据同步:

当服务器的场景中的一个SyncVar的值发生变化时,就同步给其它所有客户端。

    //需要把name和颜色同步给其他玩家,添加同步变量的标记[SyncVar(hook=nameof(FunctionExecOnClient))]
    [SyncVar(hook = nameof(OnPlayerNameChanged))]
    private string playerName;
    [SyncVar(hook = nameof(OnPlayerColorChanged))]
    private Color playerColor;

    //申明OnPlayerNameChanged和OnPlayerColorChanged这两个方法
    //第一个变量(oldstr)是同步变量修改前的值,第二个(newstr)是同步变量修改后的值
    private void OnPlayerNameChanged(string oldstr,string newstr)
    {
        nameText.text = newstr;
    }
    private void OnPlayerColorChanged(Color oldCor,Color newCor)
    {
        nameText.color = newCor;

        playerMaterialClone = new Material(GetComponent<Renderer>().material);
        playerMaterialClone.SetColor("_EmissonColir", newCor);

        GetComponent<Renderer>().material = playerMaterialClone;
    }

玩家名字、颜色的变化,以及远程控制:

    /// <summary>
    /// player 的随机名称和颜色
    /// </summary>
    private void ChangedColorAndName()
    {
        //随机名称和颜色
        var tempName = $"Player{Random.Range(1, 999)}";
        var tempColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f), 1);

        //同步变量进行修改
        CmdSetupPlayer(tempName, tempColor);
    }
    //对于同步变量的修改,使用[Command]标记(针对方法的标记,方法名以Cmd开头)
    //通过这个方法同时对name和颜色进行修改
    [Command]
    private void CmdSetupPlayer(string name,Color color)
    {
        playerName = name;
        playerColor = color;
    }

 移动代码:

    private void Update()
    {
        if (!isLocalPlayer) 
        {
            name.transform.LookAt(Camera.main.transform);
            return; 
        }
        var movex = Input.GetAxis("Horizontal") * Time.deltaTime * 110f;
        var movez = Input.GetAxis("Vertical") * Time.deltaTime * 4f;

        transform.Rotate(0, movex, 0);
        transform.Translate(0, 0, movez);

        if (Input.GetKey(KeyCode.Space))
        {
            ChangedColorAndName();
        }
    }