Unity Mirror联网游戏开发(9) 远程行为之Command

1,372 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情

Mirror中可以穿过网络执行行为,称为remote actions,也称为RPC(remote procedure calls,远程过程调用)。Mirror中的RPC包含 Commands 和 ClientRpc。其中Commands是客户端调用服务器上的方法,而ClientRpc是服务器调用客户端上的方法。

Command

Commands从客户端上的player object发送给服务器上的player object。出于安全考虑,默认只有你自己控制的player object(即Local player)可以发送command,因为你不能控制其他玩家的objects。

使用方法

  • 将一个函数变成Command,只要加上[Command]自定义属性,按照惯例,函数名前加前缀"Cmd"。前缀让其他人可以了解这是一个Command函数,而不是一个在客户端执行的普通函数。
  • Command函数在客户端上被调用,但是是在服务器上执行的。
  • Command函数可以带有参数,参数类型必须是Mirror支持的类型,当Comannd函数被调用时,参数也随之从客户端传递到服务器。

例子

public class Player : NetworkBehaviour
{
    public GameObject cubePrefab;
    
    void Update()
    {
        if(!isLocalPlayer) return;
        if(Input.GetKey(KeyCode.J))
            CmdDropCube();
    }
    
    [Command]
    void CmdDropCube()
    {
        if(cubePrefab != null)
        {
            Vector3 pos = transform.position + tranform.forward*3;
            GameObject cube = Instantiate(cubePrefab, pos, transform.rotation);
            NetworkServer.Spawn(cube);
        }
    }
}

这个例子中,玩家在客户端上按下J键,就会调用一个CmdDropCube Command函数。该函数在服务器上执行,会在玩家面前生成一个方块,并且使用 NetworkServer.Spawn(cube)方法在其他客户端上也生成一个方块。该方块的prefab上需要有NetworkIdentity组件。

非Local Player调用Command的情况

一般情况,只有Local player可以调用Command,但也有几种情况,Command可以在其他对象上执行。

  • 当该对象是使用客户端授权生成时。
  • 该对象被授予了客户端授权,即使用 NetworkIdentity.AssignClientAuthority
  • Command函数的Command属性的参数 requireAuthority 被设置为false。此时,可以在Command函数上使用一个可选的参数:NetworkConnectionToClient sender=null,Mirror会将发送该Command的客户端连接填入这个参数。不要在调用时设置这connection参数,会被忽略掉。

注意:以上几种情况,Command函数是在服务器上该对象的实例上执行的,而不是在客户端所关联的服务器上的Player Object上。这个其实是显而易见的,毕竟Command函数本来就包含在该对象的NetworkBehaviour脚本中。 下面看一个非local player使用Command的简单例子:

public class Tree : NetworkBehaviour
{
    [SyncVar]
    public float HP;
    
    [Client]
    void OnMouseUp()
    {
        CmdCutTree();
    }
    
    [Command(requireAuthority=false)]
    public void CmdCutTree(NetworkConnectionToClient sender=null)
    {
        HP--;
        if(HP<=0)
        {
            //Destroy tree
            NetworkServer.Destroy(gameObject);
        }
    }
}

这个例子中的Tree对象,可以在任意客户端上使用鼠标进行砍树操作,CmdCutTree是一个Command函数,由于设置了requireAuthority=false,因此可以被服务器执行,该函数执行时会扣减Tree的HP值,并且由于HP是一个SyncVar,所有玩家都可以看到树的血条在扣血,当HP扣减完后,服务器会删除这棵树,且所有的客户端会同步从客户端上删除这棵树。