Sync ParticleSystem across Clients and server, Unity3D - c#

I am trying to switch a single player game into multiplayer using unity 5.6.4p2 and c#.
I have two particle systems:
"enginePS" set to play on-wake which appears on all sides (cliens + server).
"engineSpeedPS" which set to play when player moving forward.
The second particle system does not appear only for localplayer the one moving forward, so others does not see the particle system.
I am new to UNet so I would really appreciate your help. please check my code below:
using UnityEngine;
using UnityEngine.Networking;
public class MP_PlayerController : NetworkBehaviour
{
public ParticleSystem enginePS1, enginePS2, engineSpeedPS1, engineSpeedPS2,
engineSpeedPS3;
private float verticalCurrentValue;
private float movingX, movingZ;
private bool zAxis;
public bool isMovingForward = false;
public bool isMovingBackward;
public float currentPossition;
public GameObject player;
void Start()
{
engineSpeedPS1.Stop();
engineSpeedPS2.Stop();
engineSpeedPS3.Stop();
verticalCurrentValue = movingZ;
currentPossition = transform.position.z;
}
void Update()
{
if (!isLocalPlayer)
{
return;
}
movingX = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
movingZ = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, movingX, 0);
transform.Translate(0, 0, movingZ);
ChangeEngineParticle();
}
void ChangeEngineParticle()
{
if(!isLocalPlayer)
{
return;
}
if (Input.GetKey("up"))
{
if (isMovingForward == false)
isMovingForward = true;
}
else
{
if (isMovingForward == true)
isMovingForward = false;
}
if (isMovingForward)
{
if (!engineSpeedPS1.isPlaying)
{
engineSpeedPS1.Play();
engineSpeedPS2.Play();
engineSpeedPS3.Play();
}
}
else if (isMovingForward == false)
{
if (engineSpeedPS1.isPlaying)
{
engineSpeedPS1.Stop();
engineSpeedPS2.Stop();
engineSpeedPS3.Stop();
}
}
}
I tried using the [Command] attribute before CmdChangeEngineParticle(), but that made the engineSpeedPS to work at the server end only without being detected at the client end.
Any ideas??

OK so your second engineSpeedPS can be ignored in the networking code - just play that locally on the client using isClient or similar. It doesn't need to go over the network.
I'll talk just about setting the other ParticleEffect, which you want to play everywhere. It is on a Client object, meaning that object is controlled by the client. The client should tell the server that it's time to play the particles, and the server then tells all other connected clients.
The particles probably shouldn't play on awake, as everyone will awake at different times.
So you should have your own code that decides it's time to play the particles. When it does it tells the server with a Command. Note, this should be on the Player object - if not you'll need to Assign Client Authority.
[Command]
public void CmdStartParticles()
{
}
So the client in charge calls CmdStartParticles(). The [Command] tag means that it doesn't get executed locally, but on the server instead.
So what do we want the server to do? It should tell all Clients to play the particles, and also play them itself.
[ClientRpc]
public void RpcStartParticles()
{
DoStartParticles();
}
public void DoStartParticles()
{
particles.Play();
}
The first function can only be called by a server, and it acts on all the connected clients.
The second function is just a handy way to actually do the action
In the CmddStartParticles function, you would just call RpcStartParticles() and also DoStartParticles() (because you want the server to also play them, and RpcStartParticles only affects the clients ).

Rip off the Tanks Demo, which I believe has moving things with engines which play Particle Effects. It might be a bitt outdated, but should help still.

Related

UNET- non-player object glitches back and forth after moving from previous spot to current

I am using Unet in Unity and I am trying to basically pick up an object and move it around the scene and show it to everyone on the server. I can successfully spawn the object with the host and both the client and host can see the object.
However, as the client I can spawn the object but, it does not show up for the host. As far as moving the object the host is able to move the object and the client sees that the host is moving the object. I do this using Assign and Remove Authority method. However, when the client tries to move the host's object it does not appear on the server either. But when the host tries to move the object again after the client has "moved" it the object basically jumps repeatedly back and forth between where the host is moving it too and where the client placed it last.
I really hoped that made sense and someone can help me out please. I have listed some code from the player controller script.
[Command]
public void CmdSpawnCapsule()
{
RpcSpawnCapsule();
}
[ClientRpc]
public void RpcSpawnCapsule()
{
if (isLocalPlayer)
{
//Debug.Log("You are in the cmd");
Vector3 capDir = transform.forward;
Vector3 capPos = transform.position + capDir * 1.5f;
GameObject capsuleToSpawn = (GameObject)Instantiate(capsule, sharedWorldAnchorTransform.InverseTransformPoint(capPos), Quaternion.Euler(capDir));
//capsuleToSpawn.GetComponentInChildren<Rigidbody>().velocity = capDir;
NetworkServer.SpawnWithClientAuthority(capsuleToSpawn, connectionToClient);
//Debug.Log("Exiting cmd");
}
}
public void OnInputClicked(InputClickedEventData eventData)
{
if (isLocalPlayer)
{
if (Physics.Raycast(transform.position, direction: transform.forward, hitInfo: out hit, maxDistance: range))
{
objectID = GameObject.Find(hit.transform.name);
CmdAssignAuthority(objectID);
}
}
}
public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
{
if (isLocalPlayer)
{
String keyword = eventData.RecognizedText;
//Debug.Log(keyword);
switch (keyword)
{
case "Spawn":
CmdSpawnCapsule();
break;
}
}
}
[Command]
void CmdAssignAuthority(GameObject obj)
{
if (control == 0)
{
objNetId = obj.GetComponent<NetworkIdentity>();
objNetId.AssignClientAuthority(connectionToClient);
control = 1;
}
else
{
objNetId.RemoveClientAuthority(connectionToClient);
control = 0;
}
}
Solved: The problem was in my GameObject.Find function where I was looking for an object name. I gave a unique name to each object and it solved the problem I was having.

Send player position to another player to move him in multi player game using Unity Photon

I follow the steps of PUN basic tutorial.
For now I reach to a part of what I want Send my position in the current time to another player with me in the room to move him. I can print my position each time I update it , what I need is to know how I can send position to another player to move him.
Let's say I have a desktop player and when I move him this translation moving the player on mobile.
And how I stop instantiate object on mobile, I just want to deal with the instantiated object on desktop.
I am using unity and Photon Network SDK.
Here is the code I used
using UnityEngine;
using System.Collections;
public class NetworkCharacter : Photon.PunBehaviour {
private Vector3 correctPlayerPos;
void Update()
{
if (!photonView.isMine)
transform.position = Vector3.Lerp(transform.position, this.correctPlayerPos, Time.deltaTime * 5);
photonView.RPC ("PrintPosition", PhotonTargets.All, transform.position);
}
void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.isWriting)
{
// We own this player: send the others our data
stream.SendNext(transform.position);
}
else
{
// Network player, receive data
this.correctPlayerPos = (Vector3)stream.ReceiveNext();
}
}
[PunRPC]
void PrintPosition(Vector3 pos)
{
Debug.Log (pos);
//I need to send position coordinates to the other device
}
}
The other class of establish multiplayer environment:
using UnityEngine;
using System.Collections;
public class NetworkManager : Photon.PunBehaviour {
// Use this for initialization
void Start () {
PhotonNetwork.ConnectUsingSettings ("0.1");
//PhotonNetwork.logLevel = PhotonLogLevel.Full;
}
void Update () {
}
void OnGUI()
{
GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
}
public override void OnJoinedLobby ()
{
Debug.Log("join lobby!");
PhotonNetwork.JoinRandomRoom ();
}
void OnPhotonRandomJoinFailed()
{
Debug.Log("Can't join random room!");
PhotonNetwork.CreateRoom(null);
}
void OnJoinedRoom()
{
Debug.Log("join random room!");
GameObject monster = PhotonNetwork.Instantiate("monsterprefab", Vector3.zero, Quaternion.identity, 0);
}
}
PUN has some new components since their new update.
I'd recommend you to use those components because it is really user friendly towards new users.
Some components you could use:
PhotonTransformView
PhotonRigidbodyView
PhotonAnimatorView
These three components will help you sync your position, physics and animations on the GameObject it is attached to.
If you do not want to use these components i suggest you search up: interpolation and extrapolation for Unity PUN.
Some good starting tutorials:
SkyArena PUN Tutorial This is a really good video tutorial[in parts] on PUN so you should definitely check that out.
Exit Games Marco Polo This tutorial is created by someone from PUN also really good to read even if you don't need it.
Hope this will help you.
-Menno
I found the answer in Demo Synchronization that provided in PUN plugin, it is really helpful.

How to call [Command] on Client in UNet(Unity)

I'm working on a Unity 2D multiplayer game using UNet. My problem is that the Client cant send the [Command] to the server. Im debugging on UnityEditor and a built apk for my android phone.
First I used UnityEditor as Host and the phone as Client, the Debug.Log(SkinName) APPEARS on the console.
Then I used UnityEditor as the Client and the phone as Host, the Debug.Log(SkinName) DOES NOT APPEAR.
I tried to use [ClientRpc] instead of [Client] but it just made it worse, both client and host wont sync. I dont know if I excuted the [ClientRpc] in the right way.(im a noob at UNet)
I've visited other threads/forums and other UNet tutorials to look for solutions but this is what I came up with.
Note: On the other threads that I visited, people mostly suggest that Local Player Authority is unchecked and that is what causing the problem but in this case it is CHECKED.
Code:
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using Spine;
using Spine.Unity;
using Spine.Unity.Modules;
class SetupLocalPLayer : NetworkBehaviour {
[SyncVar]
public string SkinName;
public string[] CharNames;
public string[] SlotNames;
public string[] AttachmentSuffix;
void Start (){
TransmitSkins ();
SyncSkin ();
if (isLocalPlayer) {
var skeletonrenderer = GetComponent<SkeletonRenderer>();
for(int z=0;z<SlotNames.Length;z++){
skeletonrenderer.skeleton.SetAttachment(SlotNames[z],GameController.control.skinName+AttachmentSuffix[z]);
}
GetComponent<PlayerManager> ().enabled = true;
GetComponent<FollowCam> ().enabled = true;
}
}
void Update () {
}
void SyncSkin(){
if (!isLocalPlayer) {
var skeletonrenderer = GetComponent<SkeletonRenderer>();
for(int z=0;z<SlotNames.Length;z++){
skeletonrenderer.skeleton.SetAttachment(SlotNames[z],SkinName+AttachmentSuffix[z]);
}
}
}
[Command]
void CmdSetSkin(){
SkinName = GameController.control.skinName;
Debug.Log (SkinName);
}
[Client]
void TransmitSkins(){
if (isLocalPlayer) {
CmdSetSkin ();
}
}
}
Ok, so from what i can see you are trying to sync the skins being used by each player so that each player has the correct skin on every client.
There are a couple of problems with your code, in both syntax and structure.
First lets look at the syntax.
You should absolutely use [ClientRpc] instead of [Client] and the method should be named RpcTransmitSkins. If the script is attached to the player prefab and Local Player Authority is Checked on the network identity then it will work. [Client] belongs to a different networking API entirely.
Now lets look at the structure.
The basic logic is correct, however, in reality the SyncSkin method will be called long before the Transmission is received.
The Start method will not wait for the transmission, so why not move the skin assignment to the Rpc, that way the other versions of the player will only try to assign their skin once the message is received.
You also have certain actions split up that all clients need to do, getting the SkeletonRenderer for example
Here is how I would restructure your script.
void Start (){
//first, grab the SkeletonRenderer on every version of the player.
//note that it should not be a local var now, but a field in the script
skeletonrenderer = GetComponent<SkeletonRenderer>();
//now do the local player specific stuff
if (isLocalPlayer) {
//transmit the skin name to the other versions of the player
CmdSendSkinRpc(GameController.control.skinName);
//then assign the skin to the local version of the player
for(int z=0;z<SlotNames.Length;z++){
skeletonrenderer.skeleton.SetAttachment(SlotNames[z],GameController.control.skinName+AttachmentSuffix[z]);
}
GetComponent<PlayerManager> ().enabled = true;
GetComponent<FollowCam> ().enabled = true;
}
}
[Command]
void CmdSendSkinRpc(string skin){
RpcTransmitSkins(skin);
Debug.Log("Transmitting Skin Named: " + skin);
}
[ClientRpc]
void RpcTransmitSkins(string TransmittedSkinName){
if (!isLocalPlayer) {
Debug.Log("Receiving Skin Named: " + TransmittedSkinName);
for(int z=0;z<SlotNames.Length;z++){
skeletonrenderer.skeleton.SetAttachment(SlotNames[z],TransmittedSkinName+AttachmentSuffix[z]);
}
}
}
Don't be disheartened by the learning curve of the UNET system. It's super confusing to think in multi client and server terms. Even this simple action had me scratching my head for a few minutes :D

Unity Networking: can't spawn scene objects on all clients

I can't really figure out how to solve my problem. I have been looking for an answer but I couldn't find anything.
I have a button in my scene that can be pressed both by client and host. When the button is pressed, it creates a cube in the scene. The problem is that: the cube can be created only by the host and the host is the only user that can see it and manipulate it.
My code is:
public class CreateCube : NetworkBehaviour {
GameObject cubo;
float lastCollisionTime=0;
float collisionTime=0;
void OnCollisionExit(Collision other) {
collisionTime = Time.time;
if (collisionTime - lastCollisionTime >1.5) {
CmdCreaCubo ();
lastCollisionTime = collisionTime;
}
}
}
}
[Command]
void CmdCreaCubo(){
GameObject cubo=Instantiate(Resources.Load("MyPrefabs\\Oggetti\\CubeGrasp")) as GameObject;
cubo.transform.position = new Vector3 (-5.88f, 7.51f, -19f);
cubo.name = "CubeGrasp";
NetworkServer.Spawn (cubo);
}
}
Could anyone help me please?
Thank you so much
Instead using simple Instantiate you should need to use Network.Instantiate
The given prefab will be instanted on all clients in the game.
Synchronization is automatically set up so there is no extra work
involved.

How to fix multiplayer stuttering?

For some reason the other player's movement is 'stuttering'. I know this is a common problem people run into with Photon, so was wondering if anyone knows how I can resolve it?
Here's my player movement code:
public float SmoothingDelay = 5;
public void Start()
{
GetComponent<SmoothSyncMovement>().enabled = true; //This is the name of this script
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.isWriting)
{
//We own this player: send the others our data
stream.SendNext(rb2D.position);
stream.SendNext(rb2D.rotation);
}
else
{
//Network player, receive data
correctPlayerPos = (Vector3)stream.ReceiveNext();
}
}
public void Update()
{
if (!photonView.isMine)
{
Vector2 playerMovement = rb2D.position + velocity * Time.deltaTime;
rb2D.MovePosition(playerMovement);
}
if (photonView.isMine)
{
Vector2 playerMovement = rb2D.position + velocity * Time.deltaTime;
rb2D.MovePosition(playerMovement);
}
}
Make a smooth transition between players old possible and new position, dont set position. You can use lerp for this or any other method.
This video tutorial goes into all the details of photon networking including how to deal with stuttering and other issues you might run into. Video Tutorial Play List
Exact Video That Addresses Stuttering
It would look something like this:
currentPosition = Vector3.Lerp(currentPosition, realPosition,0.1f);
Where currentPosition is the position of the networked player before it moves on your client and realPosition is the new position received from the network where you want the player to be.

Categories