Shooting projectiles and detecting collisions with Points

Options
Ok I'm a bit stumped on this one. In my game players can shoot projectiles at each other and when hit they respawn and the player hit gets their points increased which is essentially deaths in the game. The problem I have is that every time the collisions happen points get added to both players. I'm wondering about using an RPC method within there but I have no idea what part should be included in the RPC and which should be local.

Here is my script for the player health:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHealth_Basic : Photon.PunBehaviour
{

    void OnCollisionEnter(Collision col)
    {
		if(col.gameObject.CompareTag("Ball"))
		{
			Debug.Log("Player " + PhotonNetwork.player.ID + " Hit by ball on body or head");
			}
    }


	void RespawnOnHit ()
	{
		
		PhotonNetwork.player.AddScore(1);
		Debug.Log("Added points to " + PhotonNetwork.player.ID);
		GameManager_Basic.Instance.RespawnPlayer(this.transform);
	}
}

Comments

  • Ok I tested this out with two players. One had the health script and the other didn't, yet randomly the points keep adding up for the other player. There's nothing else that would be adding points besides that script. I honestly don't know where else to look. The score is being updated in a separate score manager script in this way:
     void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps)
        {
            
            PhotonPlayer[] pList = PhotonNetwork.playerList;
              System.Array.Sort(pList, delegate (PhotonPlayer p1, PhotonPlayer p2) { return p1.ID.CompareTo(p2.ID); });   System.Array.Reverse(pList);
             
            for (int i = 0; i < pList.Length; i++)
            {
                PhotonPlayer player = pList[i];
                scoreText[i].text = player.GetScore().ToString();
                Debug.Log("Score text " + i + " connected to " +"Player " + player.ID + " score " + player.GetScore());
    
            }
        }
        
    It seems to be adding points randomly. Sometimes it'll update with just one out of the blue, then sometimes it'll add a few points and I have no idea why.
  • Ok I'm not entirely sure what the issue is, but I am looking at building another game that also utilizes projectiles. Is there an ideal way to utilize projectiles within Photon?
  • Hi @jgonzosan,

    as far as I see, the problem might be, that void RespawnOnHit () gets called on each client and is processed completely. Means that each client in the room calls PhotonNetwork.player.AddScore(1); and adds one to his own score. You can avoid this by surrounding this (and maybe other calls) with a if (photonView.isMine) condition.
  • jgonzosan
    jgonzosan
    edited September 2018
    Options
    I tried that but when I do it doesn't add points. It seems to only give me points if I shoot myself, but when I shoot another player nothing happens. I'll give it another try with that, thanks for the info.
  • Ok so I tried it with isMine:
    void OnCollisionEnter(Collision col)
        {
            if (col.gameObject.CompareTag("Ball"))
            {
    
                GameManager_Basic.Instance.RespawnPlayer(this.transform);
                Debug.Log("Player " + PhotonNetwork.player.ID + " Hit by ball on body or head");
               
               if(photonView.isMine){
                PhotonNetwork.player.AddScore(1);
               }
            }
        }
    but this only seems to work if I shoot myself. In the game you can take yourself out with projectiles if you don't aim correctly so it's not specific to enemies. With isMine added in it seems to ignore collisions if they're not shot locally. Is there something else I'm missing here? I know Photon doesn't detect collisions, so am I supposed to be using the Respawn method as an RPC?
  • Firstly you should decide, who should handle collisions. This can be either done by the MasterClient for all objects or by each client for his objects individually. In both cases, you would have to add a certain condition to not handle OnCollisionEnter on a client who doesn't have the permission to do so. If you for example want to handle collision handling on the MasterClient, you want to add the if (!PhotonNetwork.isMasterClient) return; condition.

    Whenever an object got hit, you can use a RPC to respawn it. This can be done by either the MasterClient or the owner of the object. It should basically be done by the same client who handles collision detection. When the respawn RPC is processed on all clients, you can use PhotonNetwork.player.AddScore surrounded by a if (photonView.isMine) condition in order to increase the client's death counter.
  • Ok this is what I have and this seems to respawn both players and also give points to both of them.
    public class PlayerHealth_Basic : Photon.PunBehaviour
    {
    
        void OnCollisionEnter(Collision col)
        {
           
            
            if (col.gameObject.CompareTag("Ball"))
            {
              
                Debug.Log("Hit by ball");
                photonView.RPC("Respawn", PhotonTargets.All);
               
            }
        }
    
        [PunRPC]
        void Respawn ()
        {
               
               if(photonView.isMine){
              
                PhotonNetwork.player.AddScore(1);
                Debug.Log("Player " + PhotonNetwork.player.ID + " Hit by ball on body or head");
                GameManager_Basic.Instance.RespawnPlayer(this.transform);
               }
                
        }
    
    
    }
    I also tried doing it the master client way as such:
    public class PlayerHealth_Basic : Photon.PunBehaviour
    {
    
        void OnCollisionEnter(Collision col)
        {
           if(!PhotonNetwork.isMasterClient)
           return;
           
            
            if (col.gameObject.CompareTag("Ball"))
            {
              
                Debug.Log("Hit by ball");
                photonView.RPC("Respawn", PhotonTargets.All);
               
            }
        }
    
        [PunRPC]
        void Respawn ()
        {
               
               if(photonView.isMine){
              
                PhotonNetwork.player.AddScore(1);
                Debug.Log("Player " + PhotonNetwork.player.ID + " Hit by ball on body or head");
                GameManager_Basic.Instance.RespawnPlayer(this.transform);
               }
                
        }
    
    
    }

    That only seems to work for the Master. So the Master points and respawning happens, but the clients don't respawn or get any points, even if the client is shooting the player. I'm really confused as to why this isn't working.
  • Ok so I tested it again using just the "isMine" from the script up above just doing the collision on the client and it works for the most part. I think it might just be lag in my game. I'm using the FPS controller for testing and I notice that if I shoot the ball while running forward I'll respawn as if I got hit.

    It's consistent for both players even though I can see the ball in front of me. I can only assume that it's lagging and I'm actually getting hit. When I do the same shoot and run but move to the side while running it doesn't happen. I can run towards a player, stop, then shoot and it works just fine for both players.

    I'm going to assume that's what the issue is unless there's something wrong with the script I posted up above. For clarification I'm not checking for collision on the master but I am using "isMine" in the RPC method for Respawn.
  • If you don't use the either the isMine or the isMasterClient condition in OnCollisionEnter, each client, who detects the collision, will send this RPC. If you for example have two clients in the room and both of them are detecting a collision, both of them will send the RPC and each client will at least call the certain function. If you have the isMine condition in this [PunRPC] marked function, only the owner will process the code in it, however he will do it twice (in this example). You should make sure, that this RPC is only sent once.
  • Oh ok, so use "isMine" before I even call the RPC? I'll add that in, thanks.