Search Unity

Help with Player Pick Up

Discussion in 'Multiplayer' started by Nitro00, Jan 11, 2018.

  1. Nitro00

    Nitro00

    Joined:
    Jan 11, 2018
    Posts:
    18
    So, I was creating a pickup method attached to the object that needs to be picked up. However, when testing with multiple players, when the object is picked up it goes to a different player. How do I make it go to the player that pressed the button? Also, follow up question, how do I make the item show up for other players on the server. (When the player tries to pick the sword up, it goes to the other player on his screen but it doesn't show up for everybody else, so would I just need to give the object a network transform?)


    PS: I am fairly new to coding and while I did write this myself I might not understand your replies, so please try to explain as best as you can :)

    Here is my code:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PickUp : MonoBehaviour {
    6.  
    7.  
    8.     public GameObject sword;
    9.     public GameObject player;
    10.     public GameObject playerPrefab;
    11.     bool equipped = false;
    12.  
    13.     // Use this for initialization
    14.     void Start () {
    15.  
    16.     }
    17.    
    18.     // Update is called once per frame
    19.     void Update () {
    20.        
    21.         if (player == null) {
    22.             player = GameObject.FindWithTag ("Player");
    23.         }
    24.  
    25.         if (equipped == true) {
    26.             if (Input.GetButtonDown ("Drop")) {
    27.             sword.transform.parent = null;
    28.                 equipped = false;
    29.         }
    30.         }
    31.  
    32.     }
    33.  
    34.     void OnMouseOver()    {
    35.        
    36.         if (sword.transform.parent == null) {
    37.            
    38.             if (equipped == false) {
    39.            
    40.                 if (Input.GetButtonDown ("Pick")) {
    41.                     sword.transform.parent = player.transform;
    42.                     sword.transform.localPosition = new Vector3 (0.2f, 0.5f, 0.6f);
    43.  
    44.                     equipped = true;
    45.                 }
    46.  
    47.             }
    48.  
    49.         }
    50.     }
    51.  
    52. }
    53.  
     
  2. uaioe

    uaioe

    Joined:
    Feb 11, 2013
    Posts:
    1
    Could it be that your Update and OnMouseOver methods need to check if it is the local player before handling input? Right now I believe all player objects that are loaded are handling the local input in the client, so you think your real local player is picking up the item, but really all of the player objects are seeing the Input.GetButtonDown and trying to pick up the item?

    You can try adding this at the start of Update and OnMouseOver methods, before you start handling local input.

    Code (CSharp):
    1.  
    2. if (!isLocalPlayer)
    3.        return;
     
  3. Nitro00

    Nitro00

    Joined:
    Jan 11, 2018
    Posts:
    18
    Will try to test out when I can, currently busy with other things!
     
  4. ItsaMeTuni

    ItsaMeTuni

    Joined:
    Jan 19, 2015
    Posts:
    44
    As you said you're new to programming I'll try my best to explain as simple as possible.
    1) The first thing I see in your code is that this
    Code (CSharp):
    1.  
    2. if (player == null) {
    3.       player = GameObject.FindWithTag ("Player");\
    4. }
    should be in the Start method to run this once.
    2) You are searching for an object with the tag "player". If it is a multiplayer game there will be more than one object called player. The way to do this is by iterating through all players and checking which one is the local player like this
    Code (CSharp):
    1. void Start()
    2. {
    3.        foreach(GameObject _player in Find("player"))
    4.        {
    5.               if(_player.GetComponent<NetworkIdentity>().isLocalPlayer)
    6.               {
    7.                      player = _player;
    8.               }
    9.        }
    10. }
    3) You should use Commands (call a function from the client and execute it on the server) and Client RPCs (call a function from the server and execute it on the client). I won't explain how this works here because if I do I'd be write a really long post explaining all the little parts and tricks to get it working.

    Here is how I would've done it:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public class PickUp : MonoBehaviour {
    5.     [SyncVar]
    6.     public GameObject sword;
    7.     public GameObject player;   //Notice we don't need this variable on the server
    8.     public GameObject playerPrefab;
    9.  
    10.     [SyncVar] //this attribute keeps the variable from the client in sync with the server (only the server can change it)
    11.     bool equipped = false;
    12.     // Use this for initialization
    13.     void Start () {
    14.         if(!isServer)
    15.         {
    16.             //Find the local player
    17.             foreach(GameObject _player in GameObject.FindGameObjectsWithTag ("Player"))
    18.             {
    19.                 if(_player.GetComponent<NetworkIdentity>().isLocalPlayer)
    20.                     player = _player;
    21.             }
    22.         }
    23.     }
    24.  
    25.     // Update is called once per frame
    26.     void Update ()
    27.     {
    28.         if(isServer)
    29.         {
    30.             return;
    31.         }
    32.  
    33.         if (Input.GetButtonDown ("Drop") && equipped)
    34.         {
    35.             CmdDrop();
    36.         }
    37.     }
    38.     void OnMouseOver()
    39.     {
    40.      
    41.         if (sword.transform.parent == null && !equipped)
    42.         {
    43.             if (Input.GetButtonDown ("Pick"))
    44.             {
    45.                 CmdPick(player);
    46.             }
    47.  
    48.         }
    49.     }
    50.  
    51.  
    52.     //Tell the server to pick the object and put in the hand of the player that clicked on it
    53.     [Command]
    54.     void CmdPick(GameObject playerThatPickedUp)
    55.     {
    56.         sword.transform.parent = playerThatPickedUp.transform;
    57.         sword.transform.localPosition = new Vector3 (0.2f, 0.5f, 0.6f);
    58.  
    59.         equipped = true;
    60.     }
    61.  
    62.     //Tell the server to drop it
    63.     [Command]
    64.     void CmdDrop()
    65.     {
    66.         sword.transform.parent = null;
    67.         equipped = false;
    68.     }
    69. }
    I did not test this code, but it should work. If it doesn't, just by looking at it you already know what to search for on Google.

    Btw, you should see a UNet tutorial series on youtube. GTGD's (it's a youtube channel)
    series on UNet is pretty good.
    Hope to have helped!
     
    FireBird110 likes this.
  5. FireBird110

    FireBird110

    Joined:
    May 20, 2017
    Posts:
    2

    Should we also add a RPC call to tell other players?
    PS. There are some other ways to change player names in this way you don't have to worry about checking isLocalPlayer!





    Credit; Game to Gamer, youtuber
     
  6. ItsaMeTuni

    ItsaMeTuni

    Joined:
    Jan 19, 2015
    Posts:
    44
    If the object has a network transform component I think it will be automatically synced to other clients. If it doesn't, then you should make a RPC.