The example solves DontDestroyOnLoad but not .GetInstance()

The video showed how this component solves DontDestroyOnLoad but didn’t show how it replaces GetInstance. Isn’t that legitimately one of its uses?

To argue for an example: you have various individual animation scripts for different things. But at different points in the game, for different objects, they spawn the same kind of effect. You wouldn’t put an effect prefab directly into them because, arguably, they shouldn’t need to know the specific prefab; just that it needs to spawn, say, an “explode” effect at a certain spot.

The interface would be something like EffectSpawner.GetInstance().ExplodeAt(Vector3). And components of that singleton could take care of randomization, audio, particles, pooling, etc, so that the script merely wanting to make an explosion doesn’t need to know how and to manage the performance details.

This doesn’t have to be effects. They could be spawning enemies. Or pickup items. Coins. Anything where various scripts dealing with logic of WHEN to spawn something shouldn’t need to know HOW to spawn a common thing.

What would be the solution for this? (in the context of the shown PersistentObjectSpawner script) Or is that simply not what it’s for?

I would argue that using Singletons for many of these things is bad practice…

In terms of the GetInstance, this is replaced in the PersistentObjectSpawner model with FindObjectOfType<T>()
We use this particular model in the RPG course series for our saving system, and the Fader that controls the scene. We’re not calling any of these frequently (and ideally, no singleton should be called frequently anyways).

For most of the things you list, I would stick with a more object oriented approach.

I’ll give a great example in the EffectSpawner you’re discussing, using another tool in the Unity playbook, the ScriptableObject. In fact, this EffectSpawner will even allow you to apply several different explosions chosen randomly.

using UnityEngine;

[CreateAssetMenu(fileName= "New Explosion", menuName = "Effects/Explosion")]
public class ExplosionFactory : ScriptableObject
{
    [SerializeField] private GameObject[] explosions;
    
    public void ExplodeAt(Vector3 location)
    {
        GameObject go = Instantiate(explosions[Random.Range(0, explosions.Length)], location, Quaternion.identity);
        Destroy(go, 10f);
    }
}

Now a class that needs to instantiate an explosion can simply add the field

[SerializeField] ExplosionFactory explosionFactory;

and when needed, call the method:

explosionFactory.ExplodeAt(transform.position);

And it’s fire and forget.

This has two advantages. One: You can make changes in one asset to change the available explosions for everybody. Two: You can have multiple ExplosionFactories, choosing the factory most appropriate for that GameObject’s situation. For example: A laser might want a small focused explosion with sparks, while a rocket launcher may want big poofy explosions. Different lasers can all share the LaserExplosionFactory while different Rocket Launchers would share the same BigExplosionFactory.

1 Like

Interesting solution! Thank you!

I see the ScriptableObject Factory solution working in the cases where the factory doesn’t need knowledge of scene objects/hierarchy. I’ll have to try it to see if I run into any practical problems.

I finished this course just now. I’ll be proceeding with the RPG course next week. It’s much longer than I expected but I’m excited to see the specifics of how solutions like this were used.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms