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
только на сервере.
Но:
насколько сервер знает вашего клиента
Input.mousePosition
?Вы не хотите, чтобы Raycast с сервера
camera.main
, а точнее от клиента.
Решение:
Сделайте обе вещи локально на клиенте и передайте позицию в качестве параметра на
[Cmd]
методы к серверу.Поскольку вы говорите, что объект уже имеет
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;
}