Hi everyone, let me know your honest opinion on the C# 8 interface methods in the comments - I may or may not use them in future videos. Link to the source code is in the description! 👍
i like seeing them, i think both versions of using and not should be shown so people can recognise them better and how to convert to them where/if sensible
It's great you show them. I'm an experienced developer. I've heard of them but never seen them in the code. That doesn't mean we shouldn't use them. Great job!
When I started learning Unity game programming I asked my lecturer why can't interfaces be defaulted with base behaviours. My lecture gave the standard "because it's not allowed" speil about them being a 'contract' so I chuckled learning of this new feature. I think it's good for simple cases where the abstract base class really just exists to implement the interface with default behaviours. Merging them means one less file to worry about. Though "The New Toy Principle' stipulates any new toy will inevitabely get broken my many users due to the play instinct overriding the read the manual rationale logic. lol.
@@OdysseyHome-Gaming I found another use for this just yesterday. If you have properties defined in the interface and then implement a base abstract class, then all inheritors must abide by the access levels defined in the abstract class. So, if you have a private setter in the base class, you cannot make a public setter in another one. By not having a base abstract class, you are only defined by the contract of the interface (in my case, only defines { get; } so I can do whatever I want with the setters in any implementors. In that sense it is indeed still behaving as a contract, but it's also not giving me any of the limitations of the abstract base class.
I discovered your channel 2 weeks ago and I really praise you for actually covering more advanced topics and not another "create your first game for dummies" channel. Could you cover MVP - MVC and MVVM patterns for handling UI in a future video? That would be great. Anyways, keep up the good work!
Thanks! A few others have asked for MCP/MVC, and I've started working on a video for that. I want to cover that before starting into any more complex systems! Cheers!
I started learning unity couple weeks ago to implement some simulations I wanted to demostrare. However your channel got me by surprise, there is something about game development that makes the implementation and explanation of software design patterns oddly satisfying. I am a profesional DevOps engineer and cloud architect, and let me tell you; your videos have been a huge inspiration to clean up my code and audit the dev teams I support. Please keep the great work! This channel is a gem ❤
I've watched a few of your video's, I like the level of depth and breadth you go into on these subjects. Your channel got a mention on Jason Weimann's latest GameDevShow so your efforts are appreciated.
Great video! I really appreciate hearing about new language features as well since I didn't realize interface methods were usable in Unity. I always think it's funny that in general software development, singletons are considered "bad" design, but they're extremely useful in game dev.
@@git-amend My game is flooded with them for everything. Especially useful when dealing with Timeline custom tracks and cross scene references. I ended up making a handful to stuff like black bars during cutscenes, subtractive screen fader, etc, just so I could easily test them all in the editor without needing to run the game and rebind everything. Timeline and cross scene references are the bane of my existence, haha.
@@git-amend Was showing this video to someone just now and they got mad that people use singletons ever, as opposed to SO's or injection. I tried to argue there are many use cases for them when you actually need to reference one thing globally, but they remained adamant. What's your take on that debate?
@@MarushiaDark316 I think that it's important to recognize that while DI is a powerful and usually preferable design approach, it may not always provide a solution to every architectural challenge. Particularly, in scenarios where it's critical to ensure that only one instance of a certain class is operational - a constraint that DI alone cannot enforce. In such cases, the Singleton pattern becomes not just relevant but essential. Critics of the Singleton pattern often raise valid concerns about global state, it's potential to hinder testing, and complicate code maintenance. However, the pragmatic aspect of software development sometimes requires balancing ideals with the practicalities of existing systems and specific technical requirements. So, while the Singleton pattern is not universally applicable, dismissing it entirely overlooks the complexity and diversity of software engineering challenges.
These will work in 2022 LTS just to be clear. It's only versions before the 2022 alpha release that don't support it. If you were to do it before 2022, you would have to put the Null class and default methods into a base class. Not much different, but a little bit more code. There were some good comments about this already, so I will probably talk about it a bit more in the future! Cheers!
Good to see that Unity is starting to use newer version of C#. Wish it was more current. About using new C# features in Unity. I think it is a good idea that you document that such feature is used.
I think I will see how .NET devs are handling these features... they've been around for so long, there must be some good conventions used outside of game dev.
What I love most about these videos is the overlap of concepts. Learning about singletons? How about you practice some command and factory pattern implementations as well! 11/10 - on a sidenote I was able to implement the null singleton interface in 2022 without any issues. So thats pretty cool
@@git-amend Im here for it! Definitely drives home all of the different concepts and helps with cementing the basic ideas of actual engineering. Please do keep it up! :)
Tested the new interface implementation in Unity 2021.3.26f and it works well. I suppose the new features are somehow compatible with versions earlier. The only way to know is to try it out. Thanks for introducing new interface features.
That had a lot of valuable information, I added the unparenting part to mine now.. never ran into the issue of it not being a top level object, but in case it happens it would be bad if the DontDestroyOnLoad fails to move the object into the DontDestroyOnLoad scene. Also a really small thing: for the InitializationTime it might be better to use realtime (like Time.realtimeSinceStartup) because sometimes people either have the timeScale set to 0 for longer or just forget about changing it back. A possible extension of the singletons (not sure if you covered that somewhere yet): Having a ServiceProvider approach where you have a static class that manages singleton access. Consumers request an interface type from that class and get the configured singleton for it. This could for example allow mocking singletons for tests and such. Although even though I have something like that in my project I haven't had an actual use for it yet.
I love that you bring up the concept of principle of least surprise. I think these new features are amazing, but I think they lead to a ton of confusion and lower readability if implemented without comments explaining what is going on. I am on a project with a more junior dev who is gung-ho about using every modern c# syntactic sugar and feature which is great, but also its important to understand the value of making your code in a way that someone else can expect certain behaviour based on conventions. I think these new features are wonderful and lead to less verbose ways to express the same things, but less verbose often means harder to understand, which can translate to more complex. I think it's a constant tradeoff to consider and if using new fancy things like the c# 8 interface methods, its important to leave some comments describing the intent for clarity. maybe in 5 years it will become the common convention, but until that point older coders will find them confusing and it leads to harder to understand code for them, which on a project with a bigger team makes it less valuable than more verbose code
Thanks for the comment. I agree with all of that, and for the most part, I have been leaning towards only adding a default interface method if the interface is already in use and adding a new method to the interface would cause a lot of problems where it has already been implemented (in a public api at least).
@@git-amend I might be a bit naive in my thinking but I can't think of a situation where adding a method to an interface would cause a problem. Or do you mean more specifically .... having to call a new method from an interface everywhere that references that interface? In my thinking, adding a new method to an interface is free and the risk is zero so im not quite sure im on the same page as you here. not trying to be obtuse or difficult, I just wanna make sure I understand
@@unitydev457 Adding a new method to an interface typically requires all implementing classes to provide an implementation for the new method, which can be problematic in widely-used libraries as it forces all consumers to update their implementations. For example, suppose I have created a popular Unity logging tool and I have an interface ILogger where I want to add a new logging method. By providing a default implementation, I can ensure that existing classes implementing ILogger do not need to change unless they want to override the default behavior. All consumers can upgrade to this latest version of the Library without making any further changes to their code that uses the interface unless they choose to.
@@git-amend oh gosh okay yeah it sounds stupid and obvious now that you explained it. changing the interface means anything implementing it requires adding an implementation of the new methods in that interface. In that sense its not free at all, if you add a method to an interface thats implemented by like 40 or 400 classes in your project, you have to go and add that method and possibly some implementation logic to each of those 40-400 classes. In hindsight it was a really dumb question. I was thinking in reverse, that a new method on the interface doesnt change your consumption of that interface. the things consuming it don't have to do anything new if the interface adds methods. Thank you very much for taking the time to clarify something pretty obvious. I appreciate you helping me be less dumb :) edit: actually I just realized something that needs clarification, what do you mean by consumer? in my mind consumers would be things that get a reference to the interface and then maybe call a method on it. Is that what you mean when you use the term consumer? or are you referring to things that implement the interface as consumers.
Hi @git-amend. At 2:27 you say that FindAnyObjectByType() finds objects in any loaded scene. However based on my testing it seems like it only finds them in the active scene or the same scene the calling object is in. Do you know of any method I could use instead to find an existing instance even if it's not in the active or same scene as the object where I want to access the Singleton? Edit: Yet strangely FindAnyObjectByType() is able to find the instance after the Singleton's Awake() has been called despite not being in the same or active scene. I'm at a loss D:
The confusion probably comes from the order of execution. In Unity, the `Awake` method is called when a script instance is being loaded, before any `Start` methods are called. This means that even if a GameObject is not active in the scene, its `Awake` method can still be invoked. See docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html Also, in this particular situation keep in mind that instance is a static variable, meaning that once instance is assigned in the Awake() method of one object, that assignment will persist across all scenes.
Hey. Another nice detailed video about a pattern that many (game) developers will use. I was wondering at 1:48 you say that for the ScoreKeeper Monobehaviour it already is too much boilerplate code (for you) then proceed to create 3 more complex examples that not every developer will get without research, some explanation or descriptive code comments. What are you thoughts on code readability in regards to a team or maybe other external developers in the future?
By boilerplate, I'm referring to repetitive visual clutter. I tend to agree with most of what is written here: stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
I figured it out ( i feel like we're best friends now) What sets you apart is that you explain the CORE CONCEPTS of everything. You don't just 'code a loop function' You explain that loop function explicitly rather than implicitly. You don't talk with the assumption that I know what you're talking about. Nor do you address me with the assumption that I'm a developer with X years of experience. You just talk to me as if we're working on this together. You said: "Lets get the regulator singleton component" Now...I could anticipate what you are going to do based on your previous sentence: "Doesn't matter what sort mode we use, because we're going to get rid of all of them" So you're going to get rid of all singleton instances next... nd yet...You made sure to go through each line of code and explain it in such a simple concise way... We're best friends now.
4:45 I'm a bit confused on how this bitflag works. You say you use it so the object doesn't get saved with the scene but...why would it? If instantiated objects aren't serialized to the "serialized scene state" that exists in edit mode, why would this flag be necessary?
HideFlags.HideAndDontSave is necessary for objects created at runtime to explicitly prevent them from being saved or appearing in the scene hierarchy, as Unity does serialize some runtime objects into the scene state under certain conditions, like during play mode in the editor.
@@git-amend very interesting, thanks for the reply. Just when I think I'm getting a hang of this engine something new always throws me for a loop, haha
How do you handle the case where you want your singleton to have serialized values ? If it is responsible for instantiating a prefab, I need a serialized field where I can store that prefab. However, if that singleton is auto-generated through AddComponent, that field won't be populated (even worse if you hide the singleton from the hierarchy). Also, you do not handle the case where the Instance is fetched during unload (ie. scene change for your first singleton, and play mode exit for the other two). If you try to generate a new Instance during scene unload, Unity will send you a nasty error message "you cannot spawn sttuff during unload". I've been struggling with these issues for a while, I do have some workarounds with helper classes and trickery (mostly preventing generation once Unity enters the unload phase between scenes / on play mode exit), but no elegant solution.
This is something that is being discussed on Discord a little bit, you might be interested in joining that discussion. Generally speaking, for the types of use cases you are describing, you would probably want to have a scene that is primarily for game management where your manager class lives. You would still enforce the singleton constraint, but you never have to worry about unloading your instance or about serialized values. If you need to change the values that were serialized during runtime, you can always offload that work to a service class.
Any reason the github repo link doesn't exist anymore? Also never heard of the 'Regulat' before, but nice idea! What is your opinion on utilizing the Lazy type C# provides? While I realize it may not be desired to have a Singleton be instantiated lazily, I feel like it takes care of all the boilerplate one might think about when working with them(like thread-safety), unless I understood it wrong.
I added the ability to import the entire Utility library as a package this week, can still access the code from the root level. I've updated the link: github.com/adammyhre/Unity-Utils Regarding the Lazy operator, it is certainly an option and useful in many scenarios!
Personally, I use the Persistent Singleton, but with a virtual bool "Persistent" defaulted to false, and if it is true, does the DoNotDestroy. Then you only have one file.
Yes, it does seem a bit counter intuitive. One argument I've heard so far as a pro is that you could add a method to an interface and provide a default implementation so that classes that implement the interface don't all break.
@@git-amend That's the one of the two legimate usages for default interface implementation, the other one being a generic interface inheriting from a non generic one, something like public interface INonGeneric { object GetValue(); } public interface IGeneric : INonGeneric where T : class { T GetValue(); // Default implementation of INonGeneric.GetValue() object INonGeneric.GetValue => this.GetValue(); }
I was wondering if there was any reason why you shouldn't make the other singletons inherit from your base singleton class and override the methods and mark the properties with a new if necessary.
You certainly could take that approach if you wanted to, and in fact I would say it's worth considering in your own projects if you felt that was useful for long term maintenance or some other reason. Usually though in the context of a UA-cam video, for the sake of communicating the ideas being presented, I do my best to keep it as straightforward as possible.
I see, thank you! I'd really like to thank you for the quality of your videos, which are really professional. I've been looking for months for videos on game architecture in unity, which is often poorly explained, and with you I'm taking it to the next level.
I have been wondering, What design batterin would be best for interactable objects? Like you pick up a key from the ground and then you can open the door. Key is a picup so i think it was Visitor patttern for pickups. But what pattern for interactable objects?
That's probably a bit too much to describe in a comment, because it wouldn't necessarily require one programming pattern to solve and would mostly fall back onto Unity's functionality. If you want, feel free to request a video on the Discord so I don't forget, and maybe can cover that in the future.
i often declare singleton class in Start() instead of Awake() cause whenever i declare one in Awake, the null reference will happen. I think unity have no execution order for Awake method . Therefore, suppose i wanna reference to another component from another class, it will return null. And i saw that u declare singleton right in Awake, it means that whenever u in play mode, it will initialize that singleton object. I read a method called lazy initialization so instead of declaring right in awake, i create an Instance static variable so that whenever i call that it will initialize singleton class for me. So what do u think about this prob, is it better to initialize singleton in awake or only initialize it when u need.
There's no guaranteed execution order for Awake() unless explicitly defined via script execution order settings. If one script tries to access the singleton instance from its Awake() method before the singleton's Awake() has run, the instance won't be initialized yet, leading to a null reference. My suggestion to you is that you initialize scripts in the Awake method and reference other scripts, including the singleton, from the Start method. See: forum.unity.com/threads/a-comprehensive-guide-to-the-execution-order-of-unity-event-functions.1381647/ If you cannot do that, I would suggest running the singleton script earlier than others which you can set using Unity's Script Execution Order settings or use the DefaultExecutionOrder Attribute like this: [DefaultExecutionOrder(-100)] // This script runs before most others See: uninomicon.com/defaultexecutionorder
Yoo. I have a question. If i have other scripts to the same gameobject that holds the regulator singleton, do they persist between scenes as well? Edit: I just checked with a script. Yeah anything attached to the regulator singleton object is persistent and don't get reset.
Hey there, how can I make a persistent object ? like UIManager, MusicManager , LevelManager , to be persistent object ,or load allthis object in some kind of Awake? and check if does exist in the beggining and load automatic with references. thanks.
You might benefit from watching the video about multi-scene loading so that you can have a Bootstrapper scene that contains all your persistent game objects. ua-cam.com/video/JFP-cCFID7o/v-deo.html
I have another question that isn't related to this video. Do you use game managers? Are they different for each project? The more I think about it, the less i see the use of a game manager. Cause most scenes are limited to just one state anyway. Why store the state of the game like "menu" or "in-game" when the menu is its own scene?
I do not typically use a Game Manager per se, but they can be useful sometimes. I think it really depends on the size of your project. In a small project it can be an efficient way to handle global state, but most people want to build games where you need a more robust solution. We'll dive into that when we start talking about additive scene loading.
@@git-amend Sweet. Looking forward to it. If possible, could you explain when do you usually save game data? Idk if the game manger should be in charge of that...
Hi, is there a good way to remove static? The reason is that Unity remove all the static field when recompile during runtime. It would great if you can make a video about making a structure functions like static but doesn't get deleted when recompile in runtime.
I don't know if I can make a whole video about that, but here's a suggestion. I'm going to assume you mean that when scripts are recompiled in the editor, static fields are reset to their default values. To address this, you could use a ScriptableObject to store the singleton's data, which is then accessed through a MonoBehaviour component that loads the data from the Resources folder. This method ensures data persistence across script recompilations and scene transitions. The MonoBehaviour can dynamically load and reference the singleton data at runtime, thus maintaining a form of global access similar to traditional singletons but circumventing the issue of static fields being reset during runtime recompilation.
@@git-amend great! I think runtime recompile is a really good feature, it would save a a lot of time for bigger project, but there isn't anyone talking about taking advantage of it, like avoiding static
I just wonder when you just wrote the scorekeeper class and it shows all class awake and method gray. How its possible in rider is there any update to do that ? Like autofill from AI or check previous scripts, solutions ?
@@git-amend I watched the video and it's really great. This design patterns was like a tv series whose new episode I was eagerly waiting for. Like i said I want to watch more of those and thank you for all your work.
This may be more the result of my poor coding elsewhere, but I get a situation where as i close out a scene and delete all the GOs, I seem to still be fetching for Instances that have the plain Singleton extension, giving me the following error: "Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?) The following scene GameObjects were found: EventManagerAuto-Generated QuestManagerAuto-Generated PlayerEquipmentManagerAuto-Generated" @git-amend: would you adjust the singleton code to accommodate for these types of issues, or would you say that this means i have serious issues elsewhere 😅
@Brightfield probably happens because you're calling something from the Singleton's Instance in a OnDestroy() or OnDisable() method. I assume you're using the first Singleton type from the video. If so you can simply add the "go.hideFlags = HideFlags.DontSave;" (2:39) in that class as well.
@@MSCardinal to clarify - another script, Script A, is referring to the Singleton instance, and upon stopping the game, Script A triggers OnDestroy or OnDisable, and tries to for instance unsubscribe its observer method from the Singleton which is already destroyed? Would I be adding a new line 16 before setting go to instance ?
Hi everyone, let me know your honest opinion on the C# 8 interface methods in the comments - I may or may not use them in future videos. Link to the source code is in the description! 👍
i like seeing them, i think both versions of using and not should be shown so people can recognise them better and how to convert to them where/if sensible
It's great you show them. I'm an experienced developer. I've heard of them but never seen them in the code. That doesn't mean we shouldn't use them. Great job!
I didn't know that they weren't there before :D I started using Unity this year. Interface methods make it easier a lot
When I started learning Unity game programming I asked my lecturer why can't interfaces be defaulted with base behaviours. My lecture gave the standard "because it's not allowed" speil about them being a 'contract' so I chuckled learning of this new feature.
I think it's good for simple cases where the abstract base class really just exists to implement the interface with default behaviours. Merging them means one less file to worry about.
Though "The New Toy Principle' stipulates any new toy will inevitabely get broken my many users due to the play instinct overriding the read the manual rationale logic. lol.
@@OdysseyHome-Gaming I found another use for this just yesterday. If you have properties defined in the interface and then implement a base abstract class, then all inheritors must abide by the access levels defined in the abstract class. So, if you have a private setter in the base class, you cannot make a public setter in another one. By not having a base abstract class, you are only defined by the contract of the interface (in my case, only defines { get; } so I can do whatever I want with the setters in any implementors. In that sense it is indeed still behaving as a contract, but it's also not giving me any of the limitations of the abstract base class.
I appreciate how you delve into higher-level programming on your channel, whereas most gamedev UA-camrs tend to stick to the basics.
Thank you!
I discovered your channel 2 weeks ago and I really praise you for actually covering more advanced topics and not another "create your first game for dummies" channel. Could you cover MVP - MVC and MVVM patterns for handling UI in a future video? That would be great. Anyways, keep up the good work!
Thanks! A few others have asked for MCP/MVC, and I've started working on a video for that. I want to cover that before starting into any more complex systems! Cheers!
Really high quality stuff, I adore your knowledge about programming
Thank you so much!
I started learning unity couple weeks ago to implement some simulations I wanted to demostrare. However your channel got me by surprise, there is something about game development that makes the implementation and explanation of software design patterns oddly satisfying. I am a profesional DevOps engineer and cloud architect, and let me tell you; your videos have been a huge inspiration to clean up my code and audit the dev teams I support. Please keep the great work! This channel is a gem ❤
Thanks, that's an amazing compliment! Cheers!
I've watched a few of your video's, I like the level of depth and breadth you go into on these subjects. Your channel got a mention on Jason Weimann's latest GameDevShow so your efforts are appreciated.
Much appreciated!
Great video! I really appreciate hearing about new language features as well since I didn't realize interface methods were usable in Unity. I always think it's funny that in general software development, singletons are considered "bad" design, but they're extremely useful in game dev.
Thanks! It is funny isn’t it - I tend to avoid them out of habit and not necessarily because they are ‘bad’ for this very reason!
@@git-amend My game is flooded with them for everything. Especially useful when dealing with Timeline custom tracks and cross scene references. I ended up making a handful to stuff like black bars during cutscenes, subtractive screen fader, etc, just so I could easily test them all in the editor without needing to run the game and rebind everything. Timeline and cross scene references are the bane of my existence, haha.
I love when I find a hidden gem new channel on my feed! This is great stuff man. Keep it up :D
Welcome aboard!
NOOO you dropped the Malevolent namespace for our beloved singletons 😅😁😁😂😂
Sorry... it shall return...
Yet another great video! Good job! Keep it up.
Thanks!
"There can be only ONE!"
Hahahaha!
@@git-amend Was showing this video to someone just now and they got mad that people use singletons ever, as opposed to SO's or injection. I tried to argue there are many use cases for them when you actually need to reference one thing globally, but they remained adamant. What's your take on that debate?
@@MarushiaDark316 I think that it's important to recognize that while DI is a powerful and usually preferable design approach, it may not always provide a solution to every architectural challenge. Particularly, in scenarios where it's critical to ensure that only one instance of a certain class is operational - a constraint that DI alone cannot enforce. In such cases, the Singleton pattern becomes not just relevant but essential.
Critics of the Singleton pattern often raise valid concerns about global state, it's potential to hinder testing, and complicate code maintenance. However, the pragmatic aspect of software development sometimes requires balancing ideals with the practicalities of existing systems and specific technical requirements. So, while the Singleton pattern is not universally applicable, dismissing it entirely overlooks the complexity and diversity of software engineering challenges.
Another stellar video, the new C# features are cool, I like to see them, but also like to see how we'd do it in the currently LTS supported c#
These will work in 2022 LTS just to be clear. It's only versions before the 2022 alpha release that don't support it. If you were to do it before 2022, you would have to put the Null class and default methods into a base class. Not much different, but a little bit more code. There were some good comments about this already, so I will probably talk about it a bit more in the future! Cheers!
@@git-amend no drama, most of this video I actually understood, maybe I'm making progress :P Your videos have been a real eye-opener for me
Good to see that Unity is starting to use newer version of C#. Wish it was more current. About using new C# features in Unity. I think it is a good idea that you document that such feature is used.
I think I will see how .NET devs are handling these features... they've been around for so long, there must be some good conventions used outside of game dev.
I like the default implementation to make some methods optional in an interface
Yes, it’s nice for that. I also like that you can add a new method to the interface if you have to without breaking your existing code.
good explanation. hope this video gets a good amount of views. Lots of choices for a singleton.
Thanks!
Awesome explanations, as always. Keep it up!
Thanks, will do!
What I love most about these videos is the overlap of concepts. Learning about singletons? How about you practice some command and factory pattern implementations as well! 11/10 - on a sidenote I was able to implement the null singleton interface in 2022 without any issues. So thats pretty cool
Thanks! Yeah, the overlap is something I've been trying to consciously do more often - glad to hear the null singleton worked in '22!
@@git-amend Im here for it! Definitely drives home all of the different concepts and helps with cementing the basic ideas of actual engineering. Please do keep it up! :)
Tested the new interface implementation in Unity 2021.3.26f and it works well. I suppose the new features are somehow compatible with versions earlier. The only way to know is to try it out. Thanks for introducing new interface features.
Very interesting, thanks for sharing that info!
instant subscription... I wish this video existed a month and a half ago.
Welcome!
That had a lot of valuable information, I added the unparenting part to mine now.. never ran into the issue of it not being a top level object, but in case it happens it would be bad if the DontDestroyOnLoad fails to move the object into the DontDestroyOnLoad scene.
Also a really small thing: for the InitializationTime it might be better to use realtime (like Time.realtimeSinceStartup) because sometimes people either have the timeScale set to 0 for longer or just forget about changing it back.
A possible extension of the singletons (not sure if you covered that somewhere yet): Having a ServiceProvider approach where you have a static class that manages singleton access. Consumers request an interface type from that class and get the configured singleton for it. This could for example allow mocking singletons for tests and such.
Although even though I have something like that in my project I haven't had an actual use for it yet.
Interesting, I added a Quiz question about realTimeSinceStartup the other day lol (for March). Those are all good ideas, thanks for sharing them!
Excellent video. Thank you :)
Glad you liked it!
This singleton advice can also be applied to dating, thanks
lol
I love that you bring up the concept of principle of least surprise. I think these new features are amazing, but I think they lead to a ton of confusion and lower readability if implemented without comments explaining what is going on. I am on a project with a more junior dev who is gung-ho about using every modern c# syntactic sugar and feature which is great, but also its important to understand the value of making your code in a way that someone else can expect certain behaviour based on conventions. I think these new features are wonderful and lead to less verbose ways to express the same things, but less verbose often means harder to understand, which can translate to more complex. I think it's a constant tradeoff to consider and if using new fancy things like the c# 8 interface methods, its important to leave some comments describing the intent for clarity. maybe in 5 years it will become the common convention, but until that point older coders will find them confusing and it leads to harder to understand code for them, which on a project with a bigger team makes it less valuable than more verbose code
Thanks for the comment. I agree with all of that, and for the most part, I have been leaning towards only adding a default interface method if the interface is already in use and adding a new method to the interface would cause a lot of problems where it has already been implemented (in a public api at least).
@@git-amend I might be a bit naive in my thinking but I can't think of a situation where adding a method to an interface would cause a problem. Or do you mean more specifically .... having to call a new method from an interface everywhere that references that interface? In my thinking, adding a new method to an interface is free and the risk is zero so im not quite sure im on the same page as you here. not trying to be obtuse or difficult, I just wanna make sure I understand
@@unitydev457 Adding a new method to an interface typically requires all implementing classes to provide an implementation for the new method, which can be problematic in widely-used libraries as it forces all consumers to update their implementations. For example, suppose I have created a popular Unity logging tool and I have an interface ILogger where I want to add a new logging method. By providing a default implementation, I can ensure that existing classes implementing ILogger do not need to change unless they want to override the default behavior. All consumers can upgrade to this latest version of the Library without making any further changes to their code that uses the interface unless they choose to.
@@git-amend oh gosh okay yeah it sounds stupid and obvious now that you explained it. changing the interface means anything implementing it requires adding an implementation of the new methods in that interface. In that sense its not free at all, if you add a method to an interface thats implemented by like 40 or 400 classes in your project, you have to go and add that method and possibly some implementation logic to each of those 40-400 classes. In hindsight it was a really dumb question. I was thinking in reverse, that a new method on the interface doesnt change your consumption of that interface. the things consuming it don't have to do anything new if the interface adds methods. Thank you very much for taking the time to clarify something pretty obvious. I appreciate you helping me be less dumb :)
edit: actually I just realized something that needs clarification, what do you mean by consumer? in my mind consumers would be things that get a reference to the interface and then maybe call a method on it. Is that what you mean when you use the term consumer? or are you referring to things that implement the interface as consumers.
@@unitydev457 No worries!
Hi @git-amend. At 2:27 you say that FindAnyObjectByType() finds objects in any loaded scene. However based on my testing it seems like it only finds them in the active scene or the same scene the calling object is in.
Do you know of any method I could use instead to find an existing instance even if it's not in the active or same scene as the object where I want to access the Singleton?
Edit: Yet strangely FindAnyObjectByType() is able to find the instance after the Singleton's Awake() has been called despite not being in the same or active scene. I'm at a loss D:
The confusion probably comes from the order of execution. In Unity, the `Awake` method is called when a script instance is being loaded, before any `Start` methods are called. This means that even if a GameObject is not active in the scene, its `Awake` method can still be invoked. See docs.unity3d.com/6000.0/Documentation/Manual/execution-order.html
Also, in this particular situation keep in mind that instance is a static variable, meaning that once instance is assigned in the Awake() method of one object, that assignment will persist across all scenes.
Hey. Another nice detailed video about a pattern that many (game) developers will use. I was wondering at 1:48 you say that for the ScoreKeeper Monobehaviour it already is too much boilerplate code (for you) then proceed to create 3 more complex examples that not every developer will get without research, some explanation or descriptive code comments. What are you thoughts on code readability in regards to a team or maybe other external developers in the future?
By boilerplate, I'm referring to repetitive visual clutter. I tend to agree with most of what is written here: stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
Underrated channel!
Thanks!
I figured it out ( i feel like we're best friends now)
What sets you apart is that you explain the CORE CONCEPTS of everything.
You don't just 'code a loop function'
You explain that loop function explicitly rather than implicitly.
You don't talk with the assumption that I know what you're talking about.
Nor do you address me with the assumption that I'm a developer with X years of experience.
You just talk to me as if we're working on this together.
You said:
"Lets get the regulator singleton component"
Now...I could anticipate what you are going to do based on your previous sentence:
"Doesn't matter what sort mode we use, because we're going to get rid of all of them"
So you're going to get rid of all singleton instances next...
nd yet...You made sure to go through each line of code and explain it in such a simple concise way...
We're best friends now.
Haha! Well thanks again for the kind words! I really appreciate it!
4:45 I'm a bit confused on how this bitflag works. You say you use it so the object doesn't get saved with the scene but...why would it? If instantiated objects aren't serialized to the "serialized scene state" that exists in edit mode, why would this flag be necessary?
HideFlags.HideAndDontSave is necessary for objects created at runtime to explicitly prevent them from being saved or appearing in the scene hierarchy, as Unity does serialize some runtime objects into the scene state under certain conditions, like during play mode in the editor.
@@git-amend very interesting, thanks for the reply. Just when I think I'm getting a hang of this engine something new always throws me for a loop, haha
How do you handle the case where you want your singleton to have serialized values ? If it is responsible for instantiating a prefab, I need a serialized field where I can store that prefab. However, if that singleton is auto-generated through AddComponent, that field won't be populated (even worse if you hide the singleton from the hierarchy).
Also, you do not handle the case where the Instance is fetched during unload (ie. scene change for your first singleton, and play mode exit for the other two). If you try to generate a new Instance during scene unload, Unity will send you a nasty error message "you cannot spawn sttuff during unload".
I've been struggling with these issues for a while, I do have some workarounds with helper classes and trickery (mostly preventing generation once Unity enters the unload phase between scenes / on play mode exit), but no elegant solution.
This is something that is being discussed on Discord a little bit, you might be interested in joining that discussion. Generally speaking, for the types of use cases you are describing, you would probably want to have a scene that is primarily for game management where your manager class lives. You would still enforce the singleton constraint, but you never have to worry about unloading your instance or about serialized values. If you need to change the values that were serialized during runtime, you can always offload that work to a service class.
@@git-amend Thanks for answering ! I've actually joined the Discord, could you point me to where it has be discussed ?
@@Yggdr4zyl In the video-discussions channel
Any reason the github repo link doesn't exist anymore? Also never heard of the 'Regulat' before, but nice idea! What is your opinion on utilizing the Lazy type C# provides? While I realize it may not be desired to have a Singleton be instantiated lazily, I feel like it takes care of all the boilerplate one might think about when working with them(like thread-safety), unless I understood it wrong.
I added the ability to import the entire Utility library as a package this week, can still access the code from the root level. I've updated the link: github.com/adammyhre/Unity-Utils
Regarding the Lazy operator, it is certainly an option and useful in many scenarios!
Personally, I use the Persistent Singleton, but with a virtual bool "Persistent" defaulted to false, and if it is true, does the DoNotDestroy. Then you only have one file.
While interface methods may reduce code. Having implementation details in an interface feels wrong to me.
Yes, it does seem a bit counter intuitive. One argument I've heard so far as a pro is that you could add a method to an interface and provide a default implementation so that classes that implement the interface don't all break.
@@git-amend That's the one of the two legimate usages for default interface implementation, the other one being a generic interface inheriting from a non generic one, something like
public interface INonGeneric
{
object GetValue();
}
public interface IGeneric : INonGeneric where T : class
{
T GetValue();
// Default implementation of INonGeneric.GetValue()
object INonGeneric.GetValue => this.GetValue();
}
I was wondering if there was any reason why you shouldn't make the other singletons inherit from your base singleton class and override the methods and mark the properties with a new if necessary.
You certainly could take that approach if you wanted to, and in fact I would say it's worth considering in your own projects if you felt that was useful for long term maintenance or some other reason. Usually though in the context of a UA-cam video, for the sake of communicating the ideas being presented, I do my best to keep it as straightforward as possible.
I see, thank you! I'd really like to thank you for the quality of your videos, which are really professional. I've been looking for months for videos on game architecture in unity, which is often poorly explained, and with you I'm taking it to the next level.
I have been wondering, What design batterin would be best for interactable objects?
Like you pick up a key from the ground and then you can open the door. Key is a picup so i think it was Visitor patttern for pickups. But what pattern for interactable objects?
That's probably a bit too much to describe in a comment, because it wouldn't necessarily require one programming pattern to solve and would mostly fall back onto Unity's functionality. If you want, feel free to request a video on the Discord so I don't forget, and maybe can cover that in the future.
i often declare singleton class in Start() instead of Awake() cause whenever i declare one in Awake, the null reference will happen. I think unity have no execution order for Awake method . Therefore, suppose i wanna reference to another component from another class, it will return null. And i saw that u declare singleton right in Awake, it means that whenever u in play mode, it will initialize that singleton object. I read a method called lazy initialization so instead of declaring right in awake, i create an Instance static variable so that whenever i call that it will initialize singleton class for me. So what do u think about this prob, is it better to initialize singleton in awake or only initialize it when u need.
There's no guaranteed execution order for Awake() unless explicitly defined via script execution order settings. If one script tries to access the singleton instance from its Awake() method before the singleton's Awake() has run, the instance won't be initialized yet, leading to a null reference. My suggestion to you is that you initialize scripts in the Awake method and reference other scripts, including the singleton, from the Start method.
See: forum.unity.com/threads/a-comprehensive-guide-to-the-execution-order-of-unity-event-functions.1381647/
If you cannot do that, I would suggest running the singleton script earlier than others which you can set using Unity's Script Execution Order settings or use the DefaultExecutionOrder Attribute like this:
[DefaultExecutionOrder(-100)] // This script runs before most others
See: uninomicon.com/defaultexecutionorder
@@git-amend thanks for ur answer. Btw, ur vids are so useful :3
Yoo. I have a question. If i have other scripts to the same gameobject that holds the regulator singleton, do they persist between scenes as well?
Edit: I just checked with a script. Yeah anything attached to the regulator singleton object is persistent and don't get reset.
Nice.
Thank you! Cheers!
Hey there, how can I make a persistent object ? like UIManager, MusicManager , LevelManager , to be persistent object ,or load allthis object in some kind of Awake? and check if does exist in the beggining and load automatic with references. thanks.
You might benefit from watching the video about multi-scene loading so that you can have a Bootstrapper scene that contains all your persistent game objects. ua-cam.com/video/JFP-cCFID7o/v-deo.html
I have another question that isn't related to this video. Do you use game managers? Are they different for each project? The more I think about it, the less i see the use of a game manager. Cause most scenes are limited to just one state anyway. Why store the state of the game like "menu" or "in-game" when the menu is its own scene?
I do not typically use a Game Manager per se, but they can be useful sometimes. I think it really depends on the size of your project. In a small project it can be an efficient way to handle global state, but most people want to build games where you need a more robust solution. We'll dive into that when we start talking about additive scene loading.
@@git-amend Sweet. Looking forward to it. If possible, could you explain when do you usually save game data? Idk if the game manger should be in charge of that...
Hi, is there a good way to remove static? The reason is that Unity remove all the static field when recompile during runtime.
It would great if you can make a video about making a structure functions like static but doesn't get deleted when recompile in runtime.
I don't know if I can make a whole video about that, but here's a suggestion. I'm going to assume you mean that when scripts are recompiled in the editor, static fields are reset to their default values. To address this, you could use a ScriptableObject to store the singleton's data, which is then accessed through a MonoBehaviour component that loads the data from the Resources folder. This method ensures data persistence across script recompilations and scene transitions. The MonoBehaviour can dynamically load and reference the singleton data at runtime, thus maintaining a form of global access similar to traditional singletons but circumventing the issue of static fields being reset during runtime recompilation.
@@git-amend great! I think runtime recompile is a really good feature, it would save a a lot of time for bigger project, but there isn't anyone talking about taking advantage of it, like avoiding static
I just wonder when you just wrote the scorekeeper class and it shows all class awake and method gray. How its possible in rider is there any update to do that ? Like autofill from AI or check previous scripts, solutions ?
That's GitHub's CoPilot, and AI Pair Programming tool - you can read about that here: github.com/features/copilot
@@git-amend thank you you are awesome
NEW VIDEOOO GIVE ME MOORE
Too bad I can only make one per week!
@@git-amend I watched the video and it's really great. This design patterns was like a tv series whose new episode I was eagerly waiting for. Like i said I want to watch more of those and thank you for all your work.
This may be more the result of my poor coding elsewhere, but I get a situation where as i close out a scene and delete all the GOs, I seem to still be fetching for Instances that have the plain Singleton extension, giving me the following error:
"Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)
The following scene GameObjects were found:
EventManagerAuto-Generated
QuestManagerAuto-Generated
PlayerEquipmentManagerAuto-Generated"
@git-amend: would you adjust the singleton code to accommodate for these types of issues, or would you say that this means i have serious issues elsewhere 😅
@Brightfield probably happens because you're calling something from the Singleton's Instance in a OnDestroy() or OnDisable() method. I assume you're using the first Singleton type from the video. If so you can simply add the "go.hideFlags = HideFlags.DontSave;" (2:39) in that class as well.
@@MSCardinal
to clarify - another script, Script A, is referring to the Singleton instance, and upon stopping the game, Script A triggers OnDestroy or OnDisable, and tries to for instance unsubscribe its observer method from the Singleton which is already destroyed?
Would I be adding a new line 16 before setting go to instance ?