Unity Unet单击时更新转换

时间:2018-01-27 13:23:33

标签: unity3d unity3d-unet unet

我目前正在尝试制作一个小型绘图游戏,其中两个玩家可以通过网络同时绘制。

我正在使用GameObjectTrailRenderer来绘制线条。

现在只有主机播放器的图纸显示在两台机器上。

如果客户端玩家点击并尝试绘制,我可以看到生成了一个新对象但转换没有更新。生成的预制件有一个NetworkIdentity(已选中“本地播放器权限”)和NetworkTransform。以下脚本由两个玩家生成,并且还具有NetworkIdentity(已选中本地播放器权限)。

我认为我实际上在对CmdTrailUpdate做错了以及如何处理它,但我无法弄清楚是什么。

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

public class TrailDrawer : NetworkBehaviour {

    private Plane objPlane;
    private GameObject currentTrail;
    private Vector3 startPos;
    public GameObject trail;

    public void Start()
    {
        objPlane = new Plane(Camera.main.transform.forward * -1, this.transform.position);
    }

    // Update is called once per frame
    void FixedUpdate() {
        if (isLocalPlayer) {
            if (Input.GetMouseButtonDown(0)) {
                CmdSpawn();
            } else if (Input.GetMouseButton(0)) {
                CmdTrailUpdate();
            }
        }
    }

    [Command]
    private void CmdTrailUpdate() {
        Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);
        float rayDistance;
        if (objPlane.Raycast(mRay, out rayDistance)) {
            currentTrail.transform.position = mRay.GetPoint(rayDistance);
        }
    }

    [Command]
    private void CmdSpawn(){
        Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);

        float rayDistance;
        if (objPlane.Raycast(mRay, out rayDistance)) {
            startPos = mRay.GetPoint(rayDistance);
            currentTrail = (GameObject)Instantiate(trail, startPos, Quaternion.identity);
            NetworkServer.Spawn(currentTrail);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

我认为你的问题是:

[Command]表示:从客户端调用方法,但只在服务器上执行。

=>您只在服务器上执行方法CmdSpawnCmdTrailUpdate

但是:

  1. 服务器如何知道您的客户Input.mousePosition

  2. 您不希望从服务器camera.main进行光线投射,而是来自客户端。

  3. <强>解决方案:

    1. 在客户端上执行本地操作并将[Cmd]方法上的位置作为参数传递给服务器。

    2. 由于您说对象已经有NetworkTransform,因此您不需要将更新的位置传输到服务器,因为NetworkTransform已经为您执行了此操作。因此,从客户端调用CmdTrailUpdate并不是必要的。

      但是:在产生对象后,您必须告诉正在呼叫CmdSpawn的客户,这是他当地currentTrail的位置,他必须更新。我只需将调用客户端gameObject传递给CmdSpawn方法,然后在服务器上调用[ClientRpc]方法来设置此客户端的currentTrail对象

    3. (我假设在这里,您发布的脚本与玩家对象相关联。如果不是这样,那么您需要获得玩家&#39而不是this.gameObject行。 ; s gameObject以另一种方式。)

      void FixedUpdate() {
          if (!isLocalPlayer) return;
      
          if (Input.GetMouseButtonDown(0)) {
              // Do the raycast and calculation on the client
              Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);
      
              float rayDistance;
              if (objPlane.Raycast(mRay, out rayDistance)) {
                  startPos = mRay.GetPoint(rayDistance);
      
                  // pass the calling Players gameObject and the
                  // position as parameter to the server
                  CmdSpawn(this.gameObject, startPos);
              }
          } else if (Input.GetMouseButton(0)) {
              // Do the raycast and calculation on the client
              Ray mRay = Camera.main.ScreenPointToRay(Input.mousePosition);
      
              float rayDistance;
              if (objPlane.Raycast(mRay, out rayDistance)) {
                  // only update your local object on the client
                  // since they have NetworkTransform attached
                  // it will be updated on the server (and other clients) anyway
                  currentTrail.transform.position = mRay.GetPoint(rayDistance);
              }
          }
      }
      
      [Command]
      private void CmdSpawn(GameObject callingClient, Vector3 spawnPosition){
          // Note that this only sets currentTrail on the server
          currentTrail = (GameObject)Instantiate(trail, spawnPosition, Quaternion.identity);
          NetworkServer.Spawn(currentTrail);
      
          // set currentTrail in the calling Client
          RpcSetCurrentTrail(callingClient, currentTrail);
      }
      
      // ClientRpc is somehow the opposite of Command
      // It is invoked from the server but only executed on ALL clients
      // so we have to make sure that it is only executed on the client
      // who originally called the CmdSpawn method
      [ClientRpc]
      private void RpcSetCurrentTrail(GameObject client, GameObject trail){
          // do nothing if this client is not the one who called the spawn method
          if(this.gameObject != client) return;
      
          // also do nothing if the calling client himself is the server
          // -> he is the host
          if(isServer) return;
      
          // set currentTrail on the client
          currentTrail = trail;
      }