我目前正在尝试制作一个小型绘图游戏,其中两个玩家可以通过网络同时绘制。
我正在使用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);
}
}
}
答案 0 :(得分:2)
我认为你的问题是:
[Command]
表示:从客户端调用方法,但只在服务器上执行。
=>您只在服务器上执行方法CmdSpawn
和CmdTrailUpdate
。
但是:
服务器如何知道您的客户Input.mousePosition
您不希望从服务器camera.main
进行光线投射,而是来自客户端。
<强>解决方案:强>
在客户端上执行本地操作并将[Cmd]
方法上的位置作为参数传递给服务器。
由于您说对象已经有NetworkTransform
,因此您不需要将更新的位置传输到服务器,因为NetworkTransform
已经为您执行了此操作。因此,从客户端调用CmdTrailUpdate
并不是必要的。
但是:在产生对象后,您必须告诉正在呼叫CmdSpawn
的客户,这是他当地currentTrail
的位置,他必须更新。我只需将调用客户端gameObject
传递给CmdSpawn
方法,然后在服务器上调用[ClientRpc]
方法来设置此客户端的currentTrail
对象
(我假设在这里,您发布的脚本与玩家对象相关联。如果不是这样,那么您需要获得玩家&#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;
}