Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by OnEd0t · Jul 14, 2019 at 06:59 AM · counter

making a left enemies counter,count the number of enemies

Hi, I am working on a FPS game where enemies spawn in waves, and i want to make a counter for the number of enemies left to kill in the scene, and i do it by creating a var then finding the GameObjects with tag "Enemy" and adding it to the list or (var), but the problem with that is the length of the list wont update if i kill one of them, or is there a better way of doing the counter.

Here is the enemy script:

using UnityEngine; using UnityEngine.AI; using System.Collections;

public class EnemyController : MonoBehaviour {

 Transform target;
 NavMeshAgent agent;

 void Start()
 {
     target = PlayerManager.instance.Player.transform;
     agent = GetComponent<NavMeshAgent>();
     
 }
 
 void Update()
 {
     targetPlayer();
 }

 void targetPlayer()
 {
         agent.SetDestination(target.position);
 }

and i know that this wave spawner script is way too long but i dont know what parts are the important for you, sooo.......

here it is:

using UnityEngine; using System.Collections; using UnityEngine.UI; using System; using System.Collections.Generic;

public class WaveSpawner : MonoBehaviour {

 //public GameObject spawningNextWavePanel;
 //public Text spawningNextWaveText;

 public GameObject waveCompletedPanel;
 public Text waveCompletedText;

 public enum SpawnState { SPAWNING, WAITING, COUNTING };

 [System.Serializable]
 public class Wave
 {
     public string name;
     public Transform enemy;
     public int count;
     public float rate;
     
 }
 
 public Wave[] waves;
 private int nextWave = 0;
 public int NextWave
 {
     get { return nextWave + 1; }
 }
 


 public Transform[] spawnPoints;

 public float timeBetweenWaves = 5f;
 public float waveCountdown;
 public float WaveCountdown
 {
     get { return waveCountdown; }
 }

 private float searchCountdown = 1f;

 private SpawnState state = SpawnState.COUNTING;
 public SpawnState State
 {
     get { return state; }
 }
 

 void Start()
 {
     if (spawnPoints.Length == 0)
     {
         Debug.LogError("No spawn points referenced.");
     }

     waveCountdown = timeBetweenWaves;
 }

 void Update()
 {
     //var enemies = GameObject.FindGameObjectsWithTag("Enemy");
     //var enemiesCount = enemies.Length;
     //Debug.Log(enemiesCount);


     if (state == SpawnState.WAITING)
     {
         if (!EnemyIsAlive())
         {
             WaveCompleted(waves[NextWave - 1]);

         }
         else
         {
             return;
         }
     }

     if (waveCountdown <= 0)
     {
         if (state != SpawnState.SPAWNING)
         {
             StartCoroutine( SpawnWave ( waves[nextWave] ) );
         }
     }
     else
     {
         waveCountdown -= Time.deltaTime;
     }
     
 }

 

 void WaveCompleted(Wave myWave)
 {
     Debug.Log("Wave Completed!");

     waveCompletedPanel.SetActive(true);

     waveCompletedText.text = myWave.name + " Completed";

     StartCoroutine("waitForText");

     state = SpawnState.COUNTING;
     waveCountdown = timeBetweenWaves;

     if (nextWave + 1 > waves.Length - 1)
     {
         nextWave = 0;
         Debug.Log("ALL WAVES COMPLETE! Looping...");


     }
     else
     {
         nextWave++;
     }
 }
 IEnumerator waitForText()
 {
     yield return new WaitForSeconds(2);
     waveCompletedPanel.SetActive(false);
 }

 private string GetName()
 {
     return name;
 }

 bool EnemyIsAlive()
 {
     searchCountdown -= Time.deltaTime;
     if (searchCountdown <= 0f)
     {
         searchCountdown = 1f;
         if (GameObject.FindGameObjectWithTag("Enemy") == null)
         {
             return false;
         }
     }
     return true;
 }

 IEnumerator SpawnWave(Wave _wave)
 {
     //spawningNextWavePanel.SetActive(true);
     //spawningNextWaveText = "Spawning " + _wave.name + " in " + waveCountdown;
     Debug.Log("Spawning Wave: " + _wave.name);
     state = SpawnState.SPAWNING;

     for (int i = 0; i < _wave.count; i++)
     {
         SpawnEnemy(_wave.enemy);
         yield return new WaitForSeconds( 1f/_wave.rate );
     }

     state = SpawnState.WAITING;

     yield break;
 }

 void SpawnEnemy(Transform _enemy)
 {
     Debug.Log("Spawning Enemy: " + _enemy.name);

     Transform _sp = spawnPoints[UnityEngine.Random.Range (0, spawnPoints.Length) ];
     Instantiate(_enemy, _sp.position, _sp.rotation);
 }

}

hope you can help since i tried to modify it my self and failed

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
3
Best Answer

Answer by Hellium · Jul 14, 2019 at 07:05 AM

OnDestroyEventSender.cs

 using UnityEngine;
 
 public class OnDestroyEventSender : MonoBehaviour
 {
     public event System.Action<OnDestroyEventSender> OnDestroyed;
 
     private void OnDestroy()
     {
         if ( OnDestroyed != null )
             OnDestroyed( this );
     }
 }


Wave.cs

 using UnityEngine;
 using System.Collections.Generic;

 [System.Serializable]
 public class Wave
 {
     /// <summary>
     /// Event invoked when the wave has been cleared
     /// </summary>
     public event System.Action<Wave> OnCleared;

     /// <summary>
     /// Event invoked when an enemy of the wave has been spawned
     /// </summary>
     public event System.Action<Wave, Transform> OnEnemySpawned;

     /// <summary>
     /// Event invoked when an enemy of the wave has been killed
     /// </summary>
     public event System.Action<Wave, Transform> OnEnemyKilled;

     [SerializeField]
     private string name;

     [SerializeField]
     private Transform enemyPrefab;

     [SerializeField, Range(1, 100)]
     private int count;

     [SerializeField, Range(0.01f, 1f)]
     private float rate;

     private List<OnDestroyEventSender> enemies;

     public bool IsCleared
     {
         get { return enemies != null && enemies.Count == 0; }
     }

     public string Name
     {
         get { return name; }
     }

     public int Count
     {
         get { return count; }
     }

     public float Rate
     {
         get { return rate; }
     }

     public int RemainingEnemiesToInstantiate
     {
         get; private set;
     }

     public int RemainingEnemiesAlive
     {
         get { return enemies.Count; }
     }

     /// <summary>
     /// Resets the wave
     /// </summary>
     public void Reset()
     {
         RemainingEnemiesToInstantiate = count;
     }

     /// <summary>
     /// Instantiate an enemy at the given position and rotation
     /// </summary>
     public void InstantiateEnemy( Vector3 position, Quaternion rotation )
     {
         if ( RemainingEnemiesToInstantiate == 0 )
             throw new System.InvalidOperationException( "No remaining enemy to instantiate. Have you called `Reset`?" );

         if ( enemies == null ) enemies = new List<OnDestroyEventSender>( count );

         Transform enemy = Object.Instantiate( enemyPrefab, position, rotation );
         OnDestroyEventSender onDestroyEventDispatcher = enemy.gameObject.AddComponent<OnDestroyEventSender>();
         onDestroyEventDispatcher.OnDestroyed += OnEnemyDestroyed;
         enemies.Add( onDestroyEventDispatcher );
         RemainingEnemiesToInstantiate--;

         if ( OnEnemySpawned != null )
             OnEnemySpawned( this, enemy );
     }

     /// <summary>
     /// Called when an enemy has been destroyed
     /// </summary>
     private void OnEnemyDestroyed( OnDestroyEventSender destroyedEnemy )
     {
         destroyedEnemy.OnDestroyed -= OnEnemyDestroyed;
         enemies.Remove( destroyedEnemy );

         if ( OnEnemyKilled != null )
             OnEnemyKilled( this, destroyedEnemy.transform );

         if ( RemainingEnemiesToInstantiate == 0 && enemies.Count == 0 && OnCleared != null )
             OnCleared( this );
     }
 }

WaveSpawner.cs

 using System.Collections;
 using UnityEngine;
 using UnityEngine.UI;

 public class WaveSpawner : MonoBehaviour
 {
     [Header("===== Waves ===== ")]
     public GameObject waveCompletedPanel;
     public Text waveCompletedText;
     public Text waveEnemiesCountText;
     public Wave[] waves;
     public float timeBetweenWaves = 5f;
     public bool loopWaves = false;

     private int currentWaveIndex = -1;
     private float waveCountdown;
     private bool spawningWave;

     [Header("===== Spawn points ===== ")]

     public Transform[] spawnPoints;

     /// <summary>
     /// Gets the current wave
     /// </summary>
     private Wave CurrentWave
     {
         get
         {
             return currentWaveIndex >= 0 && currentWaveIndex < waves.Length
                 ? waves[currentWaveIndex]
                 : null;
         }
     }

     /// <summary>
     /// Indicates whether the last wave has been cleared (if waves don't loop)
     /// </summary>
     private bool ClearedLastWave
     {
         get { return !loopWaves && currentWaveIndex == waves.Length - 1 && CurrentWave.IsCleared; }
     }

     void Start()
     {
         if ( spawnPoints.Length == 0 )
             Debug.LogError( "No spawn points referenced." );

         waveCountdown = timeBetweenWaves;
     }

     void Update()
     {
         waveCountdown -= Time.deltaTime;
         if ( spawningWave )
         {
             if ( waveCountdown <= 0 && CurrentWave != null && CurrentWave.RemainingEnemiesToInstantiate > 0 )
             {
                 Transform spawnPoint = spawnPoints[UnityEngine.Random.Range (0, spawnPoints.Length) ];
                 CurrentWave.InstantiateEnemy( spawnPoint.position, spawnPoint.rotation );
                 waveCountdown = 1 / CurrentWave.Rate;
             }
         }
         else if ( waveCountdown <= 0 )
         {
             StartNextWave();
         }
     }

     /// <summary>
     /// Starts the next wave
     /// </summary>
     private void StartNextWave()
     {
         Debug.Log( "Starting next wave!" );
         spawningWave = true;
         if ( CurrentWave != null )
         {
             CurrentWave.OnCleared      -= OnWaveCleared;
             CurrentWave.OnEnemySpawned -= OnEnemySpawned;
             CurrentWave.OnEnemyKilled  -= OnEnemyKilled;
         }
         if ( !ClearedLastWave )
         {
             currentWaveIndex = ( currentWaveIndex + 1 ) % waves.Length;
             CurrentWave.Reset();
             CurrentWave.OnCleared      += OnWaveCleared;
             CurrentWave.OnEnemySpawned += OnEnemySpawned;
             CurrentWave.OnEnemyKilled  += OnEnemyKilled;
         }
     }

     /// <summary>
     /// Called when the given wave has been cleared (all the instantiated enemies have been destroyed)
     /// </summary>
     private void OnWaveCleared( Wave wave )
     {
         if ( ClearedLastWave )
         {
             Debug.Log( "You have cleared the last wave, congratulations!" );
         }
         else
         {
             Debug.Log( "Wave Completed! Next one starting in " + timeBetweenWaves + " seconds" );
         }

         waveCountdown = timeBetweenWaves;
         spawningWave = false;

         waveCompletedPanel.SetActive( true );
         waveCompletedText.text = wave.Name + " Completed";
         StartCoroutine( HideWavePanel( 2 ) );
     }

     private void OnEnemySpawned( Wave wave, Transform spawnedEnemy )
     {
         waveEnemiesCountText.text = string.Format( "{0} / {1}", wave.RemainingEnemiesAlive, wave.Count );
     }

     private void OnEnemyKilled( Wave wave, Transform killedEnemy )
     {
         waveEnemiesCountText.text = string.Format( "{0} / {1}", wave.RemainingEnemiesAlive, wave.Count );
     }

     /// <summary>
     /// Hides the wave panel after the given delay
     /// </summary>
     private IEnumerator HideWavePanel( float delay )
     {
         yield return new WaitForSeconds( delay );
         waveCompletedPanel.SetActive( false );
     }
 }



Original answer

 // Enemy script
 
 public event System.Action OnDestroyed;
 
 private void OnDestroy()
 {
     if( OnDestroyed != null )
          OnDestroy();
 }


 // Spawner script
 
 // Top of the file
 using System.Collections.Generic;
 
 // ....
 
 private List<Enemy> enemies = new List<Enemy>();
 
 private void SpawnWave()
 {
     // ...
     Enemy enemy = Instantiate( enemyPrefab ).GetComponent<Enemy>() ;
     enemies.Add( enemy ) ;
     enemy.OnDestroyed += () => OnEnemyDestroyed( enemy );
 }
 
 private void OnEnemyDestroyed( Enemy enemy )
 {
     enemies.Remove( enemy ) ;
     Debug.Log( "An enemy has been destroyed. " + enemies.Count + " left");
 }
Comment
Add comment · Show 13 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Hellium · Jul 14, 2019 at 04:51 PM 0
Share

@OnEd0t I've reworked your Wave and WaveSpawner script, and extracted Wave to its own file for better clarity.

Feel free to ask questions if you don't understand everything.

avatar image OnEd0t Hellium · Jul 15, 2019 at 08:47 AM 0
Share

Duoooode!....YOU ARE Such A Legend! thank you so much for the help, honstly didnt expect help as much as you gave me. thank you just thank you

but i have a couple of questions

1- now i have to fill my hierarchy with waves and refrence them in the waveSpawner script in the Waves class, right?

2-after all of this work you still havent told me how to make the counter for the enemies

anything i do for you to return this favor, but dont ask for points i have non, this is my first time asking on this website, again thank you

avatar image Hellium OnEd0t · Jul 15, 2019 at 08:52 AM 0
Share
  1. Yes, you have to fill the information in the inspector of the WaveSpawner component. Wasn't it like this before?

  2. Yes, I haven't added the real counter, I will edit my answer to give you a clear way to get it

Show more comments
avatar image
0

Answer by suman818 · Jul 14, 2019 at 08:30 AM

you need to update your list every time you kill an enemy. just run the forEach loop after each time you kill the enemy.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by Dawdlebird · Jul 14, 2019 at 08:56 AM

How about just having a public static int called "enemyCount" or something? You could put that on your Spawner script or a game manager script. Then when you instantiate enemies just up that variable (like "Spawner.enemyCount++" for example), and in your onDestroy function you add the line "Spawner.enemyCount--" This way each enemy is responsible for being accounted for themselves. This saves you the cpu overhead over finding gameobjects by tag or having to do forEach loops or anything of the sort. Also having a single integer is more memory friendly than tracking a dynamic list.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

110 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Run time counter 1 Answer

Only tagged objects raise counter 1 Answer

Making something happen only for one second during an Update function? 1 Answer

Creating an up and down counter 2 Answers

How to stop a countdown from counting down 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges