UnityMirror学习笔记(6):权限与运动控制

Mirror是一个简单高效的开源的Unity多人游戏网络框架。
官方文档链接:
https://mirror-networking.gitbook.io/docs

在之间的几章博客里,已经基本介绍了UnityMirror的各种有用的概念。
但是并没有详细介绍如何在Mirror中,随心所欲地控制任何一个对象。
如果有读者仿照我之前的实验代码去自己实验,会发现很多问题,
比如rigidbody.velocitytransform.position无法在本地直接设定等。

当然可以通过[Command]等通知服务器进行控制,间接控制本地,
不过个人觉得不太好,有可能导致严重的延迟,客户端还是应该优先强调本地的控制。

本节将权限和控制一起介绍,旨在能实现各个客户端随心所欲控制自己想要控制的对象,而保持良好的同步~

权限

权限是Mirror中一个很重要的概念,它用来描述一个客户端对某个对象的所有权。

运动控制

在Mirror中,由于需要在服务器上获取速度计算物理效果,使用本地的Rigidbody组件是无法完成这个效果的,而且也无法实现同步控制。
因为Mirror不会自动去序列化RigidBody的信息进行同步。

因此此时只会出现两种状况:
服务器可以实现控制,并通过服务器->客户端的同步实现同步运动,这是因为对象默认自带了NetworkTransform组件。
客户端可以实现控制,但由于没有从客户端->服务器的同步,服务器看不到对象的运动。

我们需要挂载NetworkRigidbody组件,
来实现客户端对有权限的物体的运动控制向服务器的同步。

挂载脚本后,直接控制自己的RigidBody即可
这个脚本暂时属于Mirror的Experimental命名空间中,如果需要在自己的脚本中访问控制,需要using Mirror.Experimental;指定
可能遇到出乎意料的问题,大可以往Mirror的github里扔Issue
https://github.com/vis2k/Mirror

使用

在玩家预制体上挂载NetworkRigidbody组件,
并且勾选Client Authority,这样才能从客户端向服务器同步
[外链图片转存中...(img-Sanv3gdO-1646296056197)]

代码案例如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using Cinemachine;

public class PlayerController : NetworkBehaviour
{
    Rigidbody rb;    
    CinemachineVirtualCamera cv;

    MaterialPropertyBlock prop;

    public GameObject prefabWeapon;
    [Command]
    void spawnWeapon(){
        GameObject tmp = GameObject.Instantiate(prefabWeapon);
        NetworkServer.Spawn(tmp);
        tmp.transform.position = new Vector3(transform.position.x, transform.position.y+2, transform.position.z);
    }


    private void Start() {
        rb = GetComponent<Rigidbody>();
        if(isLocalPlayer){
            cv = GameObject.FindGameObjectWithTag("VCAM").GetComponent<CinemachineVirtualCamera>();
            cv.LookAt = this.transform;
            prop =  new MaterialPropertyBlock();
            GetComponent<Renderer>().GetPropertyBlock(prop);
            prop.SetColor("_Color", (Color.HSVToRGB(Random.Range(0,360), 0.8f, 0.8f)));
            GetComponent<Renderer>().SetPropertyBlock(prop);
        }
    }

    float moveDirX;
    float moveDirY;
    private void Update() {
        if(isLocalPlayer){
            if(Input.GetKeyDown(KeyCode.Space)){
                spawnWeapon();
            }
            moveDirX = Input.GetAxisRaw("Horizontal");
            moveDirY = Input.GetAxisRaw("Vertical");
            rb.velocity = new Vector3(3 * moveDirX, 3*moveDirY, 0);
        }
    } 
}

运行一个纯服务器和一个客户端,在客户端上使用键盘控制实体,可以实现同步:
[外链图片转存中...(img-YbvT8Fhe-1646296056199)]

多端同步也是一致的:
[外链图片转存中...(img-UJ9z3tz5-1646296056199)]

权限给予

角色控制脚本里已经写了按下空格键生成武器的代码。
我们先不让武器跟随,而是将相同的这个角色控制脚本挂载到武器预制体上,同时也将NetworkRigidbody挂载上,且勾选Client Authority
[外链图片转存中...(img-3FMFQaXr-1646296056200)]

虽然期望武器同自己的角色能一起运动,但事实是无法跟随:
[外链图片转存中...(img-lsmQkO2Q-1646296056200)]

这里有两个问题需要修改:

isLocalPlayer 与 hasAuthority

isLocalPlayer为true的对象,在客户端全体对象里,只有唯一一个。(由连接到服务器生成的本地玩家)

因此想要本地控制的其它对象需要必须使用hasAuthority,而不能使用isLocalPlayer
我们这里直接将isLocalPlayer替换成hasAuthority

//在 第36行 Update()中 
if(isLocalPlayer)

=>

if(hasAuthority)
服务器给予客户端对象权限

此时运行依然无法两个都控制,
原因是isLocalPlayer为true的对象默认hasAuthority为true

但是其它在服务器生成并同步到客户端的对象默认在所有客户端hasAuthority为false包括主机的客户端

因此需要在服务器上给予某个客户端对某个对象的权限:
使用NetworkServer.Spawn方法同时携带到客户端的连接通道,是最简单的设置方式。

//在 第18行 spawnWeapon()中
NetworkServer.Spawn(tmp);
=>
NetworkServer.Spawn(tmp,connectionToClient);

此时就可以完成两个都控制了。
[外链图片转存中...(img-kbbrz7w2-1646296056201)]

权限中途分配与取消

有的时候某个对象不是一直属于一个客户端的。

可以通过identity.AssignClientAuthority(conn);进行对象生成完毕后,后续权限的分配。

可以通过identity.RemoveClientAuthority();让这个对象不属于任何一个客户端。

注意localPlayer不可以被取消权限,但是可以通过NetworkServer.ReplacePlayerForConnection(conn, newGameObj);被替换

同一对象多客户端权限是不被允许的,即使中途分配,也只认第一个为主人,先Remove再Assign
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值