Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Instantiate problem - Double Trouble

Discussion in 'Scripting' started by Necktron, Mar 22, 2016.

  1. Necktron

    Necktron

    Joined:
    Feb 10, 2016
    Posts:
    20
    Hello!

    I made a function that destroy the player if the HP is equal to, or below zero. Later on, another script creates an Instantiated clone of the player. This worked all fine when I only had one death possible, fall outside of the map. This do so the player recive 999999999 damage if he is below a certain Y coordinate.

    Later I started to create hazards like spikes and such stuff, these are equipped with a hitbox with trigger property and a script that controlls if the player is inside the trigger. The player takes 5HP damage when he enters the hitbox, and keep on being damaged with 1HP for each Update() he's inside of the hitbox. It works kinda good, but there is a VERY anoying bug that I cant figure out how to solve.

    Sometimes, like when you are at very low HP and jump into the hitbox, the scripts create TWO players. These can then collide with eachother and exploit each others hitbox to constaintlly jump while being close to each other and jump straight to the end of the level.

    I've even tried to cut off any chance of another clone appearing by creating a function that counts the number of "Players" and is supposed to completley destroy one of the clones without activating the respawn function. Sad enough, this function wont do any good as the clones still multiply from time to time.

    Please help me fast!

    I got my three scripts responsible for "Basic game functions like kill and respawn", "Player Stats" and "Hostile Objects like spikes and such".

    Player Script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4.  
    5. public class Player : MonoBehaviour
    6. {
    7.     [System.Serializable]
    8.     public class PlayerStats
    9.     {
    10.         //Player HP
    11.         public int Health = 100;
    12.     }
    13.  
    14.     public PlayerStats playerStats = new PlayerStats();
    15.  
    16.     //Set's the limit of falling before he dies when outside of the map
    17.     public int fallBoundary = -5;
    18.  
    19.     //If the player falls off the map, he shall die
    20.     void Update()
    21.     {
    22.         if (transform.position.y <= fallBoundary)
    23.         {
    24.             DamagePlayer(99999999);
    25.         }
    26.     }
    27.  
    28.     //Deals damage to the player and kills him if he is equal to, or below 0 HP
    29.     public void DamagePlayer (int damage)
    30.     {
    31.         playerStats.Health -= damage;
    32.  
    33.         if (playerStats.Health <= 0)
    34.         {
    35.             GameMaster.KillPlayer(this);
    36.         }
    37.     }
    38. }

    Game Master script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEngine.UI;
    5. using UnityEngine.SceneManagement;
    6.  
    7. public class GameMaster : MonoBehaviour
    8. {
    9.     public static GameMaster gm;
    10.     public int exsistingPlayers;
    11.     public Transform player;
    12.     public Text textObject;
    13.  
    14.     void Awake()
    15.     {
    16.         //Set's the GameMaster
    17.         if (gm == null)
    18.         {
    19.             gm = GameObject.FindGameObjectWithTag("GM").GetComponent<GameMaster>();
    20.         }
    21.     }
    22.  
    23.     //Player stats for respawn
    24.     public Transform playerPrefab;
    25.     public Transform spawnPoint;
    26.     public int spawnDelay;
    27.  
    28.     //All sounds in the game is handled by the GameMaster, witch sends the requested sound to the GameObject that is calling for it upon playFunction
    29.     public string spawnSound;
    30.  
    31.     //Cache
    32.     private AudioManager audioManager;
    33.  
    34.     void Start()
    35.     {
    36.         //Caching
    37.         audioManager = AudioManager.instance;
    38.         if (audioManager == null)
    39.         {
    40.             Debug.LogError("No AudioManager found in the scene.");
    41.         }
    42.     }
    43.  
    44.     void Update()
    45.     {
    46.         exsistingPlayers = GameObject.FindGameObjectsWithTag("Player").Length;
    47.  
    48.         if(player == null)
    49.         {
    50.             player = GameObject.Find("Player(Clone)").transform;
    51.         }
    52.     }
    53.  
    54.     //Starts a timer before the player can respawn, then respawns a clone of the player at a certain spawnlocation or checkpoint
    55.     public IEnumerator RespawnPlayer()
    56.     {
    57.         yield return new WaitForSeconds(spawnDelay);
    58.  
    59.         {
    60.  
    61.             audioManager.PlaySound(spawnSound);
    62.             Instantiate(playerPrefab, spawnPoint.position, spawnPoint.rotation);
    63.  
    64.             if (exsistingPlayers > 1)
    65.             {
    66.                 Eliminate();
    67.             }
    68.         }
    69.     }
    70.  
    71.     //Destroys the player object and activates the respawn function
    72.     public static void KillPlayer (Player player)
    73.     {
    74.         Destroy (player.gameObject);
    75.         gm.StartCoroutine (gm.HPZero());
    76.         gm.StartCoroutine (gm.RespawnPlayer());
    77.     }
    78.  
    79.     public void Eliminate()
    80.     {
    81.         Destroy(GameObject.Find("Player(Clone)").transform);
    82.     }
    83.  
    84.     public IEnumerator HPZero()
    85.     {
    86.         yield return new WaitForSeconds(0f);
    87.         textObject.text = "HP: 0";
    88.     }
    89. }

    Hostile Objects script:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class HostileObject : MonoBehaviour
    5. {
    6.     public Transform player;
    7.  
    8.     void Update()
    9.     {
    10.         //Finds the player if he is gone / dead
    11.         if (player == null)
    12.         {
    13.             player = GameObject.Find("Player(Clone)").transform;
    14.         }
    15.     }
    16.  
    17.     //Damage player when he enters the Hostile Object's area
    18.     void OnTriggerEnter2D(Collider2D other)
    19.     {
    20.         if (other.gameObject.name == "Player")
    21.         {
    22.             player.gameObject.GetComponent<Player>().DamagePlayer(5);
    23.         }
    24.     }
    25.  
    26.     //Damage Over Time if the players stays inside the area
    27.     void OnTriggerStay2D(Collider2D other)
    28.     {
    29.         if (other.gameObject.tag == "Player")
    30.         {
    31.             player.gameObject.GetComponent<Player>().DamagePlayer(1);
    32.         }
    33.     }
    34. }
    If you have any tip aswell on how to improve the code, please let me know! Im thirsty for becoming a greater programmer!
     
  2. Teravisor

    Teravisor

    Joined:
    Dec 29, 2014
    Posts:
    654
    Error possibly happens because Destroy(...) is triggered at the end of frame; thus giving possibility of getting one more damage before player is destroyed, and because player already has HP<=0 it will instantiate player second time. Try either DestroyImmediate(...) or setting some bool flag on player so it won't instantiate anymore.

    Another solution (feels like workaround though) is to use Invoke("methodname",seconds) instead of Coroutines - you can't Invoke method with same name twice (it will replace it in queue).

    Stop using Find and FindObjectsWithTag. Especially in Update().
     
    Nigey likes this.
  3. Necktron

    Necktron

    Joined:
    Feb 10, 2016
    Posts:
    20
    Thank you! I made it work by using bools. Btw, any recommendation for other code instead of Find and FindObjectsWithTag?
     
  4. Teravisor

    Teravisor

    Joined:
    Dec 29, 2014
    Posts:
    654
    Keep a List or array of objects and access it. If you instantiate, you also Add to that List; if you Destroy, you also Remove from that List then loop through list when you need to do something with them.
    It's possible to set list initial values in editor if you need it.