Recently switched from SFS to Photon - Been stuck on this...

Options
When instantiating players (2D game) I have a single prefab that I use. From there I will change the SpriteRenderer to show what the player actually has chosen. In SFS it was a simple player variable that I would store and call when needed, however with photon it seems a little different. The local player character works just fine as it should, however when I try to announce to everyone that "hey" i've changed my 'skin' I get all sorts of different errors, no matter which way I try.

SS w/ errors: http://i.imgur.com/0bnXGnR.png

It seems that all the remote players still show the default (TRex) skin and don't change. For some reason that i can't figure out, the RPC method calls viewID's 1002, and 2002 which in this particular case it should be 1001 and 2001 since that is how they are assigned at run time.

[code2=csharp]void OnJoinedRoom()
{
Debug.Log("NET: Successfully Joined Room");
Avatar = PhotonNetwork.Instantiate("Player", new Vector3(-3.305943f, 0.3286543f, 0.4448996f), Quaternion.identity, 0) as GameObject;

PhotonView photonView = PhotonView.Get(Avatar.GetComponent<PhotonView>());
networkView.viewID = PhotonNetwork.AllocateViewID();
networkView.RPC ("ChangeSkin", PhotonTargets.AllBuffered, null);
}

[RPC]
void ChangeSkin()
{
Avatar.GetComponentInChildren<SpriteRenderer>().sprite = Resources.Load("Characters/" + PlayerPrefs.GetString("Avatar"), typeof(Sprite)) as Sprite;
Avatar.GetComponent<Rigidbody2D>().isKinematic = true;
Avatar.transform.localScale = new Vector2(1, 1);
Avatar.name = PlayerPrefs.GetString ("USERNAME");
}[/code2]

Any idea on what could be causing this?

Comments

  • I've never personally used AllocateViewID, but why would you use that when view Id's are automatically assigned as long as you have a PhotonView on the prefab? You're probably ending up with 1002, 2002 because you're allocating another view id, which might naturally be the next one in line. I'm not really sure though, like I said, I've never seen an instance to manually allocate it.

    What I do is serialize the avatar information and pass it as instantiationData to PhotonNetowrk.instantiate.

    Then, after the character is spawned on all clients, I fire an applyAvatar RPC which takes the instantiation data as a parameter, and applies the avatar then.

    On a side note, from your code, it looks like you would be assigning the player pref Avatar that is saved on each client of the spawning player, not the avatar of the person who just spawned.
  • dontonka
    Options
    Hello NameTaken33.

    As far as I understand, the viewID must be the same to make this work out!
    For example, local player must a have a photoViewId of 1001, and the his representation on the remote device (which would be another GameObject), must also have a photonViewID with the same value. This is the way this communication is working and that PUN can know where specific message goes on the receiver side.

    In your specific case, you probably not need the "PhotonNetwork.AllocateViewID()" if your Avatar prefab has a photonView already defined as a component. From what I understand, when you use PhotonNetwork.Instantiate, you should definitely not be using AllocateViewID.

    In my case I did switch from Badumna to Photon, and in my game i could not use the classic PhotonNetwork.Instantiate it was breaking out too many things in my current architecture. I end up using AllocateViewID. Here is my code snapshot and some more explanation how i use it, I hope it can help some devs :).
       private void CreateLocalPlayer()
        {
           // Player component is an internal script component specific to my game, so don't worry about it.
            // Nevertheless, GameManager.Manager.mAppManager.Player is my GameObject which represent my local player. it has no photonViewID in the prefab.
            var localPlayer = GameManager.Manager.mAppManager.Player.AddComponent&lt;Player&gt;();
    
    		// Create the photonview for the local player and send request to create the remote player
    	    int playerViewId = PhotonNetwork.AllocateViewID();
    		var playerView = GameManager.Manager.mAppManager.Player.AddComponent&lt;PhotonView&gt;();
    		playerView.viewID = playerViewId;
    		playerView.observed = localPlayer;
    		playerView.synchronization = ViewSynchronization.UnreliableOnChange;
    
                   // send the RPC to create the player GameObject on remote players. GamePhotonView is a photonViewID owned by the scene which I use to send any generic information.
    		GamePhotonView.RPC("CreateRemotePlayer", PhotonTargets.Others, GameManager.Manager.PlayerName, playerViewId, localPlayer.SoldierColor);
        }
    
       &#91;RPC&#93;
       private void CreateRemotePlayer(string aPlayerName, int aPhotonPlayerId, int aSoldierColorIdx)
        {
           // the Enemy prefab has already a photonViewID, but the id is assigned at runtime.
    	var remotePlayer = GameObject.Instantiate(Resources.Load("Enemy", typeof(GameObject))) as GameObject; 
            if (remotePlayer == null)
            {
                GameManager.debugLog("Failed to instantiate Enemy prefab!");
                return;
            }
            
    	    // Set player's PhotonView
    	    var playerView = remotePlayer.GetComponent&lt;PhotonView&gt;();
    	    playerView.viewID = aPhotonPlayerId;
    	}
    
    

    Don T.
  • Tobias
    Options
    Dontonka: Thanks for helping out. Your explanation is spot on.
    FarmerJoe: You can use AllocateViewID and PhotonViews in cases where our Instantiate method does not fit your needs. PUN requires you to put prefabs into "Resources" folders. If you want to load such assets from a dynamic source or want to pool the GOs, then you can use Unity's Instantiate and assign PhotonView with a unique ID. You just have to make sure all clients do the same and assign the ID.

    You can store player variables as "Custom Properties" and they get synced. This should be close to SFS.
    Use PhotonNetwork.player.SetCustomProperties() to set key-values and access them per player as player.customProperties[propName].
    There is even a callback when some player property changed.
  • Awesome, thanks for the explanation Tobias.