Can someone explain to me why all of this is better than a singleton?

All this extra complexity seems kind of crazy. if you add it all up its like an hour than an hour of videos just trying to get around using a singleton with the fader. I don’t understand how this is any better than a singleton. this feels like cutting off your nose to spite your face.

@Brian_Trotter I’m legitimately lost here. why are we doing all of this? i had my own solution that was working fine. thought id try his. now everything is broken( i even pasted his exact code in and checked all referenced objects in unity afterword’s. the fader hits alfa 1 and never goes back down).

I’m going to go back to mine for now so i can keep going through the course, there is something i’m just not getting.

I’ll let you in on a dirty little secret… The Persistent Object Prefab is… Just another type of Singleton…

You can set the SavingSystem, SavingWrapper, and Fader as Singletons, if you wish. In fact, as we move forward, we never really mention the PersistentObjectSpawner again. It was a construct that Sam used to get away from the classic Singleton pattern.

Singletons can be a useful tool, but in classic OOP, there are many (like myself, before learning Unity, as a matter of fact) who feel that Singletons do a sort of end run around the entire paradigm of Object Oriented Programming. Of course, Unity’s architecture sort of pushes us into needing Singletons both because some things need to survive between scenes, and because we often need an efficient way to find that one thing.

If it helps for debugging, the issue you’re experiencing with the Fader not fading has three potential root causes (two generally yield an error message, and one a warning which should be an error message, which should help).

The first occurs when the game is first started and there is an existing save file. In this case, the issue is that the CanvasGroup is initialized in Start() instead of Awake().

The second occurs when travelling through a Portal. In the Coroutine, the Fader is assigned and told to FadeOutImmediate, so far, so good. Then after the scene transition, the Fader gets a null reference exception. This is usually caused because of forgetting to remove the PersistentObjectPrefab from the scene heirarchy after it’s been turned into a Prefab.

The third is caused if the Portal is not at the root of the heirarchy. Ordinarily, we recommend organizing scene objects, and instinctively putting all of the Portals under a master GameObject is something that makes sense. The issue there is that when you make a GameObject DontDestroyOnLoad, that GameObject cannot have a parent. There are two solutions for this:

  1. You can make sure all Portals are at the root of the Heirarchy (have no parent) or
  2. You can put this line immediately before the DontDestroyOnLoad(gameObject);
transform.parent = null;

I’m more trying to understand why we would be going to such lengths to avoid just using a standard singleton(sorry if i wasn’t clear because i was damned near ranting). the fact that this much effort is being put into avoiding using something means i don’t understand the severity of the singleton pattern problem. Sam says it has Many disadvantages. but the only ones he lists are…

  1. leads to coupling because singletons are accessible- ( i mean i guess it can, if you get lazy, but you can also just NOT do that instead)
  2. too much responsibility for one class - (true - but couldn’t you solve this by making a singleton class that inherits from Monobehavior)? is there a problem with having singleton inherit from monobehavior?

also none of the things you are listing above are what is happening in my project. I’m grabbing in awake, portals are in the root, and persistent object is not in the hierarchy of either scene. i also scrubbed for something silly like an extra event manager or canvas left behind somewhere.

this is the error i get. ( im deleting the save file before every game). i have not touched the save system since the save system module) I skipped the advanced save module.

Im really kicking myself on this one too cause i decided NOT to do version control during this part of the project as a full version of the project is available at the start of the next series. i got fast and loose and now Im paying for it.

It’s mainly a matter of Sam disliking Singletons even more than I do (I use them, when needed, though). I found it to be an overkill solution.

Not at all. In fact, a common Singleton pattern is to make a Singleton base class that derives from MonoBehaviour

public class Singleton<T> : MonoBehaviour where T : Singleton<T>  
{
    private static T instance;
    public static T Instance { get { return instance; } }

    protected virtual void Awake() {
        if (instance != null && this.gameObject != null) {
            Destroy(this.gameObject);
        } else {
            instance = (T)this;
        }
    }
}

Then you would derive that class as:

public class SavingWrapper : Singleton<SavingWrapper>()          

That’s actually simply a log indicating that the Save is saving (which happens any time you go through a Portal), and not an actual error message.
That doesn’t necessarily mean that there isn’t an error happening. Check in the upper right hand corner of the Console and make sure that error messages aren’t suppressed. If there is a number (besides 0) in the last of the three buttons, then errors are being suppressed, click on the button and it will then show the error.

If there still isn’t an error, then we’re into something unusual that I may not have seen yet. In that case, zip up your project and upload your project to https://gdev.tv/projectupload and I’ll take a look at it. Be sure to remove the Library and .git folders to conserve space.

Oh sorry i didnt check the image preview when i pasted it in . i have an annoying thing with snipping tool where the snip is offset if i do it from my bigscreen because its in a different resoloution. my bad

So in this case, one of your CaptureStates is returning a LazyValue instead of the LazyValue’s .value property. A LazyValue itself is not [System.Serializable], but in most cases, it’s .value is (like when it’s a float.
9 times out of 10, this happens in the Health script

public object CaptureState()
{
    return currentHealth;
}

when it should be

public object CaptureState()
{
    return currentHealth.value;
}

Unfortunately, Binary Formatter never tells us exactly which CaptureState() returned a non-serializable value, just that it was a LazyValue.

i figured that’s what it was, but when i couldn’t find it i tried switching all the scripts to the repo code. so everything in my code is just sam’s code now. the problem didn’t resolve when i swapped them out.

Once the save file has been spoiled, it must be deleted (an unfortunate BinaryFormatter problem).

i delete the save file before i hit play every time

Zip up your project and upload it to https://gdev.tv/projectupload and I’ll see if I can figure out what’s going on. Be sure to remove the Library folder and .git folder to conserve space.

Ill make another pass and look for something where the lazy loader is having an issue. any recommendations on how to find that spot? when i scrubbed for it before i was just looking at the variables at the top, looking for “lazyloaders” and then searching for them in the script

Ok sure let me take one more quick pass and then ill ship it t o you. feels like giving up lol

Welp i figured it out. it was in base stats. i had not changed for a long time, but i also had not gone through a portal in a long time or used the save in a long time. the error was going to happen regardless of the portal, it would have happened if i had just saved and loaded, which i did not try. and i didn’t swap base stats code for sams since it was not in the lesson where the bug presented.

basically i assumed too much and didnt use my big boy troubleshooting brain. thats what i get for doing lessons until 3am. i got dumb

We’ve all been there. Important bit is it’s sorted now. :slight_smile:

Privacy & Terms