- Home /
How to swap purchased weapons over Photon Network?
Hello all!
EDIT: TL;DR - How do I make a change on just my player, but be able to display that change over the Photon Network to the other players?
I have been working with Unity and C# for a little while and am making a multiplayer shooter. I have made a lot of progress on this, even the multiplayer part. But I have hit a bit of a road block, which I spent most of today trying to figure out and I feel I just wasted a lot of time barking up the wrong tree!
My game currently has a Zombies mode where you and other players team up and try and hold out against waves of zombies as long as you can. There is a little store you can purchase power-ups and weapons from, very similar to Counter Strike. When you start the game, your selected character(4 in total) starts with his own default weapon which is different than the others.
Everything works great if it is just one player. You can press a button and switch between all your purchased weapons and they have their own weapon data and that works great.
My Setup: The player can select which character they want, and when they check ready, they spawn at a random location with that character. By default, that character has only its default weapon spawned on a "Weapon Container" child of the Player object. When you purchase a weapon, a script in a global object "StoreManager" instantiates it for the player and adds it to the weapon swapping list in the "WeaponChangeManager" script, which is a component in the Weapon Container object.
The Problem: The problem comes from purchasing a weapon from the store and having all players in the room be able to see it. At the moment, I was able to play with the code until I can spawn a weapon on Player 1 on one build, but on Player 2 on the second build. I need that weapon to spawn on Player 1 on all builds.
public class StoreManager : Photon.MonoBehaviour {
public GameObject player;
WeaponChangeManager weaponChangeManager;
PhotonView pv;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag("Player");
weaponChangeManager = player.gameObject.GetComponentInChildren<WeaponChangeManager>();
pv = weaponChangeManager.gameObject.GetComponent<PhotonView>();
}
// Update is called once per frame
void Update () {
if (player == null)
{
player = GameObject.FindGameObjectWithTag("Player");
}
if (weaponChangeManager == null)
{
//weaponChangeManager = GameObject.FindObjectOfType<WeaponChangeManager>();
weaponChangeManager = player.gameObject.GetComponentInChildren<WeaponChangeManager>();
}
}
// What happens if player buys Health
public void PurchasedHealth(int healthToIncrease)
{
player.GetComponent<Health>().currentHealth += healthToIncrease;
if (player.GetComponent<Health>().currentHealth > 100)
{
player.GetComponent<Health>().currentHealth = 100;
}
}
// What happens if player buys Grenade
public void PurchasedGrenade(int grenadeToIncrease)
{
player.GetComponent<PlayerShooting>().grenadeCount += grenadeToIncrease;
// Sets the grenade count to 4 if count goes over 4
if (player.GetComponent<PlayerShooting>().grenadeCount > 4)
{
player.GetComponent<PlayerShooting>().grenadeCount = 4;
}
}
[PunRPC]
public void InstantiateSMG(int receivedID, Vector3 localPos, Vector3 localAngle)
{
if (!pv.isMine)
{
return;
}
if (PhotonNetwork.player.ID != receivedID)
{
GameObject SMGCreated = (GameObject)Instantiate(weaponChangeManager.SMG);
SMGCreated.transform.parent = weaponChangeManager.weaponContainer.transform;
SMGCreated.transform.localPosition = localPos;
SMGCreated.transform.localEulerAngles = localAngle;
}
//weaponChangeManager.weapons.Add(SMGCreated); // Adds this weapon to the list in Weapon Container
}
// What happens if player buys SMG Weapon
public void BuySMG(bool purchased)
{
weaponChangeManager.SMGPurchased = purchased; // SMG is purchased
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class WeaponChangeManager : Photon.PunBehaviour {
public List<GameObject> weapons; // The list of guns the player is carrying
public int selectionIndex = 0;
int x = 0;
// Which weapons you have purchased
public bool MGPurchased;
public bool RiflePurchased;
public bool SMGPurchased;
public bool SniperRiflePurchased;
// Weapon Prefabs and the Weapon Container in game Prefab
public GameObject MG;
public GameObject Rifle;
public GameObject SMG;
public GameObject SniperRifle;
public GameObject weaponContainer;
StoreManager storeManager;
NetworkManager networkManager;
// Use this for initialization
void Start () {
weapons = new List<GameObject>();
storeManager = GameObject.FindObjectOfType<StoreManager>();
networkManager = GameObject.FindObjectOfType<NetworkManager>();
// Disables all game objects in the ModelContainer Game Object
foreach (Transform t in transform)
{
weapons.Add(t.gameObject);
t.gameObject.SetActive(false);
}
// Sets selected model to active
weapons[selectionIndex].SetActive(true);
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown("t")) // Key for changing weapons, if you have any
{
if (x >= 1)
{
x = -1;
}
Select(x = x + 1);
GetComponent<PhotonView>().RPC("Select", PhotonTargets.AllBuffered, x);
}
if (SMGPurchased)
{
storeManager.GetComponent<PhotonView>().RPC("InstantiateSMG", PhotonTargets.AllBuffered, networkManager.individualID, weaponContainer.transform.localPosition, weaponContainer.transform.localEulerAngles);
}
}
// The buttons tell this which models to display
[PunRPC]
public void Select(int index)
{
if (index == selectionIndex)
return;
if (index < 0 || index >= weapons.Count)
return;
weapons[selectionIndex].SetActive(false);
selectionIndex = index;
weapons[selectionIndex].SetActive(true);
}
}
I am not sure how to proceed from here. I think the issue I am having is that I am telling it to go to the Weapon Container, but each build has its own Weapon Container for its own character, which is why I was playing around the with Player IDs trying to get it to work that way.
If any one could just steer me in the right direction I would appreciate it! :)
Answer by ChristianSimon · Jan 23, 2017 at 09:53 AM
Hi,
you need to check if the game object is yours (means the local client) when you perform input checks. So in this case I guess you need to extend the WeaponChangeManager with a private PhotonView pView;
. In the Start() function you need to assign a value to the PhotonView component. Since the WeaponChangeManager is a child of the Player (hopefully I got this right from your source code) you can use pView = GetComponentInParent<PhotonView>();
. Finally in the Update() function before you check input (best: at the beginning of the function), add this:
if (!pView.isMine)
{
return;
}
This makes sure, that you only continue, if the current game object is yours.
For synchronization: I think the best approach is to implement IPunObservable
interface which forces you to add public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
function. Using this, you can easily send the player's currently active weapon to other clients. You maybe want to use IDs for that. This can look like this:
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.isWriting)
{
stream.SendNext(currentWeaponId);
}
else
{
currentWeaponId = (int) stream.ReceiveNext();
if (currentWeaponId == 1)
{
// Activate the weapon with unique ID 1
}
}
}
A somehow related tutorial using IPunObservable can be found here.
Sorry for the late reply, but yes that worked! I sort of had an idea about how to go about it, but I could just not come up with a solution for the life of me, thanks!