I'm wondering how I can organize instantiated GameObjects that are spawned in sort of a nested structure. I'm spawning these GameObjects via Containers, a set of classes that either spawn the GameObjects directly, or spawn other Containers with some kind of logic. I want to be able to spawn a number of Containers, and then spawn a parent in the Unity hierarchy to which each of the GameObjects spawned by these containers will be parented. However, some Containers will also be parented to other Containers, creating this kind of structure:
Container
Container
Prefab
Prefab
Container
Prefab
Prefab
For example, I may have classes like these:
public abstract class Container : ScriptableObject
{
public static event Action<Container> OnContainerSpawned;
public abstract void Spawn(Vector2 position);
protected void RaiseSpawnEvent(Container container)
{
OnContainerSpawned(container);
}
}
// Spawns a single prefab; this is the smallest "unit" in my system
public class GameObjectContainer: Container
{
public static event Action<GameObject> OnGameObjectSpawned;
[SerializeField]
private GameObject prefab;
public override void Spawn(Vector2 position)
{
var spawnedPrefab = Instantiate(prefab, position, Quaternion.identity);
OnGameObjectSpawned?.Invoke(spawnedPrefab);
RaiseSpawnEvent(this);
}
}
// Spawns a container in a row
public class RowContainer : Container
{
[SerializeField]
private Container container;
[SerializeField]
private int length;
public override void Spawn(Vector2 position)
{
var spawnPosition = position;
for (int i = 0; i < length; i++)
{
container.Spawn(spawnPosition);
spawnPosition += Vector2.right;
}
RaiseSpawnEvent(this);
}
}
// Spawns a container in a column
public class ColumnContainer: Container
{
[SerializeField]
private Container container;
[SerializeField]
private int length;
public override void Spawn(Vector2 position)
{
var spawnPosition = position;
for (int i = 0; i < length; i++)
{
container.Spawn(spawnPosition);
spawnPosition += Vector2.down;
}
RaiseSpawnEvent(this);
}
}
I'm currently using events to alert my debugging class that something has been spawned so that it can parent things accordingly:
public class Debugger : MonoBehaviour
{
[SerializeField]
private GameObject prefabParent;
private List<GameObjects> recentlySpawnedGameObjects = new List<GameObject>();
private void OnEnable()
{
Container.OnContainerSpawned += TrackSpawns;
GameObjectContainer.OnGameObjectSpawned += recentlySpawnedGameObjects.Add;
}
private void TrackSpawns(Container container)
{
if (container is GameObjectContainer) // Don't bother making a parent for a single GameObject
return;
// Make a new parent in the hierarchy, and update its name
var parent = Instantiate(prefabParent);
parent.name = container.name;
// Parent each recently spawned GameObject (from the event in the GameObjectContainer class) to the parent we just created
foreach (var gameObject in recentlySpawnedGameObjects)
gameObject.transform.parent = parent;
// Clear the list, and await next container to spawn
recentlySpawnedGameObjects.Clear();
}
}
This might produce a result that looks like this:
Row Container
GameObject
GameObject
GameObject
This is fine, but it only shows the topmost Container. What if I have a RowContainer that spawns a ColumnContainer that spawns a GameObjectContainer, attempting to get something that looks like this:
Row Container
Column Container
GameObject
GameObject
GameObject
Column Container
GameObject
GameObject
GameObject
Column Container
GameObject
GameObject
GameObject
I have no idea how to achieve this. In my actual game I'm spawning things using object pools, so I only need to track the pooled objects and reuse them as necessary, which I can do. However, it would be very nice to debug my system in this way, creating an easy-to-understand visual, especially as my game becomes more complex.
Instantiate? docs.unity3d.com/ScriptReference/Object.Instantiate.html All you need to do is pass the parent, under which it should be. \$\endgroup\$Instantiatemethod to assign a parent. \$\endgroup\$