1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

why my enemy fires bullet for each logged-in player

Discussion in 'Multiplayer Networking' started by skattigat, Mar 13, 2017.

  1. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Hello to all,

    in a small multiplayer game I have an enemy with a simple script to shoot to players.

    The problem is that the enemy instantiates a bullet for each player present in the room.
    Here is my code:

    Code (CSharp):
    1. void EnemyShoot() {
    2.         if (ShootTimer >= EnemyShootSpeed) {
    3.             ShootTimer = 0f;
    4.             photonView.RPC ("RPC_Shoot", PhotonTargets.All, null);
    5.         } else {
    6.             ShootTimer += Time.deltaTime;
    7.         }
    8.     }
    9.  
    10.     [PunRPC]
    11.     void RPC_Shoot() {
    12.         Instantiate (
    13.             Resources.Load ("Enemies/"+BulletPrefab),
    14.             this.transform.position,
    15.             this.transform.rotation
    16.         );
    17.     }
    The idea was to instantiate the bullet locally instead assign it a photon view ..
    Can someone help me?

    Thanks in advance
     
  2. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    Is the enemy AI based? Your issue probably happens because you didn't add IsMine check to the enemy.
     
  3. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    First thanks for the reply.

    Yes it is.

    I tried a switch like this:

    Code (CSharp):
    1. if (photonView.isMine) {
    2.             if (ShootTimer >= EnemyShootSpeed) {
    3.                 ShootTimer = 0f;
    4.                 photonView.RPC ("RPC_Shoot", PhotonTargets.All, null);
    5.             } else {
    6.                 ShootTimer += Time.deltaTime;
    7.             }
    8.         }
    but that way the enemy was not firing at all...
     
  4. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    Get the photon view of the enemy with GetComponent. You are probably not using enemys view.
     
  5. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Hi Kamil,

    thanks for the tip. Now my code is this:

    Code (CSharp):
    1.     void EnemyShoot() {
    2.         if (GetComponent<PhotonView>().isMine) {
    3.             if (ShootTimer >= EnemyShootSpeed) {
    4.                 ShootTimer = 0f;
    5.                 photonView.RPC ("RPC_Shoot", PhotonTargets.All, null);
    6.             } else {
    7.                 ShootTimer += Time.deltaTime;
    8.             }
    9.         }
    10.     }
    but still no luck. Enemy does not shoot.

    I also tried to run the control in the RPC function, instead of outside. But the behavior remains the same.
     
  6. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    Line 5. Try with component photonview instead of the global Photon.Monobehavior
     
  7. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Hi Kamil,
    thank you very much for your help.

    Here is the code with the modified line 5:

    Code (CSharp):
    1.     void EnemyShoot() {
    2.         if (GetComponent<PhotonView>().isMine) {
    3.             if (ShootTimer >= EnemyShootSpeed) {
    4.                 ShootTimer = 0f;
    5.                 // photonView.RPC ("RPC_Shoot", PhotonTargets.All, null);
    6.                 GetComponent<PhotonView> ().RPC ("RPC_Shoot", PhotonTargets.All, null);
    7.             } else {
    8.                 ShootTimer += Time.deltaTime;
    9.             }
    10.         }
    11.     }
    The behavior remains the same :(

    Some additional information that I hope will be helpful:

    the "EnemyShoot ()" function is included in the "EnemyBaseController ()" script assigned to the enemy.

    The enemy is instantiated by an external script (EnemySpawnController) using the following code:

    Code (CSharp):
    1.         enemySpawned = PhotonNetwork.Instantiate (
    2.             prefab,
    3.             spawnpoint.position,
    4.             spawnpoint.rotation,
    5.             0
    6.         );
     
  8. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    Who is the owner of the enemy, any player or the scene? If it shouldn't be owned by a player then instantiate it manually with scene view rpc. I just did read your first post again and you said "The problem is that the enemy instantiates a bullet for each player present in the room"
    When I look at your code again, you actually send it to all clients so the enemy actually instantiates a bullet for each player in the room. That's how bullet sync works. I don't get your case here.
     
  9. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10

    All right.

    At this point I am afraid of having provided insufficient data on the structure of the game.

    1) I have a dedicated client that acts as a "game server".
    2) I control the logic of the server by checking if "IsMasterClient" in the controller of the scene.
    3) Enemies are instantiated from MasterClient.

    This works very well: players can shoot enemies and kill them; enemies attack players as expected.
    However, when (enemies) firing, the projectile is multiplied by the number of players in the room.
     
  10. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    Oh okey now I got you. Where is the enemy shot being called, any code to show? It looks like it's called multiple times by unknown objects, so far. I would debug this and check which viewID or player ID calls the RPC. Add the "PhotonMessageInfo" struct as parameter to your RPC head and debug the whole thing. It contains info about the sender of the RPC.
     
  11. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Hi Kamil,
    sure.


    The "EnemyShoot ()" function is called by the "AttackPlayer ()" function:

    Code (CSharp):
    1.  
    2. void AttackPlayer () {
    3.     // exit if I have no target
    4.     if (myTarget == null) {
    5.         return;
    6.     }
    7.     // look at player
    8.     transform.LookAt (myTarget.transform.position);
    9.     // get enemy distance from player
    10.     DistanceFromPlayer = Vector3.Distance (transform.position, myTarget.transform.position);
    11.     // if enemy is near enough and can see player than shoot
    12.     if (EnemyShootRange >= DistanceFromPlayer && CanSeePlayer()) {
    13.         EnemyShoot ();
    14.     } else {
    15.         // approach the player
    16.         transform.position = Vector3.MoveTowards (
    17.             this.transform.position,
    18.             myTarget.transform.position,
    19.             EnemySpeed * Time.deltaTime
    20.         );
    21.     }
    22. }
    23.  
    Both functions are within the "EnemyBaseController" script, attached to the enemy prefab.

    To be sure that the script is run only by MasterClient I have this control in the "Update ()" function:

    Code (CSharp):
    1.  
    2. void Update () {
    3.     if (PhotonNetwork.isMasterClient)
    4.         return;
    5.     // other stuffs here
    6. }
    7.  

    Here is the current code.
    I went back to the initial code (and the initial problem) and added "PhotonMessageInfo" to the debugging information.
    I also commented out the statement "if (GetComponent <PhotonView> (). IsMine)".

    Code (CSharp):
    1.  
    2. void EnemyShoot() {
    3.     //if (GetComponent<PhotonView>().isMine) {
    4.     if (ShootTimer >= EnemyShootSpeed) {
    5.         ShootTimer = 0f;
    6.         photonView.RPC ("RPC_Shoot", PhotonTargets.All, null);
    7.         //GetComponent<PhotonView> ().RPC ("RPC_Shoot", PhotonTargets.All, null);
    8.     } else {
    9.         ShootTimer += Time.deltaTime;
    10.     }
    11.     //}
    12. }
    13.  
    14. [PunRPC]
    15. void RPC_Shoot(PhotonMessageInfo info) {
    16.     Debug.Log ("RPC_Shoot PhotonMessageInfo: " + info);
    17.     Instantiate (
    18.         Resources.Load ("Enemies/" + BulletPrefab),
    19.         this.transform.position,
    20.         this.transform.rotation
    21.     );
    22. }
    23.  
    I did some tests using a MasterClient and two clients.

    both client and MasterClient show these lines in the log when enemy shoots:

    RPC_Shoot PhotonMessageInfo: [PhotonMessageInfo: Sender=''player_1' ' Senttime=2828571.156]
    RPC_Shoot PhotonMessageInfo: [PhotonMessageInfo: Sender=''player_2' ' Senttime=2828571.545]

    Thanks again for your help :)
     
  12. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Sorry, I meant: "to make sure that runs only on clients".
     
  13. Kamil-Says

    Kamil-Says

    Joined:
    Jun 30, 2014
    Posts:
    151
    So I was right, your debug says there are 2 senders but only the enemy is allowed to send this.
    After instantiate, can you look at the enemy PhotonView in inspector and check who the owner is? It should have no real owner (should be owned by the scene) since it's AI based.
     
  14. skattigat

    skattigat

    Joined:
    Mar 13, 2013
    Posts:
    10
    Yes, you was right, I got a sender for each logged player.

    I did some tests: the possessor of the enemy is always the local player (player_1 or player_2 based on how the login was performed).

    Also I see the option "Controlled locally: (master)" active.

    Perhaps the problem is in the way in which the enemy is instantiated. I'm using the following code into a script attached to a scene gameobject.

    Code (CSharp):
    1. void SpawnEnemy () {
    2.     if (!PhotonNetwork.inRoom || !PhotonNetwork.isMasterClient)
    3.         return;
    4.     this.transform.parent.GetComponent<EnemySpawnController> ().Spawn (          
    5.         myPrefabName,
    6.         this.transform
    7.     );
    8. }
    the code in the EnemySpawnController.Spawn() is:

    Code (CSharp):
    1. public void Spawn (string prefab, Transform spawnpoint) {
    2.     enemySpawned = PhotonNetwork.Instantiate (
    3.         prefab,
    4.         spawnpoint.position,
    5.         spawnpoint.rotation,
    6.         0
    7.     );
    8.     enemySpawned.transform.SetParent (spawnpoint);
    9.     enemySpawned.transform.position = spawnpoint.position;
    10.     enemySpawned.transform.rotation = spawnpoint.rotation;
    11. }
    Can you point me in the right direction ?
    Thanks in advance