0

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

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

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

如果客户端玩家单击并尝试绘制,我可以看到生成了一个新对象,但变换没有更新。生成的预制件有一个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);
        }
    }
}
4

1 回答 1

2

我认为你的问题是:

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

=> 您正在执行这两种方法CmdSpawn,并且CmdTrailUpdate仅在服务器上执行。

但:

  1. 服务器应该如何知道你的客户Input.mousePosition

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

解决方案:

  1. 在客户端本地做这两件事,并将位置作为[Cmd]方法上的参数传递给服务器。

  2. 由于您说该对象已经具有NetworkTransform,因此您不需要将更新的位置传输到服务器,因为NetworkTransform已经为您完成了。CmdTrailUpdate因此,不必从客户那里致电。

但是:在生成对象后,您必须告诉正在调用的客户端CmdSpawn,这是他的本地currentTrail位置,他必须更新。我将通过简单地将调用客户端gameObject也传递给该CmdSpawn方法并在服务器上调用一个[ClientRpc]方法来设置此客户端的currentTrail对象来做到这一点。

(我在这里假设您发布的脚本直接附加到 Player 对象。如果不是这种情况,this.gameObject那么您必须以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;
}
于 2018-01-27T15:57:38.533 回答