How can efficiently spawn many (as in, thousands of) objects?
Hello, I want to create a random 2D level at the start of the game. I made an empty game object and attached a script to it that spawns a given number of a certain object in a given range. Here is my code:
using UnityEngine;
using System.Collections;
public class StarPlacer : MonoBehaviour {
public GameObject[] Stars;
public int Star_Count;
public int Star_Space_Min;
public int Star_Space_Max;
public GameObject star;
public string StarTag;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Stars = GameObject.FindGameObjectsWithTag(StarTag);
if (Stars.Length <= Star_Count)
{
GameObject BackGround_Star = Instantiate(star) as GameObject;
BackGround_Star.transform.position = new Vector3(Random.Range(Star_Space_Min, Star_Space_Max), Random.Range(Star_Space_Min, Star_Space_Max), 0.1f);
}
}
}
The problem with this code is that it spawns one object per frame. I'm trying to spawn 2400 objects. It doesn't help that my FPS dies when the game starts so I end up spawning 2400 objects at 3 objects per second!
How can I spawn these objects more efficiently?
EDIT: When the code speaks about stars, it really means any object that I want it to mass spawn.
Do you really need individual gameobjects? For a star background a particle system is usually sufficient.
I've not considered a particle system. However, I don't only spawn stars, I also spawn asteroids, enemies etc. so I don't think a particle system will help. Thanks any way :)
But you'll probably have much fewer asteroids and enemies than stars. $$anonymous$$aybe you can use a particle system for the stars and spawn all other objects the conventional way.
If you really want to spawn so many objects:
Why are you instantiating the gameobjects in Update() and not in a separate function in/or called by Start()? ... You could just make a for-loop that spawns 2400 objects.
You are trying to find (and so to count) all your instantiated stars every frame by their tag (ins$$anonymous$$d of using a simple counter).
Thanks for the reply. So you're saying I should make the engine spawn all the objects in one frame. Ok, cool, I'll try that. Thanks.
I've tried to move some things around in my code. Now I'm using a while loop. But for some reason, my game freezes and stops doing anything when I test it in the editor. Even when only spawning a couple of objects.
What is wrong with this code?
public GameObject[] Stars; public int Star_Count; public int Star_Space_$$anonymous$$in; public int Star_Space_$$anonymous$$ax; public GameObject star; public string StarTag; // Use this for initialization void Start () { while (Stars.Length < Star_Count) { GameObject BackGround_Star = Instantiate(star) as GameObject; BackGround_Star.transform.position = new Vector3(Random.Range(Star_Space_$$anonymous$$in, Star_Space_$$anonymous$$ax), Random.Range(Star_Space_$$anonymous$$in, Star_Space_$$anonymous$$ax), 0.1f); } }
You are not adding the instantiated gameobject to your Star-array (or counting them in any way), so Stars.Length will always be 0 and the while-loop is looping forever.
a for loop is by the way most likely the better choice, because it's definitely going to end. Especially when know how many iterations you want (2400?)
Ok, thanks for all the answers. I used a particle system for my background stars and adjusted my object placer script to use a for loop in the start function. All my issues seem to be fixed. Thanks everyone XD.
Answer by ghostravenstorm · May 08, 2020 at 12:25 AM
I too am wondering this. In my example, I'm spawning markers at each point on Unity's Cartesian grid that label what that point in space is on the X and Z axis.
I've offset this work into a coroutine, but going into the thousands does really hurt computation.
public GameObject meterMarkerPrefab;
GameObject[] listOfMarkers;
Coroutine generateMeterMarkers;
IEnumerator GenerateMeterMarkers (int xRange, int zRange, Action onFinished) {
/// xRange is how far from the origin in both directions on the X plane.
/// zRange is how far from the origin in both directions on the Z plane.
/// e.g. xRange of 3 is a distance of 7 counting from -3 to +3 inclusive.
int numOfXMarkers = (xRange * 2) + 1;
int numOfZMarkers = (zRange * 2) + 1;
int totalMarkers = numOfXMarkers * numOfZMarkers;
listOfMarkers = new GameObject[totalMarkers];
int markerCount = 0;
for (int x = xRange * -1; x <= xRange; x++) {
for (int z = zRange * -1; z <= zRange; z++) {
listOfMarkers[markerCount++] = GameObject.Instantiate(
meterMarkerPrefab, new Vector3(x, -0.4f, z), Quaternion.identity
);
yield return null;
}
}
if (onFinished != null) onFinished();
yield return null;
}
Your answer
