Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Invoking RPC to affect "others" variables

Discussion in 'Multiplayer' started by Ibzy, Apr 14, 2014.

  1. Ibzy

    Ibzy

    Joined:
    Sep 15, 2013
    Posts:
    112
    I'm trying to create a simple 1v1 multiplayer game but am struggling with the (supposedly) easiest of steps.

    Very basic, cut-down version for testing purposes: Player 1 presses a button, player 2 takes damage and vice-versa.

    Code (csharp):
    1.  
    2. public int playerHealth = 10;
    3.  
    4. void OnGUI(){
    5.         if (GUI.Button(new Rect(originalWidth-60,originalHeight/2-25,50,50),"Attack"))
    6.             Attack();
    7. }
    8.  
    9. [RPC] void Attack(){
    10.         if (networkView.isMine){
    11.             networkView.RPC("Attack",RPCMode.OthersBuffered);
    12.             Debug.Log ("I Attacked");
    13.         } else {
    14.             networkView. RPC("TakeDamage",RPCMode.AllBuffered, 1);
    15.             Debug.Log ("I Was Attacked");
    16.         }
    17.     }
    18.  
    19. [RPC]
    20.     public void TakeDamage(int damage){
    21.             Debug.Log("I Took Damage");
    22.             playerHealth -= damage;
    23.     }
    24.  
    Currently this causes Player 1 to attack AND take damage. Can anybody please help me figure where I'm going wrong?

    Thanks
     
  2. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,062
    You call the RPC "Attack" on the others. Everyone else will call the RPC "TakeDamage" on ALL clients.
    You can call "TakeDamage" on others instead. Alternatively you can call "Attack" on others (like you do now) but in the else case, call TakeDamage not as RPC but as local method.

    Aside from that, you might want to not use "Buffered" mode. This will store the RPC and anyone who joins later will also take damage (even though the attack happened way before)...

    Good luck!
     
  3. Ibzy

    Ibzy

    Joined:
    Sep 15, 2013
    Posts:
    112
    Hi Tobias,

    Thanks for your reply. Would only calling TakeDamage on Others result in "my" view not updating their health?
    I tried "else TakeDamage(1)" before, but that still caused the attacking player to take damage, it's almost like I need to say "otherPlay.TakeDamage(1)", but I have no way of referencing the other player?

    As for Buffered, there is only every going to be 2 players, and attacking will be restricted until both are present, so this is set in order for attacks to still register in the result of a temporary connection drop (may be misunderstanding this part, so could possibly be talking nonsense :p )

    Thanks
     
  4. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,062
    You call the RPC on some networkView, which belongs to some GameObject which was (most likely) instantiated by some player.
    I don't know how you store the health but it looks like it's part of the script. So the individual script instances keep their own health.

    The TakeDamage method is executed on that GameObject on all clients that get the RPC.
    You implicitly know which player TakeDamage targets. It simply can reduce health in the RPC method and call it on "All" clients, instead of calling it on "Others" only.

    Hope that helps.
     
  5. Ibzy

    Ibzy

    Joined:
    Sep 15, 2013
    Posts:
    112
    Correct on all accounts.

    Please forgive my stupidity here, but although I know which player should TakeDamage I'm unsure how I am to target it? I have tried setting a static GameObjects to player1 and player2 on connection to the server, but I keep getting null references.

    Thanks
     
  6. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,062
    I don't know what exactly you want to access. Player? There is a PhotonPlayer but that class does not have a "health" value, so that doesn't help anyways.

    As you can access the PhotonView component on any "networked" GameObject you instantiated, you can also access the owner and the PhotonView.ownerId. You can create a Dictionary<int, myPlayerWithHealth> to easily access your class for any given PhotonPlayer. You only need to make the link once.
    Let's say someone instantiates a GameObject, then you create myPlayerWithHealth and put it in the dictionary, using the ownerId as key. You can do that if you implement OnPhotonInstantiate(PhotonMessageInfo info){ ... } in a script on the Prefab you use.
     
  7. Ibzy

    Ibzy

    Joined:
    Sep 15, 2013
    Posts:
    112
    Maybe I need to be a bit more exact with my predicament?

    Each player instantiates a "Player" GameObject when they join the server (maximum 2 players). Each "Player" has a "player" script attached to it which contains the playerHealth variable. When Player1 attacks I want to be able to say the equivalent of: player2.playerHealth -= 1;

    Hope this makes sense?

    Thanks