Unity工程案例—多客户端控制同一个物体_unity pun2操作相同物体_凯尔八阿哥的博客-程序员秘密

技术标签: 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

智能推荐

PyQt5的标准输入对话框QInputDialog_pyqt5 qinputmethod_strive_one的博客-程序员秘密

QInputDialogQInputDialog提供了一个简单的便利对话框,可以从用户获取单个值。输入值可以是列表中的字符串,数字或项目。QInputDialog包含的五种方法:getDouble(QWidget, str, str, value: float = 0, min: float = -2147483647, max: float = 2147483647, decimals: int = 1, flags: Union[Qt.WindowFlags,Qt.WindowType]=Q

java--二进制字符串匹配的问题_粉末无颜的博客-程序员秘密

描述Given two strings A and B, whose alphabet consist only ‘0’ and ‘1’. Your task is only to tell how many times does A appear as a substring of B? For example, the text string B is ‘1001110110’ while

Codeforces上如何查看别人的代码 题解_codeforces怎么看别人代码_mrcrack的博客-程序员秘密

Codeforces上如何查看别人的代码 题解摘自https://blog.csdn.net/form0/article/details/53944191第一步:点击题目右边的人数第二步:点击最左边的数字即可查看提醒,比赛第二天,数字链接点进去,是看不到代码的,稍安务躁。2019-12-15...

python telnetlib open 超时时间_如何在telnet(telnetlib)时间之后继续使用Python代码..._weixin_39637711的博客-程序员秘密

我正在使用Python进行使用telnetlib的自动telnet程序。问题是:当我尝试telnet的设备没有响应时,意味着超时;程序会给我超时消息,并且不会继续执行下一个命令。我的代码:import telnetlibHOST = ("x.x.x.x")USER = ("xxxxx")PWD = ("yyyyy")ENABLE = ("zzzzz")TNT = telnetlib.Telnet(...

R语言快速入门_R语言中的一些重要的数据结构_x[1:r]_scong123的博客-程序员秘密

3、R语言中的一些重要的数据结构   向量  # 字符串     > x     > mode(x)   #输出结果为:[1] "numeric"     > y     > mode(y)  #输出结果为  [1] "character"   #字符串连接或者拆开函数     > paste(“”,””,...)   #将字符串连接起来 但是隔了一个空格 

随便推点

嵌入式Linux应用程序开发详解 _jason365的博客-程序员秘密

第二章 Linux基础命令这一章没什么好说的,记录几个自己以前不知道的。1.常见环境变量:HOME 根目录HISTSIZE 保存历史命令记录的条数LOGNAME 当前用户的登录名HOSTNAME 主机名2.设置环境变量的几种方法 echo, export, env(显示所有环境变量),set(显示所有本地定义的Shell变量),(unset清除所有环境变量)3. i

SCTP协议及偶联_sctp偶联_逍遥子墨的博客-程序员秘密

1、基本概念SCTP协议(Stream Control Transmission Protocol,流控制传输协议)是一种传输层协议,它基于IP协议,主要用于在无连接的IP网络上为M2UA、M3UA、IUA、H.248、BICC等信令提供高效与可靠的信令传输服务。IP网络中的一般消息交换通常是使用UDP或TCP协议来完成,但这两者都不能完全满足在电信网中信令承载的要求:UDP协议不能保证消

年后面试,差点就痛失了字节跳动Android岗的Offer,原因竟是因为性能调优!_安卓hook屏幕适配_紫苏不是菜的博客-程序员秘密

前言:在找工作的过程中,对于Android性能调优技术知识的掌握已经成为必须的技能。突然发现,字节跳动的面试常常就会被问到Android性能调优相关知识,而这次我就差点挂在了字节的三面了,原因就是因为性能调优,有幸的是,在之前曾目睹过腾讯大佬整理的,Android360°全方面性能调优的PDF文档,才让我顺利拿到字节跳动Android 岗offer。我们先来看看大佬对Android360°全方面性能调优的总结图:在经过近十年的发展,Android技术日新月异,如今Android 10.0 已经发布,

201771010101 白玛次仁 《2018面向对象程序设计(Java)》第九周学习总结_weixin_34161083的博客-程序员秘密

实验九 异常、断言与日志实验时间 2018-10-251.知识总结:异常:在程序的执行过程中所发生的异常事件,它中断指令正常执行。程序中出现的常见的错误和问题有:用户输入错误设备错误物理限制代码错误Java把程序运行时可能遇到的错误分为两类:1.非致命异常:通过某种修正后程序还能继续执行。这类错误叫异常。2,致命异常:程序遇到了非常重要的不正常状态不能简...

后端实践:Nginx日志配置(超详细)_Java基基的博客-程序员秘密

点击上方“Java基基”,选择“设为星标”做积极的人,而不是积极废人!源码精品专栏原创 | Java 2019 超神之路,很肝~中文详细注释的开源项目RPC 框架 Dubbo 源码解析...

几个面试问题_iteye_20271的博客-程序员秘密

去霍尼韦尔面试,虽然被鄙视了,但是还是要记录一下面试的问题,然后在经验上填上一笔,嘟嘟~经历:首先介绍一下自己学习java的经历.项目:然后看看简历,看到简历中有相关的项目经验,然后让我介绍了一个自己比较熟悉的项目,包括实现了哪些功能,用了什么工具,自己在项目中的角色和任务.基础问题:之后问,java基础怎么样,然后问了一些java基础的内容.把问到的问题整理一下:1: 简单的举一...

推荐文章

热门文章

相关标签