Unity工程案例—多客户端控制同一个物体_unity 场景多端同步-程序员宅基地

技术标签: Unity  

一、介绍

    本篇要讲的内容是在Unity中怎么实现多个客户端用户能操控同一个物体,如一个Cube,这个Cube在任何客户端有,相当于一个游戏的NPC,客户端A可以控制Cube的移动、旋转,Cube在A的位置或旋转的改变会同步到其他的客户端B、C等。同样,在其他客户端B、C控制Cube的位置和旋转也可以同步到A。如图所示:A点击LANHost(H)既做为服务器也作为客户端,B和C为客户端,鼠标点击哪个客户端就表示正在控制当前客户端的


Cube。通过不同客户端控制Cube,Cube的旋转和位移都会被同步到其他客户端。

二、实现(填坑)

  1、思路(把坑想的比较理想):服务器生成Cube,这样保证每个客户端都能看到,然后在每个客户端直接控制Cube。

2、实现(直接就跳进去坑):

1>创建一个Cube,取名为”CubeNPC“,然后给这个Cube添加Network Identity和Network Transform两个组件,如图所示:然后,将这个Cube拖到Projects文件里,作为预设体,并删除场景中的这个Cube。


2>:创建一个空的物体,取名为“NetWorkManager",然后,添加NetworkManager和NetworkManagerHud两个组件,Network有了这两个组件后将作为一个管理器,统筹管理所有的网络状态和物体。然后将上面的CubeNPC拖入到Registered Spawnable Prefab里面,如图所示:这样次CubeNPC就可以注册成为一个网络物


体了,接下来是要在服务器端先生成。

3>:创建一个空物体,取名为”PlayerSpawner“,添加Network Identity组件,并勾选Server Only。这个物体就是用来专门生成类似于NPC的物体,因此只能在服务器端执行,如果是客户端,这个物体会被失活。


4>:创建生成CubeNPC的脚本,取名为PlayerSpawner,代码如下:在OnStartServer方法里生成CubeNPC

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class PlayerSpawner : NetworkBehaviour
{
    public static PlayerSpawner M_Instance
    {
        get
        {
            if(null==_instance)
            {
                _instance = GameObject.FindObjectOfType<PlayerSpawner>();
            }
            return _instance;
        }
    }
    private static PlayerSpawner _instance;
    public GameObject prefabCubeNPC;

    [HideInInspector]
    public GameObject ObjCubeNPC;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
         
        
    }
    public override void OnStartServer()
    {
        ObjCubeNPC = Instantiate(prefabCubeNPC);
        ObjCubeNPC.transform.position = Vector3.zero;
        ObjCubeNPC.transform.eulerAngles = Vector3.zero;
        NetworkServer.Spawn(ObjCubeNPC);

    }
}

5>:然后添加CubeNPC的控制脚本,简单点,直接控制位置和旋转,代码如下:但是,发现好像这个控制只能在服务器端执行的时候会同步到其他客户端,而客户端执行的时候只能在本机上改变,服务器端和其他客户端并没

    private void Move()
    {
        rotY = Input.GetAxis("Horizontal") * Time.deltaTime * 50;
        posZ = Input.GetAxis("Vertical") * Time.deltaTime * 50;
        transform.Rotate(0, rotY, 0);
        transform.Translate(0, 0, posZ);
    }

有同步数据,如图所示:A仅仅作为服务器,B作为客户端,单独控制B的Cube,并不会影响A的Cube,也即没有同步数据到服务器,但是控制A中的Cube,B的状态立马恢复到A中Cube的数据状态,接下来保持状态同步。


这是因为,CubeNCP是服务器生成的物体,在其他客户端并没有权限通过控制来同步数据,另外服务器生成的这个Cube物体,其他客户端并没有权限发送Command命令,会提示如图所示的警告信息:


没有权限,所以在更改这个网络物体相应的位置和旋转后并不能同步到服务器和其他客户端上,只是本机上能看到改变,并且不能通过发送Command命令来同步信息。既然服务器端生成的这个CubeNPC,其他客户端没有权限,那要怎样才能获取这个权限呢。后来发现系统创建的Player是自带这个权限的,因此可以通过在Player的控制脚本里面发送这个Command脚本命令。

3、新思路(新的理想主义坑):通过每个客户端自动生成的Player,来发送Command命令,达到控制CubeNPC的目的。

4、新的实现

1>:创建一个空物体,命名为Player,如图所示,和CubeNPC一样,添加Network Identity和NetworkTransform组件,并将Player托到Project中作为预设体,删除场景总的Player。Player的代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class PlayerController : NetworkBehaviour {


    private float rotY;
    private float posZ;
    [SerializeField]
    private GameObject prefabSubObj;
    //[SerializeField]
    private GameObject subObj;
    // Use this for initialization
    void Start () {
       
	}

    // Update is called once per frame
    void Update()
    {
        if (!isLocalPlayer)
        {
            return;
        }
        //if (Input.GetKeyDown(KeyCode.R))
        //{
        //    CmdSpawaner();
        //}
        rotY = Input.GetAxis("Horizontal") * Time.deltaTime * 50;
        posZ = Input.GetAxis("Vertical") * Time.deltaTime * 50;
        if (Input.anyKey)
        {
            CmdControllerNPC2(rotY, posZ);
        }
    }

    //[Command]
    //private void CmdSpawaner()
    //{
    //    subObj = Instantiate(prefabSubObj);
    //    subObj.transform.position = transform.position + new Vector3(0, 1.0f, 0);
    //    subObj.transform.eulerAngles = Vector3.zero;
    //    NetworkServer.SpawnWithClientAuthority(subObj, connectionToClient);
    //}

    [Command]
    private void CmdControllerNPC2(float ry,float pz)
    {
        if (null != PlayerSpawner.M_Instance.ObjCubeNPC)
        {
            PlayerSpawner.M_Instance.ObjCubeNPC.transform.Rotate(0, ry, 0);
            PlayerSpawner.M_Instance.ObjCubeNPC.transform.Translate(0, 0, pz);
        }
    }
}

修改PlayerSpawner的脚本为:,虽然这个脚本的物体只能在服务器上激活,但是上面Player的代码里的Command命令下的方法也是会在服务器端执行,因此不必担心非空的问题。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class PlayerSpawner : NetworkBehaviour
{
    public static PlayerSpawner M_Instance
    {
        get
        {
            if(null==_instance)
            {
                _instance = GameObject.FindObjectOfType<PlayerSpawner>();
            }
            return _instance;
        }
    }
    private static PlayerSpawner _instance;
    public GameObject prefabCubeNPC;

    [HideInInspector]
    public GameObject ObjCubeNPC;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
    
    public override void OnStartServer()
    {
        ObjCubeNPC = Instantiate(prefabCubeNPC);
        ObjCubeNPC.transform.position = Vector3.zero;
        ObjCubeNPC.transform.eulerAngles = Vector3.zero;
        NetworkServer.Spawn(ObjCubeNPC);
      
    }
}

2>:在NetworkManager的SpawnInfo中添加Player预设体,并勾选Auto Create Player,如图所示:


在这里我删除了原来的NeworkManager组件,改用一个继承NetworkManager的Global脚本,因为NetworkManager是个单例,整个场景中就只能有一个。采用Global脚本,是想在后续获取一些脚本的控制。至此,解决了多个客户端对同一个物体的操作的问题。

三、总结

1、单纯服务器创建的CubeNPC只能在服务器端控制并同步数据到其他客户端,其他任何客户端都只能在本机上操作,不能同步数据到服务器端和其他客户端。并且客户端也不能在CubeNPC的脚本里使用Command命名来达到数据同步到服务器的控制,因为没有权限。

2、创建的Player对象有权限,在它的控制脚本里可以使用Command命令来操作CubeNPC的位置和旋转。

3、CubeNPC是否能单独授权给客户端呢?

答:可以的,采用NetworkServer.SpawnWithClientAuthority(subObj, connectionToClient);和

CubeNPC.GetComponent<NetworkIdentity>().AssignClientAuthority(connectionToClient);两个方法。前者是在创建了Player以后再在Player里面创建一个物体,并且将这个物体付给客户端一个权限,并且只能该客户端操作,其他的客户端还是不能操作。后者,还没有研究透怎么使用






版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangxiao13627093203/article/details/81026124

智能推荐

1100多份全球各地的数据汇总,这是我目前看到的最全的数据资源_数据资源清单-程序员宅基地

文章浏览阅读380次。前两天一朋友给我发了一个excel文件,说是别人整理的数据资源。打开以后一看,内容太全了,是我目前看到的最全的一份数据资源列表。独乐乐不如众乐乐,分享出来让大家都受益一下吧。先给大家大致看看内容。整个Excel表按照按别,创建了10多个sheet页,每个页面一个数据类别,分别包括Global、Regional、 Country 、Thematic、 Event Disaster、 Type Disaster List、 Conflict 、Imagery、 Physical、 Conserv_数据资源清单

calloc和malloc区别、分析_malloc与calloc相同-程序员宅基地

文章浏览阅读780次。函数malloc()和calloc()都可以用来动态分配内存空间,但两者稍有区别 malloc()函数有一个参数,即要分配的内存空间的大小:void *malloc(size_t size); calloc()函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小。void *calloc(_malloc与calloc相同

每天工作计划_算法工作计划-程序员宅基地

文章浏览阅读251次。如果坚持每天刷题3道,就离1200 codeforce不远了这周主要看:数据结构与算法 c++描述这本书_算法工作计划

Python 中的时间处理包datetime和arrow_python datetime的时间戳和arrow的时间戳不一样-程序员宅基地

文章浏览阅读1.8w次,点赞2次,收藏5次。Python 中的时间处理包datetime和arrow在获取贝壳分的时候用到了时间处理函数,想要获取上个月时间包括年、月、日等# 方法一:today = datetime.date.today() # 1. 获取「今天」first = today.replace(day=1) # 2. 获取当前月的第一天last_month = first - datetime.ti..._python datetime的时间戳和arrow的时间戳不一样

求字符串可匹配的最大长度_最长连续字符匹配-程序员宅基地

文章浏览阅读4.1k次。如:text=“abcdlijkfgd”,query=“abcdefg”,最大匹配为“abcd”_最长连续字符匹配

机器学习 Machine Learning- 吴恩达Andrew Ng 第11~15课总结-程序员宅基地

文章浏览阅读200次。YouTube课程地址https://www.youtube.com/playlist?list=PLOXON7BTL9IW7Ggbc09jLqGmzkwPI4-3V截止2021-5-3, 有112 个视频1. 第11课 Gradient descent intuition, Linear regression with one variableGradient descent intuition 阶梯下降算法介绍:a 表示 learning rate, 学习下降的速度右边的函数 deriv

随便推点

音频播放模块在短视频开发中的方案解决及所需开发环境说明_小视频模块开发方案-程序员宅基地

文章浏览阅读569次。在短视频开发中,音频媒体播放模块是仅次于视频媒体播放的另一大模块,这段源码就是用于解决音频媒体播放问题的方案。音频媒体播放前,主播需用手机等直播设备对音频媒体进行采集,向文件中添加流式信息,通过适当的压缩算法进行压缩,推流至流媒体服务器储存,直到用户点击音频播放的瞬间完成拉流、解码才能进行播放。public void startPlay(ChatMessageBean bean, Stri..._小视频模块开发方案

虚幻UE4中Matinee基础:骨架网格教程_ue4骨骼网格体-程序员宅基地

文章浏览阅读9.1k次,点赞4次,收藏15次。本教程的目标是教你在如何在Matinee中使用骨架网格的一些基础知识。 您将学习如何连接和操纵骨架网格并使骨架网格物体播放动画。_ue4骨骼网格体

linux密码破解与开机加密_lunnx password-程序员宅基地

文章浏览阅读901次。破解登录密码 GRUB:在引导装载程序菜单上,键入[e] 来进入编辑模式。你会面对一个引导项目列表。查找其中类似以下输出的句行: kernel /vmlinuz-2.4.18-0.4 ro root=/dev/hda2按箭头键直到这一行被突出显示,然后按 [e]。你现在可在文本结尾处空一格再添加 single 来告诉 GRUB 引导单用户 Linux 模式。按 [Enter] _lunnx password

[转]Socket send函数和recv函数详解_sendrecvgprs-程序员宅基地

文章浏览阅读760次。转载地址:http://hi.baidu.com/webeta/blog/item/4c04d109fdf21881d1581be8.html 引文:最近在wince5.0的设备上开发网络通信,因socket的send和recv的时间太长,而客户端不需要服务端的响应数据因此突发奇想,是否可以不用调用recv函数而直接去做其他的事情.刚开始使用的时候还成,速度倒是确实有提升.可最近用到一个操作,send函数后立刻就把GPRS网络断开了,服务器端一直无法收到客户端发送的数据,百思不得其解,google到一篇文章_sendrecvgprs

第七章 数组实验-程序员宅基地

文章浏览阅读973次。C语言设计实验报告试验项目:1、一维数组的运用2、二维数组的应用3、字符数组的应用姓名:李小玲  实验地点:514教室  实验时间:2019.5.29一、实验目的与要求7.3.1一维数组的运用实验1:写一个函数,对用随机函数产生的10个整数按从小到大的顺序排序(升序,用冒泡排序实现)1.定义一个一维数组,其大小为10,即它能存放10个数据。2..._c语言数组的应用实验

MyBatis-Configuration-程序员宅基地

文章浏览阅读58次。一、引用properties 配置文件db.propertiesdriver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://192.168.8.136:3306/mybatisusername=rootpassword=rootmybatis-config.xml<!-- 外部 properties 配置文件 -..._mybatis整合configuration