Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 /
  • Help Room /
avatar image
0
Question by Internetman · May 25, 2016 at 07:07 PM · c#instantiatespawningspawning problemslooping

Spawn system that doesn't instantiated enemies on top of player or each other (C#)

Hello my fellow great Unites. I have an enemy spawn system that spawns out enemies using Ienumerator inside a set of borders. Now the only problem is that the enemies will sometimes spawn out on the player, or another object...

How can I fix this problem? Using a for loop? Any code example?

Here's the code:

  using UnityEngine;
      using System.Collections;
      using System.Collections.Generic;
      
      public class EnemySpawn : MonoBehaviour 
      {
          // EnemyPrefabs
          public GameObject EnemyBouncingPrefab;
          public GameObject EnemyGrowerPrefab;
          public GameObject EnemyMinePrefab;
      
          //Show where spawn is prefab
          public GameObject showEnemySpawn;
          public GameObject showEnemyFlyBySpawn;
          public GameObject showEnemyGrowerSpawn;
          public GameObject showEnemyMineSpawn;
      
      
          // Array of spawn points 
          public Transform[] spawnPointsEnemyFollow; 
          public Transform[] spawnPointsEnemyExplode;
          public Transform[] spawnPointsEnemyFlyBy;
          
          // Borders
          public Transform borderTop;
          public Transform borderBottom;
          public Transform borderLeft;
          public Transform borderRight;
          
      
          //Used to put active enemies in a list
          public static List<GameObject> activeEnemies;
      
          void Start () 
          {
              // Starts a coroutine function for spawning bouncing enemies and fly by enemy
              StartCoroutine(SpawnBouncingEnemy());
              StartCoroutine(SpawnGrowerEnemy());
              StartCoroutine(SpawnEnemyFlyBy());
              StartCoroutine(SpawnMineEnemy());
          }
      
          void Awake()
          {
              // Create the list
              activeEnemies = new List<GameObject>();
      
          }
          
          // Spawn a Bouncing enemy
          IEnumerator SpawnBouncingEnemy() 
          {
              //Wait 3 to 5 seconds when game starts to spawn a ball
              yield return new WaitForSeconds(Random.Range(1, 3));
      
              while(true)
              {
                  //Calls the function to set random position
                  Vector2 spawnPoint = RandomPointWithinBorders();
                  
                  // Show spawn location for one second
                  Object marker = Instantiate(showEnemySpawn, spawnPoint, Quaternion.identity);
                  yield return new WaitForSeconds(1);
                  Destroy(marker);
                  
                  // Spawn enemy
                  GameObject newEnemy = (GameObject) Instantiate(EnemyBouncingPrefab, spawnPoint, Quaternion.identity);
      
                  activeEnemies.Add(newEnemy);
      
                  yield return new WaitForSeconds(Random.Range(4, 6));
      
              }
              
          }    
      
          // Spawn a Grower enemy
          IEnumerator SpawnGrowerEnemy() 
          {
              //Wait 3 to 5 seconds when game starts to spawn a "grower"
              yield return new WaitForSeconds(Random.Range(20, 40));
              
              while(true)
              {
                  //Calls the function to set random position
                  Vector2 spawnPoint = RandomPointWithinBorders();
                  
                  // Show spawn location for one second
                  Object marker = Instantiate(showEnemyGrowerSpawn, spawnPoint, Quaternion.identity);
                  yield return new WaitForSeconds(1);
                  Destroy(marker);
                  
                  // Spawn enemy
                  GameObject newEnemy = (GameObject) Instantiate(EnemyGrowerPrefab, spawnPoint, Quaternion.identity);
                  
                  activeEnemies.Add(newEnemy);
                  
                  yield return new WaitForSeconds(Random.Range(20, 50));
                  
              }
              
          }
      
          // Spawn a Mine enemy
          IEnumerator SpawnMineEnemy() 
          {
              //Wait 40 to 60 seconds when game starts to spawn a "Mine_enemy"
              yield return new WaitForSeconds(Random.Range(45, 60));
              
              while(true)
              {
                  //Calls the function to set random position
                  Vector2 spawnPoint = RandomPointWithinBorders();
                  
                  // Show spawn location for one second
                  Object marker = Instantiate(showEnemyMineSpawn, spawnPoint, Quaternion.identity);
                  yield return new WaitForSeconds(2);
                  Destroy(marker);
                  
                  // Spawn enemy
                  GameObject newEnemy = (GameObject) Instantiate(EnemyMinePrefab, spawnPoint, Quaternion.identity);
                  
                  activeEnemies.Add(newEnemy);
                  
                  yield return new WaitForSeconds(Random.Range(50, 60));
                  
              }
              
          }
      
          public Vector2 RandomPointWithinBorders()
          {
              //Code that will spawn a bouncing ball and ShowSpawn at a random position inside the borders 
              Vector2 random = new Vector2();
              random.x = (int)Random.Range(borderLeft.position.x, borderRight.position.x);
              random.y = (int)Random.Range(borderBottom.position.y, borderTop.position.y);
              return random;
          }
      }
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
1
Best Answer

Answer by TBruce · May 25, 2016 at 08:12 PM

Try this modified version of your code. This will get a valid spawn point before the first Instantiate() because it is calculated in RandomPointWithinBorders().

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class EnemySpawn : MonoBehaviour 
 {
     // EnemyPrefabs
     public GameObject EnemyBouncingPrefab;
     public GameObject EnemyGrowerPrefab;
     public GameObject EnemyMinePrefab;
 
     //Show where spawn is prefab
     public GameObject showEnemySpawn;
     public GameObject showEnemyFlyBySpawn;
     public GameObject showEnemyGrowerSpawn;
     public GameObject showEnemyMineSpawn;
 
 
     // Array of spawn points 
     public Transform[] spawnPointsEnemyFollow; 
     public Transform[] spawnPointsEnemyExplode;
     public Transform[] spawnPointsEnemyFlyBy;
 
     // Borders
     public Transform borderTop;
     public Transform borderBottom;
     public Transform borderLeft;
     public Transform borderRight;
 
 
     //Used to put active enemies in a list
     public static List<GameObject> activeEnemies;
 
     public Transform player;   // player transform
     public float minDistance;  // minimum distance from spawnpoint to object
 
     void Start()
     {
         // if the player has not been set in the inspector log it
         if (player == null)
         {
             Debug.LogWarning("EnemySpawn.Start(): There is no player set in the inspector. Please set this.");
         }
 
         // if the player has been set in the inspector but the Tag is not set to "Player" log it
         if ((player != null) && (player.tag != "Player"))
         {
             Debug.LogWarning("EnemySpawn.Start(): The Player does not have its Tag set to 'Player'.");
         }
 
         // if the player has not been set in the inspector and can find by Tag set it
         if ((player == null) && (GameObject.FindGameObjectsWithTag("Player") != null))
         {
             Debug.LogWarning("EnemySpawn.Start(): Setting the missing player.");
             player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
         }
 
         // Starts a coroutine function for spawning bouncing enemies and fly by enemy
         StartCoroutine(SpawnBouncingEnemy());
         StartCoroutine(SpawnGrowerEnemy());
         // StartCoroutine(SpawnEnemyFlyBy());  // this does not exist yet
         StartCoroutine(SpawnMineEnemy());
     }
 
     void Awake()
     {
         // Create the list
         activeEnemies = new List<GameObject>();
     }
 
     // Spawn a Bouncing enemy
     IEnumerator SpawnBouncingEnemy() 
     {
         //Wait 3 to 5 seconds when game starts to spawn a ball
         yield return new WaitForSeconds(Random.Range(1, 3));
 
         while(true)
         {
             //Calls the function to set random position
             Vector3 spawnPoint = RandomPointWithinBorders();
 
             // Show spawn location for one second
             Object marker = Instantiate(showEnemySpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(1);
             Destroy(marker);
 
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyBouncingPrefab, spawnPoint, Quaternion.identity);
 
             activeEnemies.Add(newEnemy);
 
             yield return new WaitForSeconds(Random.Range(4, 6));
         }
     }    
 
     // Spawn a Grower enemy
     IEnumerator SpawnGrowerEnemy() 
     {
         //Wait 3 to 5 seconds when game starts to spawn a "grower"
         yield return new WaitForSeconds(Random.Range(20, 40));
 
         while(true)
         {
             //Calls the function to set random position
             Vector3 spawnPoint = RandomPointWithinBorders();
 
             // Show spawn location for one second
             Object marker = Instantiate(showEnemyGrowerSpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(1);
             Destroy(marker);
 
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyGrowerPrefab, spawnPoint, Quaternion.identity);
 
             activeEnemies.Add(newEnemy);
 
             yield return new WaitForSeconds(Random.Range(20, 50));
         }
     }
 
     // Spawn a Mine enemy
     IEnumerator SpawnMineEnemy() 
     {
         //Wait 40 to 60 seconds when game starts to spawn a "Mine_enemy"
         yield return new WaitForSeconds(Random.Range(45, 60));
 
         while(true)
         {
             //Calls the function to set random position
             Vector3 spawnPoint = RandomPointWithinBorders();
 
             // Show spawn location for one second
             Object marker = Instantiate(showEnemyMineSpawn, spawnPoint, Quaternion.identity);
             yield return new WaitForSeconds(2);
             Destroy(marker);
 
             // Spawn enemy
             GameObject newEnemy = (GameObject) Instantiate(EnemyMinePrefab, spawnPoint, Quaternion.identity);
 
             activeEnemies.Add(newEnemy);
 
             yield return new WaitForSeconds(Random.Range(50, 60));
         }
     }
 
     public Vector3 RandomPointWithinBorders()
     {
         bool done = false;
         Vector3 randomPosition = new Vector3();
     
         while (!done)
         {
             //Code that will spawn a bouncing ball and ShowSpawn at a random position inside the borders 
             randomPosition.x = (int)UnityEngine.Random.Range(borderLeft.position.x, borderRight.position.x);
             randomPosition.y = (int)UnityEngine.Random.Range(borderBottom.position.y, borderTop.position.y);
             randomPosition.z = 0;
 
             done = ((minDistance == 0) || ValidMinimumDistance(randomPosition));
         }
         return randomPosition;
     }
 
     bool ValidMinimumDistance(Vector3 enemyPosition)
     {
         bool isValid = true;
         minDistance = Mathf.Abs(minDistance);
     
         if (player != null)
         {
             isValid = (Vector3.Distance(player.position, enemyPosition) > minDistance);
         }
     
         if (isValid && (activeEnemies.Count > 0))
         {
             for (int i = 0; i < activeEnemies.Count; i++)
             {
                 if (Vector3.Distance(activeEnemies[i].transform.position, enemyPosition) < minDistance)
                 {
                     isValid = false;
                     break;
                 }
             }
         }
         return isValid;
     }
 }

You do not need the modified Start() as long as you set Player in the inspector.

Comment
Add comment · Show 6 · 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 Internetman · May 27, 2016 at 06:20 PM 0
Share

@$$anonymous$$avina Thank you so much for your brilliant code! But I just can't get around to it, the enemies still can spawn on the player, I wrote everything down just as you wrote but it still won't work, any idéas?

avatar image TBruce Internetman · May 27, 2016 at 07:11 PM 0
Share

Here is a modified version of Valid$$anonymous$$inimumDistance() with a couple of enhancements

 bool Valid$$anonymous$$inimumDistance(Vector3 enemyPosition)
 {
     bool isValid = true;
     $$anonymous$$Distance = $$anonymous$$athf.Abs($$anonymous$$Distance);
 
     if (player != null)
     {
         isValid = ($$anonymous$$athf.Abs(Vector3.Distance(player.position, enemyPosition)) > $$anonymous$$Distance);
     }
 
     if (isValid && (activeEnemies.Count > 0))
     {
         for (int i = 0; i < activeEnemies.Count; i++)
         {
             if ($$anonymous$$athf.Abs(Vector3.Distance(activeEnemies[i].transform.position, enemyPosition)) < $$anonymous$$Distance)
             {
                 isValid = false;
                 break;
             }
         }
     }
     return isValid;
 }

Try this first, and even though you probably have tried this already you can also try playing with the $$anonymous$$Distance value in the inspector with the modified code if necessary.

If you are still having issues here is a version of Valid$$anonymous$$inimumDistance() with debug statements (Depending on how many enemies you have there will be a lot. You might want to start by adding only a few at a time)

 bool Valid$$anonymous$$inimumDistance(Vector3 enemyPosition)
 {
     bool isValid = true;
     $$anonymous$$Distance = $$anonymous$$athf.Abs($$anonymous$$Distance);
     float dist;
 
     if (player != null)
     {
         dist = $$anonymous$$athf.Abs(Vector3.Distance(player.position, enemyPosition));
         isValid = (dist > $$anonymous$$Distance);
         Debug.Log("player.position = " + player.position + ", spawned position = " + enemyPosition + ", calculated distance = " + dist + ", isValid = " + (isValid ? "True" : False"));
     }
 
     if (isValid && (activeEnemies.Count > 0))
     {
         for (int i = 0; i < activeEnemies.Count; i++)
         {
             dist = $$anonymous$$athf.Abs(Vector3.Distance(activeEnemies[i].transform.position, enemyPosition));
             Debug.Log("activeEnemies[" + i + "].position = " + activeEnemies[i].transform.position + ", spawned position = " + enemyPosition + ", calculated distance = " + dist + ", isValid = " + (isValid ? "True" : False"));
             if (dist < $$anonymous$$Distance)
             {
                 isValid = false;
                 break;
             }
         }
     }
     Debug.Log("");
     return isValid;
 }

Also change this

 public static List<GameObject> activeEnemies;

to this

 public static List<GameObject> activeEnemies = new List<GameObject>();
avatar image Internetman TBruce · May 28, 2016 at 10:09 AM 0
Share

@$$anonymous$$avina Brilliant program$$anonymous$$g my friend! I got it to work, I can't believe I didn't notice the error beforehand, I had set the $$anonymous$$Distance to a too low number!

BUT I still have a little problem. :( I have another script for a power up that the player can use, this means that if the power up is activated the player can "kill" the enemies by colliding with them. For now I just simply use the Destroy function to delete the enemies and this is where the problem starts with the new spawn code. This is where the error happens:

 bool Valid$$anonymous$$inimumDistance(Vector3 enemyPosition)
     {
         bool isValid = true;
         $$anonymous$$Distance = $$anonymous$$athf.Abs($$anonymous$$Distance);
         
         if (player != null)
         {
             isValid = ($$anonymous$$athf.Abs(Vector3.Distance(player.position, enemyPosition)) > $$anonymous$$Distance);
         }
         
         if (isValid && (activeEnemies.Count > 0))
         {
             for (int i = 0; i < activeEnemies.Count; i++)
             {
                 **if ($$anonymous$$athf.Abs(Vector3.Distance(activeEnemies[i].transform.position, enemyPosition)) < $$anonymous$$Distance)** // HERE IS THE ERROR
                 {
                     isValid = false;
                     break;
                 }
             }
         }
         return isValid;

I get the usual message: "The object of type 'GameObject' has been destroyed but you are still trying to access it."

What could be the best way to fix this? Set the object to null?

Show more comments
avatar image TBruce Internetman · May 27, 2016 at 09:00 PM 0
Share

Also, here is a little test editor script that you can use which I have already tested and it works fine. You need to place it in your Editor folder. If you do not have one create one. It allows you to test without running the game. There will be a Spawn Enemty button in the inspector. Just press the button to spawn an enemy.

 using UnityEngine;
 using System;
 using UnityEditor;
 
 [CustomEditor(typeof(EnemySpawn))]
 [System.Serializable]
 public class EnemySpawnCustomEditor: Editor
 {
     public override void OnInspectorGUI()
     {
         var target_cs = (EnemySpawn)target;
         DrawDefaultInspector();
 
         EnemySpawn enemySpawnScript = target_cs;
 
         if(!Application.isPlaying)
         {
             if(GUILayout.Button("Spawn Enemy"))
             {
                 enemySpawnScript.DoSpawn$$anonymous$$ineEnemy();
             }
         }
     }
 }

$$anonymous$$ake sure that everything is set in EnemySpawn and your player is visible I found large numbers can hang you up after too many spawns.

avatar image Internetman TBruce · May 29, 2016 at 09:59 AM 0
Share

@$$anonymous$$avina This is genius, I don't know what to say, thank you so freaking much for all your help my friend, everything works perfectly now thanks to you! Take my "follow", this is such an inspiration, makes me want to become a better programmer, thank you once again!

avatar image
1

Answer by DiGiaCom-Tech · May 25, 2016 at 07:39 PM

@Internetman ... Just shooting from the hip here ;)

First ... You might try adding a collider to the spawner object and then move it to the intended spawn point every iteration. If the collider is triggered (e.g. it is in a collision with something) then you can test if that is OK ... if not then regenerate the intended spawn point ... rinse and repeat until a spawn point is generated that is not in collision with anything undesirable.

OR ... If you have a small set of spawned objects, you could test the distance from the generated spawn point to each object in the collection of spawned objects and if it's too small/close then step out and regenerate another spawn point.

OR ... you could cast a ray down from some point directly above the intended spawn point ...

 Vector3 RayCastPoint = new Vector3(SpawnPoint.x, SpawnPoint.y + 100f, SpawnPoint.z);

... if the ray collides with something undesirable then regenerate the intended spawn point and test again. I do this in my spawner to test for collisions with water layers and other world objects. Only problem with this is the ray is infinitely narrow and could miss collision with something by an infinitesimally small amount.

Finally ... you could leave the spawner code alone and add logic to the spawned object in it's Awake/Start methods to check where it spawned in at. If the location is undesirable then it will destroy itself and decrement any counters. If it's OK then it will initialize as needed and go about its business. Note that the spawner should keep track of how many it can and has spawned (e.g. 3 of 5 have spawned in). As the spawner still has more items to spawn things move on without incident.

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

163 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

Related Questions

Make a gameobject spawn before enemies spawn? (C#) 1 Answer

Make a collision check when spawning with Instantiate 1 Answer

Problem with instantiated prefabs. Object stays dark 1 Answer

How to spawn multiple prefabs at different spawn rates 0 Answers

Items spawn and will not stop spawning. 2 Answers


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