Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 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 Mikhailzrick · Feb 10, 2021 at 12:50 AM · c#enemy spawn

Prevent spawning of enemies in same location

First time posting. I've been learning Unity over the last couple months and things are going good. Learning a lot. But I have run into a roadblock and I'd like to ask for help.


I've got a game where enemies are separated into 2 categories(stationary, and mobile), and spawn between preset spawn points of the same categories. I've used the Brackeys spawn wave tutorial as a base and have edited it to allow waves to select enemies at random, and an if else to determine if it spawns at a stationary or mobile spawn point. Problem is enemies tend to spawn at the same location overlapping onto themselves during a wave which is undesirable.


I think I need a list, and when a spawn point is selected at random it's then stored in a list to then be excluded in future spawn points? Then at the beginning of a new wave delete the stored entries in the list. Rinse, repeat.


I am not entirely sure how to go about this however. Any help welcome. Thanks!


==EDIT== I got busy and was working on other stuff but I did come back to this and it was a lot easier than I originally thought. I just used a checksphere and with a few lines of code it works so much better than any kind of convoluted list.


if (Physics.CheckSphere(s_Spawn.position, 1f, hittableLayers)) { Debug.Log("Can't spawn here"); return; } else { Debug.Log("Spawning enemy: " + stationaryEnemies[randomEnemy].name); Instantiate(stationaryEnemies[randomEnemy], s_Spawn.position, s_Spawn.rotation); }

 using System.Collections;
 using UnityEngine;
 
 public class WaveController : MonoBehaviour
 {
     public enum SpawnState { SPAWNING, WAITING, COUNTING};
 
     [System.Serializable]
     public class Wave
     {
         public string name;
         public int count;
         public float rate;
     }
 
     public GameObject[] mobileEnemies;
     public GameObject[] stationaryEnemies;
 
     public Wave[] waves;
     private int nextWave = 0;
 
     public Transform[] mobileSpawnPoints;
     public Transform[] stationarySpawnPoints;
 
     //private List<int> mobilePreviousSpawnPoint;
     //private List<int> stationaryPreviousSpawnPoint;
 
     public float timeBetweenWaves = 5f;
     private float waveCountdown;
 
     private float searchCountDown = 1f;
 
     private SpawnState state = SpawnState.COUNTING;
 
     void Start()
     {
         waveCountdown = timeBetweenWaves;
     }
 
     void Update()
     {
         if(state == SpawnState.WAITING)
         {
             if (!EnemyIsAlive())
             {
                 WaveCompleted();
             }
             else
             {
                 return;
             }
         }
         
         if (waveCountdown <= 0)
         {
             if (state != SpawnState.SPAWNING)
             {
                 StartCoroutine(SpawnWave(waves[nextWave]));
             }
         }
         else
         {
             waveCountdown -= Time.deltaTime;
         }
 
         void WaveCompleted()
         {
             Debug.Log("Wave Completed!");
 
             state = SpawnState.COUNTING;
             waveCountdown = timeBetweenWaves;
 
             if(nextWave + 1 > waves.Length - 1)
             {
                 nextWave = 0;
                 Debug.Log("All waves complete! Looping...");
             }
             else
             {
                 nextWave++;
             }
             
         }
 
         bool EnemyIsAlive()
         {
             searchCountDown -= Time.deltaTime;
             if(searchCountDown <= 0f)
             {
                 searchCountDown = 1f;
                 if (GameObject.FindGameObjectWithTag("Enemy") == null)
                 {
                     return false;
                 }
             }
            
             return true;
         }
     }
 
     IEnumerator SpawnWave(Wave _wave)
     {
         Debug.Log("Spawning Wave: " + _wave.name);
         state = SpawnState.SPAWNING;
 
         for (int i = 0; i < _wave.count; i++)
         {
             int randomEnemySelect = Random.Range(0, 10);
 
             if (randomEnemySelect >= 5)
             {
                 SpawnMobileEnemy();
                 
             }
             else
             {
                 SpawnStationaryEnemy();
                 
             }
            
             yield return new WaitForSeconds(1f / _wave.rate);
         }
 
         state = SpawnState.WAITING;
         yield break;
     }
 
     void SpawnMobileEnemy()
     {
         int randomEnemy = Random.Range(0, mobileEnemies.Length);
         Transform m_Spawn = mobileSpawnPoints[Random.Range(0, mobileSpawnPoints.Length)];
         Debug.Log("Spawning enemy: " + mobileEnemies[randomEnemy].name);
         Instantiate(mobileEnemies[randomEnemy], m_Spawn.position, m_Spawn.rotation);       
     }
 
     void SpawnStationaryEnemy()
     {
         int randomEnemy = Random.Range(0, stationaryEnemies.Length);
         Transform s_Spawn = stationarySpawnPoints[Random.Range(0, stationarySpawnPoints.Length)];
         Debug.Log("Spawning enemy: " + stationaryEnemies[randomEnemy].name);
         Instantiate(stationaryEnemies[randomEnemy], s_Spawn.position, s_Spawn.rotation);
     }
 }
 



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

2 Replies

· Add your reply
  • Sort: 
avatar image
0

Answer by Mikhailzrick · Feb 11, 2021 at 09:56 AM

Well, I figured it out on my own. Maybe there is a more efficient way of doing it but it works.


I went with my initial thought of creating a list, and in my case 2 lists. One for mobile spawn points and another for stationary spawn points. Then when either SpawnMobileEnemy or SpawnStationaryEnemy is called I generate a random int value from 0 to the length of the lists. Then take that number and check if the list already contains it. If so I return to run it again, else I add the value to the list and use the value to determine the place in the transform array.


Then when WaveCompleted is called I clear both lists before the next wave. The only issue I see is if I try to spawn more enemies than spawn points are available. I could probably write something to check for that but for now I'll just make sure I don't try to spawn more enemies than there are spawn points.


Here's the code if anyone wants to take a gander.

     using System.Collections;
     using System.Collections.Generic;
     using UnityEngine;
     
     public class WaveController : MonoBehaviour
     {
         public enum SpawnState { SPAWNING, WAITING, COUNTING};
     
         [System.Serializable]
         public class Wave
         {
             public string name;
             public int count;
             public float rate;
         }
     
         public GameObject[] mobileEnemies;
         public GameObject[] stationaryEnemies;
     
         public Wave[] waves;
         private int nextWave = 0;
     
         public Transform[] mobileSpawnPoints;
         public Transform[] stationarySpawnPoints;
   
         public float timeBetweenWaves = 5f;
         private float waveCountdown;
     
         private float searchCountDown = 1f;
     
         public List<int> mobileSpawnLocations;
         public List<int> stationarySpawnLocations;
     
         private SpawnState state = SpawnState.COUNTING;
     
         void Start()
         {
             waveCountdown = timeBetweenWaves;
             mobileSpawnLocations = new List<int>();
             stationarySpawnLocations = new List<int>();
         }
     
         void Update()
         {
             if(state == SpawnState.WAITING)
             {
                 if (!EnemyIsAlive())
                 {
                     WaveCompleted();
                 }
                 else
                 {
                     return;
                 }
             }
             
             if (waveCountdown <= 0)
             {
                 if (state != SpawnState.SPAWNING)
                 {
                     StartCoroutine(SpawnWave(waves[nextWave]));
                 }
             }
             else
             {
                 waveCountdown -= Time.deltaTime;
             }
     
             void WaveCompleted()
             {
                 Debug.Log("Wave Completed!");
                 mobileSpawnLocations.Clear();
                 stationarySpawnLocations.Clear();
                 Debug.Log("Lists cleared for next wave");
     
                 state = SpawnState.COUNTING;
                 waveCountdown = timeBetweenWaves;
     
                 if(nextWave + 1 > waves.Length - 1)
                 {
                     nextWave = 0;
                     Debug.Log("All waves complete! Looping...");
                 }
                 else
                 {
                     nextWave++;
                 }
                 
             }
     
             bool EnemyIsAlive()
             {
                 searchCountDown -= Time.deltaTime;
                 if(searchCountDown <= 0f)
                 {
                     searchCountDown = 1f;
                     if (GameObject.FindGameObjectWithTag("Enemy") == null)
                     {
                         return false;
                     }
                 }
                
                 return true;
             }
         }
     
         IEnumerator SpawnWave(Wave _wave)
         {
             Debug.Log("Spawning Wave: " + _wave.name);
             state = SpawnState.SPAWNING;
     
             for (int i = 0; i < _wave.count; i++)
             {
                 int randomEnemySelect = Random.Range(0, 10);
     
                 if (randomEnemySelect >= 5)
                 {
                     SpawnMobileEnemy();
                     
                 }
                 else
                 {
                     SpawnStationaryEnemy();
                     
                 }
                
                 yield return new WaitForSeconds(1f / _wave.rate);
             }
     
             state = SpawnState.WAITING;
             yield break;
         }
     
         void SpawnMobileEnemy()
         {
             int randomEnemy = Random.Range(0, mobileEnemies.Length);
             int randomMobileLocation = Random.Range(0, mobileSpawnPoints.Length);
             if (mobileSpawnLocations.Contains(randomMobileLocation))
             {
                 return;
             }
             else
             {
                 mobileSpawnLocations.Add(randomMobileLocation);
             }
             
             Transform m_Spawn = mobileSpawnPoints[randomMobileLocation];
             Debug.Log("Spawning enemy: " + mobileEnemies[randomEnemy].name);
             Instantiate(mobileEnemies[randomEnemy], m_Spawn.position, m_Spawn.rotation);       
         }
     
         void SpawnStationaryEnemy()
         {
             int randomEnemy = Random.Range(0, stationaryEnemies.Length);
             int randomStationaryLocation = Random.Range(0, stationarySpawnPoints.Length);
             if (stationarySpawnLocations.Contains(randomStationaryLocation))
             {
                 return;
             }
             else
             {
                 stationarySpawnLocations.Add(randomStationaryLocation);
             }
             
             Transform s_Spawn = stationarySpawnPoints[randomStationaryLocation]; 
             Debug.Log("Spawning enemy: " + stationaryEnemies[randomEnemy].name);
             Instantiate(stationaryEnemies[randomEnemy], s_Spawn.position, s_Spawn.rotation);
         }
     }
 
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 AbandonedCrypt · Feb 11, 2021 at 10:39 AM

Your solution works, but is wonky and extremely difficult in regards to scalability. Imagine you want to create a bunch of new enemy types, now you will have to cross-iterate through lists over lists of values, because you don't want enemy A spawning at a position where enemy B is already.

A somewhat more elegant solution would be to cast a ray or sphere to determine if the spawning space is occupied, or have a single list of occupied spawning spaces to check against. The issue with keeping a list of occupied spawning spaces is that moving enemies could always be spawned on, since their positin is not stored in the list.

Comment
Add comment · Show 1 · 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 Mikhailzrick · Feb 11, 2021 at 11:23 AM 0
Share

I don't disagree it's a bit wonky as you say. I hadn't thought of a raycast. Do you mean have the gameobject that I use for the spawn points cast rays and if it detects something(an enemy), exclude that spawn point from the available spawn points?

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

690 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 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 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 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 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 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 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

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

how to make enemy clone work independently? 1 Answer

Enemy Spawner help 1 Answer

Making a bubble level (not a game but work tool) 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