- Home /
Photon PUN 2 RPC function doesn't change a variable value
Hi to everyone, I have this problem: I have an RPC function, called RPC_FoodInGameSync(bool), which is called by a client when this one takes the pick up in the scene. This function should set the value of the boolean variable "food_ingame" in every client, but it doesn't change its value (false if the pick up is taken, true if the pick up is instantiated, so it is in the scene). Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
public class PUN2_FoodSync : MonoBehaviourPun
{
PhotonView PV;
public GameObject[] food_prefabs; // array that contains the food prefabs
Vector3[] positions = {new Vector3(10,0,1),new Vector3(10,0,5),new Vector3(2,0,6),
new Vector3(4,0,9),new Vector3(0,0,-10),new Vector3(-4,0,-5),
new Vector3(-7,0,-8),new Vector3(-5,0,-5)}; // Vector that contains the spawn points of the food
public Vector3 position; // current position of the food in the scene
public bool food_ingame; // variable which says if there is a food in the scene or not
// Start is called before the first frame update
void Start()
{
PV = GetComponent<PhotonView>();
food_ingame = false; // initially, there is no food in scen, so this variable is set to false
}
// Update is called once per frame
void Update()
{
if(photonView.IsMine)
{spawn_food();} // this is the fuction for instantiating the food
}
void spawn_food()
{
if(food_ingame == false) // if there is no food, let's spwan one
{
if(PhotonNetwork.IsMasterClient) // only the Master can define the position of the food
{
Vector3 pos = positions[Random.Range(0,positions.Length)]; // choose the food position
PV.RPC("RPC_FoodInGameSync",RpcTarget.AllBuffered, true); // say to every client that there is a food in the scene
PV.RPC("RPC_FoodPositionSync",RpcTarget.AllBuffered,pos); // send the position of the new food, in order to the clients
// know where to instantiate the new food
}
}
}
void OnTriggerEnter(Collider col)// this method check if there are object that are collinding with the player (OnCollisionEnter(Collision col))
{
if(col.gameObject.tag == "Food") // if a player touch a food
{
if(photonView.IsMine) // if it was the local player, then:
{
// Controllore2 is a scipt attached to the player, which is use to move the player and to do others things
GetComponent<Controllore2>().old_size = GetComponent<Controllore2>().scala.x; // save the old size
if(GetComponent<Controllore2>().timer_array[0].activated == true) // timer_array[0] is a timer for slowly increasing the size of the player
{GetComponent<Controllore2>().old_size = GetComponent<Controllore2>().old_size + GetComponent<Controllore2>().add_size;}
GetComponent<Controllore2>().add_size = col.gameObject.GetComponent<Food>().add_size; // pass the value to be added to the player size
PV.RPC("RPC_FoodInGameSync",RpcTarget.AllBuffered, false); // say to every client that we have eaten the food
}
else // another client has taken the food
{
Debug.Log("the enemy has eaten the food!!!");
}
Destroy(col.gameObject); // destroy the local food
}
}
[PunRPC]
void RPC_FoodPositionSync(Vector3 positionSync)
{
position = positionSync;
// every client spawn a local food
Instantiate(food_prefabs[0],position, Quaternion.identity);
}
[PunRPC]
void RPC_FoodInGameSync(bool puInGameSync)
{
// update this variable on every client
food_ingame = puInGameSync;
}
}
When a client takes the pick up, it will call the RPC_FoodInGameSync(bool) rpc function in order to set the variable “food_ingame” to false in every client. When the Master receives this RPC function, it will see food_ingame=false, so then it will generate a position with the function spawn_food(), which will be sent through the networks by means of the rpc function RPC_FoodPositionSync(Vector3), in order to every client will instantiate the pick up in local and in the same position. There is no problem the first time these rpc functions are called (when the game starts), so the pick up is istantiated locally in each client in the correct position, but when a client (also the master) takes the pick up, the value of “food_ingame” will not change from true to false. The pick up, when it is taken, it is correctly destroyied in each client. Maybe is there some concurrency problem between the RPC calls of the client (when it takes the pick up) and of the master (when it instantiates the pick up)? Maybe should I use another RpcTarget? Thank you!
Answer by 9NICK6 · May 12, 2020 at 08:24 PM
Hi, I finally solved the problem, it seems that it is not possible to change the value of a variable in a client by means of an RPC function. I tried to have access to a variable through an RPC function also by means of “GetComponent”, but nothing. I solved the problem by converting the spawn_food() function (which spawn a food in the scene) in an RPC function: RPC_SpawnFood(). This fuction is called by who takes the pick-up, and it is sent only to the master client, which will generate a random spawn position, that will be send through the network by using the RPC function RPC_FoodPositionSync() and by using the target RpcTargt.AllBufferedViaServer, in this way every clients (also the master) will istantiate the pick-up “at the same time”. Here is the new code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
public class PUN2_FoodSync : MonoBehaviourPun
{
PhotonView PV;
public GameObject[] food_prefabs; // array that contains the food prefabs
Vector3[] positions = {new Vector3(10,0,1),new Vector3(10,0,5),new Vector3(2,0,6),
new Vector3(4,0,9),new Vector3(0,0,-10),new Vector3(-4,0,-5),
new Vector3(-7,0,-8),new Vector3(-5,0,-5)}; // Vector that contains the spawn points of the food
public Vector3 position; // current position of the food in the scene
public bool food_ingame; // variable which says if there is a food in the scene or not
// Start is called before the first frame update
void Start()
{
PV = GetComponent<PhotonView>();
food_ingame = false; // initially, there is no food in scen, so this variable is set to false
if(PhotonNetwork.IsMasterClient) // if we are the master, when we enter in the scene we will spawn the food
{PV.RPC("RPC_SpawnFood",RpcTarget.MasterClient);}
}
void OnTriggerEnter(Collider col)// this method check if there are object that are collinding with the player (OnCollisionEnter(Collision col))
{
if(col.gameObject.tag == "Food") // if a player touch a food
{
if(photonView.IsMine) // if it was the local player, then:
{
// Controllore2 is a scipt attached to the player, which is use to move the player and to do others things
GetComponent<Controllore2>().old_size = GetComponent<Controllore2>().scala.x; // save the old size
if(GetComponent<Controllore2>().timer_array[0].activated == true) // timer_array[0] is a timer for slowly increasing the size of the player
{GetComponent<Controllore2>().old_size = GetComponent<Controllore2>().old_size + GetComponent<Controllore2>().add_size;}
GetComponent<Controllore2>().add_size = col.gameObject.GetComponent<Food>().add_size; // pass the value to be added to the player size
PV.RPC("RPC_SpawnFood",RpcTarget.MasterClient); // say to Master that we have eaten the food, so he has to spawn another food
}
else // another client has taken the food
{
Debug.Log("the enemy has eaten the food!!!");
}
Destroy(col.gameObject); // destroy the local food
}
}
[PunRPC]
void RPC_FoodPositionSync(Vector3 positionSync)
{
position = positionSync;
// every client (also the master) spawns a local food at the same position
Instantiate(food_prefabs[0],position, Quaternion.identity);
}
[PunRPC]
void RPC_SpawnFood()
{
if(PhotonNetwork.IsMasterClient) // only the Master can define the position of the food
{
Vector3 pos = positions[Random.Range(0,positions.Length)]; // choose the food position
// Now send the position of the new food, in order to the clients know where to instantiate the new food:
this.GetComponent<PhotonView>().RPC("RPC_FoodPositionSync",RpcTarget.AllBufferedViaServer,pos);
// we send this RPC function in order to each client will spawn the food at the same time
}
}
}
Answer by fblast1 · May 06, 2020 at 05:35 AM
Try changing RPCTarget to AllViaServer or AllBufferedViaServer
Regards