I’d prefer this to be a comment but its a little long, so just to build on what @MD_Reptile was saying, you could create a class for your spawner so that you could keep the gameobject, active state and index all linked together, that way you could just have a list of that class and read from it whether a spawner object was active or not nice and quickly, as @gjf mentioned though, you should really do some profiling first as you might be gaining nothing from all this!
An example spawner class
public class Spawner {
GameObject go;
Transform t;
int i;
bool b;
public Spawner(GameObject g, int ind){
go = g;
t = g.transform;
i = ind;
b = g.activeSelf;
}
public void SetActive(bool a){
go.SetActive(a);
b = a;
}
public string ToString(){
return "Name: " + go.name + "
Index " + i + "
" + (b ? "Active
" : "Inactive
");
}
public GameObject gameObject{
get{ return go; }
set {
go = value;
t = value.transform;
}
}
public Transform transform{
get{ return t; }
set {
t = value;
go = value.gameObject;
}
}
public int index{
get{ return i; }
set { i = value; }
}
public bool active{
get{ return b; }
set { b = value; }
}
}
Some examples of usage!
public GameObject[] gos;
Spawner[] spawnObjs;
bool a = false;
void Start () {
spawnObjs = new Spawner[gos.Length];
for(int i = 0; i < gos.Length; i++){
spawnObjs _= new Spawner(gos*, i);*_
* }*
}
void Update () {
* if(Input.GetKeyDown(KeyCode.Q)){*
* SetAllActive(spawnObjs, a);*
* a = !a;*
* }*
* if(Input.GetKeyDown(KeyCode.Alpha1) && spawnObjs.Length > 0){*
* spawnObjs[0].SetActive(!spawnObjs[0].active);*
* }*
* if(Input.GetKeyDown(KeyCode.Alpha2) && spawnObjs.Length > 1){*
* spawnObjs[1].SetActive(!spawnObjs[1].active);*
* }*
* if(Input.GetKeyDown(KeyCode.Alpha3) && spawnObjs.Length > 2){*
* spawnObjs[2].SetActive(!spawnObjs[2].active);*
* }*
* if(Input.GetKeyDown(KeyCode.Alpha4) && spawnObjs.Length > 3){*
* spawnObjs[3].SetActive(!spawnObjs[3].active);*
* }*
}
void SetAllActive(Spawner[] s, bool b){
* for(int i = 0; i < s.Length; i++){*
_ s*.SetActive(b);
Debug.Log(s.ToString());
}
}
----------
EDIT: Some tests and another example!
----------
So to be honest I can’t really answer the question you posed in the comments very easily without knowing your current set-up or your final exact goals, one main thing to think about is that from my quick tests, density of spawn points has a much larger impact on performance than number of spawn points.
I don’t know much about the efficiency of using triggers, I did a few tests and the problem I was finding with a trigger set-up was as soon as the density of spawn points got past a certain point I would get the error “Internal error: Too many pairs created, new pairs will be ignored. This is perhaps due to an excessive number of objects created at one location.” - Not good, this is a consistently reproducible error for me when spawning 5000 spawn points in a 1000 radius circle around the player.
Important note: this could simply be because I am creating the spawn points in this test at random locations within this circle, possibly if predefined locations were used then you would not get this error due to the second part of it “This is perhaps due to an excessive number of objects created at one location.”
If you are staying in the low thousands of spawn points you may not have this problem however for completeness I also tried a second method which appears to work far more consistently but is likely to only be useful under certain circumstances:
This method actually involves calculating the distance between the player and each spawn point which sounds horrendous when you say you have thousands of spawn points, but the efficiency is increased a lot if you know the maximum speed your character can travel per second. Basically, each spawn point is created and then a Coroutine is started for each spawn point, so we now have a few thousand coroutines running checking the distance between a spawn point and the player, however if you know the maximum speed the player can travel, then if a spawn point is 100 units from the players activation radius and you know the player can only travel at 10 units per second, then you know for certain that you don’t need to call that coroutine function again for a minimum of 10 seconds (100/10). What this means is you can have loads and loads of spawn points and if you know a maximum speed and your activation distance, then most of those thousands of coroutines will only be called once every 10, 20, 30 seconds!
Using this second method I didn’t get any errors and managed to get to get 50,000 spawn points in a 1000 radius circle with an active range of 100 (they become active if they are closer than 100 units from the player) whilst maintaining a solid 40-60fps on my 4 year old laptop. My test code to follow (My prefab object was a gameobject with only a cube mesh filter and mesh renderer attached):
----------*
public GameObject prefab;
public float activeDistance = 100;
public float maxSpawnedDistance = 1000;
public int instances = 50000;
public float maxSpeed = 10;
Spawner[] spawnObjs;
Vector2 v2;
GameObject go;
Spawner spawn;
Transform trans;
public float minTimeGap = 0.25f;
Vector3 v3;
GameObject spawnParent;
public float fps;_
void Start () {
* trans = this.transform;*
* activeDistance = Mathf.Abs(activeDistance);*
* maxSpawnedDistance = Mathf.Abs(maxSpawnedDistance);*
* instances = Mathf.Max(instances, 0);*
* maxSpeed = Mathf.Max(maxSpeed, 1);*
* minTimeGap = Mathf.Max(minTimeGap, 0.1f);*
* if(prefab == null){*
* Debug.LogError(“No prefab has been assigned”);*
* }else{*
* Init();*
* }*
}
void Update () {
* fps = 1/Time.deltaTime;*
* v3 = trans.position;*
_ v3.x += Input.GetAxis(“Horizontal”)maxSpeedTime.deltaTime;
v3.z += Input.GetAxis(“Vertical”)maxSpeedTime.deltaTime;
* trans.position = v3;
}*_
void Init(){
* spawnParent = new GameObject();*
* spawnParent.name = “Spawn Object Parent”;*
* spawnObjs = new Spawner[instances];*
* for(int i = 0; i < instances; i++){*
_ v2 = Random.insideUnitCirclemaxSpawnedDistance;
go = Instantiate(prefab, new Vector3(v2.x, 0, v2.y), Quaternion.identity) as GameObject;
go.transform.parent = spawnParent.transform;
spawn = new Spawner(go, i);
spawnObjs = spawn;
StartCoroutine(CheckDist(spawn));
}
}*_
IEnumerator CheckDist(Spawner s){
* while(true){*
* float diff = (s.transform.position-trans.position).magnitude-activeDistance;*
* if(diff > 0){*
* s.SetActive(false);*
* }else{*
* s.SetActive(true);*
_ diff = -1;
}
yield return new WaitForSeconds(Mathf.Max(diff/maxSpeed, minTimeGap));
}
}
----------*
This way all (I think) memory allocation is done in the Start method, and you will never get indexes mixed up between boolean states and gameobjects, you could add a lot more functionality to the class for example I have added the ToString function to quickly get a nicely formatted string of some of the variables contained! You could even add a script to each spawner gameobject with a reference variable to its own instance of the Spawner class so that you could find which spawner object it was from a raycast or similar!
I hope that helps 
Scribe_