Unity Unet Обновление трансформации при нажатии

В настоящее время я пытаюсь сделать небольшую игру для рисования, в которой два игрока могут рисовать одновременно по сети.

Я использую GameObject с TrailRenderer рисовать линии.

Прямо сейчас только рисунки хост-плеера показаны на обеих машинах.

Если клиентский игрок щелкает и пытается нарисовать, я вижу, что новый объект появляется, но преобразование не обновляется. Породивший сборный дом имеет 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 ответ

Я думаю, что ваша проблема:

[Command] означает: вызывать метод из клиента, но выполнять только на сервере.

=> Вы выполняете оба метода CmdSpawn а также CmdTrailUpdate только на сервере.

Но:

  1. насколько сервер знает вашего клиента Input.mousePosition?

  2. Вы не хотите, чтобы Raycast с сервера 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;
}
Другие вопросы по тегам