Reputation: 79
I am currently trying to make a little drawing game where two players can draw at the same time over the network.
I am using a GameObject
with a TrailRenderer
to draw the lines.
Right now only the drawings of the host player are shown on both machines.
If a client player clicks and tries to draw I can see that a new object is spawned but the transform doesn't get updated. The spawned prefab has a NetworkIdentity
(with Local Player Authority checked) and NetworkTransform
attached to it. The following script is spawned by both players and also has a NetworkIdentity
(with Local Player Authority checked).
I think I am actually doing something wrong with the CmdTrailUpdate
and how to handle it but I can't really figure out what.
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);
}
}
}
Upvotes: 0
Views: 211
Reputation: 90629
I think your problem is:
[Command]
means: Invoke the method from a client but only execute it on the server.
=> You are executing both methods CmdSpawn
and CmdTrailUpdate
only on the server.
But:
how shoud the server know your client's Input.mousePosition
?
You don't want to raycast from the server's camera.main
, but rather from the client's.
Solution:
Do both things local on the client and pass the position as parameter on the [Cmd]
methods to the server.
Since you say the object already has a NetworkTransform
, you wouldn't need to transmit the updated position to the server because NetworkTransform
already does it for you. So calling CmdTrailUpdate
from the client would not be neccesarry.
But: After spawning the object you have to tell the client who is calling CmdSpawn
, which is his local currentTrail
which's position he has to update. I would do this by simply passing the calling clients gameObject
also to the CmdSpawn
method and on the server call a [ClientRpc]
method to set this client's currentTrail
object.
(I'm assuming here, that the script you posted is attached diectly to the Player objects. If that is not the case, instead of the lines with this.gameObject
you have to get the player's gameObject
in a nother way.)
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;
}
Upvotes: 2