CLEAN Game Architecture with ScriptableObjects | Unity Tutorial

  Рет қаралды 10,886

Sasquatch B Studios

Sasquatch B Studios

Күн бұрын

Show your Support & Get Exclusive Benefits on Patreon (Including Access to this tutorial Source Files + Code) - / sasquatchbgames
Join our Discord Community! - / discord
--
I've long heard tales of how singletons are 'bad' - but for some time I didn't really understand why...
In this video, I'll exaplin why singletons have a bad rep (despite how easy they are to use) and one potential solution to help you keep your game's architecture CLEAN.
This approach should help you make a game that is:
- More modular
- Easier to edit things
- Easier to debug things
I hope you enjoy!
--
Timestamps:
00:00 - Intro
00:20 - The problem with Singletons
01:37 - Reading our Input from a ScriptableObject asset
04:39 -Replacing the movement code on our player
06:07 - Reading our Input (using a C# generated class) from a ScriptableObject
06:38 - Setting up an Audio Manager with NO references needed.
09:20 - Creating our sound object
10:30 - ScriptableObject Variables
Unite Austin 2017 - Game Architecture with Scriptable Objects
• Unite Austin 2017 - Ga...
---
In need of more Unity Assets? Using our affiliate link is a great way to support us. We get a small cut that helps keep us up and running: assetstore.unity.com/?aid=110...
---
Looking for some awesome Gamedev merch? - sasquatchbgames.myspreadshop....
---
Who We Are-------------------------------------
If you're new to our channel, we're Brandon & Nikki from Sasquatch B Studios. We sold our house to start our game studio, and work full time on building our business and making our game, Veil of Maia.
Don't forget to Subscribe for NEW game dev videos every Monday & Thursday!
Wishlist Samurado!
store.steampowered.com/app/23...
Follow us on Twitter for regular updates!
/ sasquatchbgames
#unitytutorial #unity2d #unity3d

Пікірлер: 81
@AnEmortalKid
@AnEmortalKid 3 ай бұрын
You technically still have dependencies, you just depend on an event stream now instead of a concrete class
@RigorMortisTortoise
@RigorMortisTortoise 3 ай бұрын
I feel like I finally understand the appeal of scriptable objects now, your explanation is so well put together. Thank you!!
@SekGuy
@SekGuy Ай бұрын
Really glad I found your channel. This was the puzzle piece I needed in order to understand how I can improve a lot of things in my project setup.
@hldfgjsjbd
@hldfgjsjbd 3 ай бұрын
Earlier I was all over singletons, but now I am using them less and less and my approach is separate static class with events. One class triggers, all other listen, and it’s so much better, because I don’t have all that dependencies.
@morgansmolder7891
@morgansmolder7891 3 ай бұрын
The dependencies still exist. Now they just occur opaquely through an event dispatch instead of directly through an object reference.
@hldfgjsjbd
@hldfgjsjbd 3 ай бұрын
@@morgansmolder7891 they are centralised indirect dependencies that are not breaking the game, easy to manage, change and adapt, which is the main point. Singletons on other hand are hard dependencies with additional headache of initialisation and existing game objects.
@morgansmolder7891
@morgansmolder7891 3 ай бұрын
@@hldfgjsjbd Whether or not that is better depends on what you are trying to implement. Indirect dependencies are difficult to follow and obfuscate what parts of your code rely on each other. It is also a pain in the ass to maintain an event based interface when the behavior of your systems is constantly in flux, which is pretty much par for the course for gameplay code. In general this singleton vs event system stuff is white noise people like to pull teeth over. You can architect a good system with either approach, and it's very easy to convert one into the other if your code is structured correctly. If your code is structured poorly switching all your singletons to event based dispatch will not solve that.
@hldfgjsjbd
@hldfgjsjbd 3 ай бұрын
@@morgansmolder7891 Surely, I ain’t argue or defend one approach :)
@midniteoilsoftware
@midniteoilsoftware 3 ай бұрын
I'm a big fan of the Mediator pattern and using a single EventBus. Anybody can trigger an event without caring who subscribes to them. Likewise, subscribers don't care who/what triggered the event(s). But I still use ScriptableObjects for configurable data (like audio event data with a collection of audioclips, volume/pitch ranges, etc.)
@MarushiaDark316
@MarushiaDark316 3 ай бұрын
Very cool, though something to be wary of - your scriptable objects won't maintain their values between sessions in a build. So for the health variable, if you wanted player health to persist, you'd have to serialize it out to something like JSON and load the value back into the scriptable object. This can be quite deceiving since it will appear to work correctly in the Editor.
@Sim2322
@Sim2322 3 ай бұрын
That last example where he stores 'current_hp' in a scriptable object made me threw up in my mouth in disgust.
@YoutuberUser002
@YoutuberUser002 3 ай бұрын
Wouldn't just storing the initial value of the variable and setting it back to the initial value when done be the same because thats what I'm doing for my weapon SO for its damage I hace a double damage power up the I just set it back to its original value after the timer has elapsed that's my way doing this but idk if it's right
@Sim2322
@Sim2322 3 ай бұрын
@@KZfaqrUser002 Very best way to use Scriptable Object is to consider them read-only outside the editor. If you have to change them on the fly, something is wrong in the architecture
@YoutuberUser002
@YoutuberUser002 3 ай бұрын
@@Sim2322 oh lol I'd keep most of my SO like that where I just reference the variables and objects from it but just not in that damage case
@Sim2322
@Sim2322 3 ай бұрын
@@KZfaqrUser002 that's the intended use. A classic example is a Unit class that has some health. Your class itself would hold a scriptable object of some Unit, which contains a hp_max variable. The hp_now value would NOT be in your scriptable object, but in your Unit itself. So yeah,basically hp_max goes in the scriptable object, and hp_now would be in the class. You'd really see the benefits either in larger projects, or when you work in teams, but it's a good habit to take as an indie nonetheless.
@bgoldpanda7265
@bgoldpanda7265 3 ай бұрын
I love this architecture ❤️ this is what I structure all the new code I am writing my first game in. Completely changed the way I thought about game development and it makes life a whole lot easier. The only problem I haven’t solved yet is saving the SO objects i instantiate and how to save changes to a file and load them.
@connorjagielski6760
@connorjagielski6760 3 ай бұрын
I see you linked the GDC talk, but it would have been nice if you had at least mentioned it in the video. I mean you even used the same heartbeat sound concept as the talk on scriptable objects.
@dmnoStretch
@dmnoStretch 2 ай бұрын
13:00
@tenko1058
@tenko1058 2 ай бұрын
damn...Unity guides have gotten so much better since I started to use the engine. Wish I had a guide like this for setting up inputs back then.
@sealsharp
@sealsharp 3 ай бұрын
Theres one thing people need to understand about ScriptableObjects is that they work differently in runtime builds than they do in the editor. They are ASSETS. And they work like ASSETS. If you change scenes and the assets in the last scene like textures models and ScriptableObjects are no longer needed, they get unloaded. In the editor, writing into ScriptableObjects changes them in the asset database. In runtime it does not. So perceived persistence which makes ScriptableObjects appear liked "supercharged singletons" in the editor does not 100% apply to runtime.
@dreamcatforgotten8435
@dreamcatforgotten8435 3 ай бұрын
Not true. You can simply set the hideFlags of a SO to HideFlags.DontUnloadUnusedAsset in their Awake, and you'll never have to worry about them unloading and getting Deserialized again with their Editor-assigned default data throughout the lifetime of the Application.
@allenbagwell8034
@allenbagwell8034 Ай бұрын
private void OnEnable() => hideFlags = HideFlags.DontUnloadUnusedAsset; You've gotta manage it directly and call "DestroyImmediate " when you don't need it anymore, but if the intent is for the SO to hang around during the entire length of the game you should probably be attaching it to DontDestroyOnLoad.
@ekm95
@ekm95 3 ай бұрын
Exactly what I want. Thank you so much.
@rechnight
@rechnight 3 ай бұрын
I used Scriptable Architecture a lot and was so hyped in the beginning, was making everything into SOs, events, variables, even references to script instances, until my project was full of SOs and I was getting lost of what was being referenced where... Now I just use a service locator...
@GabrielBigardi
@GabrielBigardi 3 ай бұрын
A service locator is better but it's still bad and considered an anti-pattern, i recommend using a minimal dependency injection library or making your own.
@rechnight
@rechnight 3 ай бұрын
@@GabrielBigardi Agree with you, I keep the service locator usage to a minimum necessary, mostly for the global services: Events, Audio System, Pooling, Saving and so on, and also instances of services specific to an entity. I do use a kind of Dependency Injection, but I mostly inject from the Service Locator for services and from an Entity Manager for components.
@outoftime9071
@outoftime9071 3 ай бұрын
In your video about seamless loading, how did you make the scene to load when it traverses backwards through the scene? I can make it work forwards but not backwards
@ggwp8618
@ggwp8618 3 ай бұрын
Love you bro. Sharing some quality knowledge. Can you please cover jobs sytem? I have learnt alot with your tutorials
@Diablokiller999
@Diablokiller999 3 ай бұрын
Pretty good but for events that fire often (like move), I would use normal C# events instead since UnityEvents tend to take longer and more ressources, at least in my benchmarks. Yeah it's some premature optimization for sure, but I go with if I need to assign in via Inspector use UnityEvents, else C# events. But if you already have UnityEvents all over your project, maybe stick with it for readability?
@jerradbieno6810
@jerradbieno6810 Ай бұрын
How does using this approach for inputs work for things like the current mouse position? Do you have to send/subscribe an event everytime the mouse position changes? I'm using the singleton inputmanager style approach so I simply update a public field on Update to store the mouse position, but I'd love to use this SO approach for inputs.
@ragerungames
@ragerungames 3 ай бұрын
Great video! I always prefer using scriptable object.. they are very powerful in many cases!
@risingforce9648
@risingforce9648 2 ай бұрын
this approach is to avoid only singleton ? or make an event scriptab object system? thanks
@bgoldpanda7265
@bgoldpanda7265 3 ай бұрын
Also could you please make a tutorial on assembly definitions 🙏
@RodriGGod
@RodriGGod 2 ай бұрын
Please make a complex inputsystem generating c# class Show us tap, hold, the combinatoon of 2 button, aim with mouse and controller at the same time. Thank youuuu
@_jonathancollins
@_jonathancollins 3 ай бұрын
I literally was working on input this morning and this will come in handy! Does this method of handling input allow for custom key bindings?
@AnEmortalKid
@AnEmortalKid 3 ай бұрын
Yes like key rebinding ?
@GabrielBigardi
@GabrielBigardi 3 ай бұрын
If you mean changing ScriptableObject's to persist key bindings, then no. They are simply static assets and should be used like that, it shouldn't change at all.
@iosandro43
@iosandro43 3 ай бұрын
i'm a big fan. I like your tutorials. I'm developing an app using unity. I encounter scroll rect( list of images one below the other) runs laggy in some mobile devices. I hope make a tutorial covering this issue. I TRIED ALMOST ALL SOLUTIONS I FOUND ON THE NET. but, I believe your lecture will the one which will help me the most. looking forward to your reply
@EudaderurScheiss
@EudaderurScheiss 3 ай бұрын
i ended up rewriting the scroll rect from unity sources and smartly enable / disable it, while also optimizing it. whole unity UI is garbage and designed for desktop. shit i even rewrote the touch handler, because touching the screen causes 15fps drops. they literally recaculate the whole hierarchy for touchable inputs and bubble those events up. no issue on desktop, but mobile thats just stupid. precache touchable areas and calculate the touches only on changes, not calculate every ui elements recttransform on touch. after all optimizations i regret not creating my own ui system based on sprites, with a camera on it. canvasscaler is also crap. horizontalgroups. verticalgroup all crap. even the textmeshpro has issues, since every textfield adds an listener, that listenes every frame for canvas scale changes. animations & animators invalidate the whole thing, and lead to recaclulation. particles are not working. oh and draw calls are by hierarchy orderning, so batching does not work. (ok not much of an issue in rly new phones anymore, still just bad) oh and dont forget the camera setup, for screen space overlay and screen space camera is also not working idealy. and its annoying when debugging, because you click on every invisible ui element in the editor. ui in unity is bad in every way. optimizing it means rewriting it and even then its mediocre. -- sorry for the rant i got ptsd from that system
@iosandro43
@iosandro43 3 ай бұрын
Can you share the touch handler you wrote with me? Thank you for replying
@FyresGames
@FyresGames 3 ай бұрын
Nice. Another way I'm using SO to make the code more modular is using it to pass events. Kinda the same as you I can drag in the player, drag in the input or delete them in play mode and no error. Question about the audio manager. How do you make a music track persist between scene with that way?
@owencoopersfx
@owencoopersfx 3 ай бұрын
You would need to expand on the example quite a bit to really handle it nicely, but at the core of it you’d just run DontDestroyOnLoad and pass in the instantiated GameObject that has your music AudioSource.
@GabrielBigardi
@GabrielBigardi 3 ай бұрын
Please don't use this to pass events, specially UnityEvents, on a real project it will make your life A LOT harder, debugging becomes a hell, naming and organizing your SO's too, not to say about keeping tight coupled references of them on each script that will use them. Do it the right way and use dependency injection and depend on abstractions instead of concrete classes.
@FyresGames
@FyresGames 3 ай бұрын
@@GabrielBigardi I'm not sure what's the problem with debuging? A debug log or error will lead me all the way down to the source even if there's a SO event (Not unityevent) in the middle. Its true I need to add them on each script that need them. In any case could you explain in more details your way so even if the player and the inputManager are on 2 different scenes (Player is a addon scene) they will work fine? What I got for now is both the input manager and player with the SO events on them for the inputs. The player script got DI into each of its state to use the SO events.
@GabrielBigardi
@GabrielBigardi 3 ай бұрын
@@FyresGames If the player and the input manager are on two different scenes, using ScriptableObjects might not be the best solution, Unity scene management system provides other ways to communicate between scenes, such as using DontDestroyOnLoad. ScriptableObjects as events introduce an extra layer of indirection, and while it’s true that a debug log or error can lead you to the source, the indirectness introduced by ScriptableObjects can still complicate debugging. It can be harder to trace the flow of data and control, especially in larger projects with many scripts and ScriptableObjects. ScriptableObjects persist their state across game sessions in the editor, which can lead to unexpected behavior and differences from playing on Editor and playing the real game's build. While ScriptableObjects events can work fine for smaller projects, they might not scale well for larger ones. If you have many scripts that need to listen to the same event, you’ll need to add the ScriptableObject event to each of them. This can become cumbersome and error-prone as your project grows.
@owencoopersfx
@owencoopersfx 3 ай бұрын
Nice examples. I really like the SO AudioManager approach. Learning how to effectively use Scriptable objects is one of the best level-ups for a Unity dev.
@lizardjoshack1839
@lizardjoshack1839 3 ай бұрын
And what is the difference between Scriptable Object and Static Solid?
@EarthtideStudios
@EarthtideStudios 3 ай бұрын
Can you do this using the old input system? As that's what we're using for our build :)
@AnEmortalKid
@AnEmortalKid 3 ай бұрын
Yeah probably. Your Input Manager scriptable object defines what events it sends. It listens to the Input system and fires those events when it makes sense. I feel that should work
@markguyton2868
@markguyton2868 3 ай бұрын
As a Godot user, I wish there were more tutorials like this for that engine. Then again, I don't comprehend code very well so I'm not sure how much of a difference it would make for my current situation.
@snarf8115
@snarf8115 3 ай бұрын
I’m still watching the video, currently at 6:49. However you said using generated C# class doesn’t work for your game/style(?). Could you elaborate/show an example of why that is? When I first started learning the “new” input system, using the C# generated class was/is much cleaner and easier to use.
@snarf8115
@snarf8115 3 ай бұрын
Also I really love the idea of you creating tutorials like this. I love the sped up, not skipped or normal speed code that you write as you explain it or if you explain it beforehand. one suggestion is to add comments to functions or certain code (as you’re typing them) so if we want to refer back to the video and let’s say want to read instead of listening, we have comments to go through. Or it can help to compare to what you’re saying and what the comment says. nonetheless, fantastic video so far. I am going to finish it up.
@dutchiewonderz6553
@dutchiewonderz6553 3 ай бұрын
Great video just wondering if you could make a small adjustment in the future and avoid adding the rolling Early Access Supporters on the screen. It's very distracting while trying to learn from your video. Perhaps a static runner (footer image) without the text changing. Again great video and I appreciate all the hard work you put in - looking forward to more down the road.
@fukodafufu6662
@fukodafufu6662 3 ай бұрын
Really cool video, and this type of architecture is indeed really cool to playtest and separate things. But I have to disagree and give a warning on the "easier to debug" statement, which I believe is false. Since a lot of stuff will be working with event and aren't directly linked to each other, the bigger your game is, the harder it will be to keep it understandable and easy to debug. And even more if you start working with other developers that'll have a hard time to understand why and what's going on.
@GabrielBigardi
@GabrielBigardi 3 ай бұрын
I tried using this pattern on a project few years ago so i 100% agree with you, it makes things a lot harder to debug and on a real project it's not maintainable at all, i even made a comment talking about using SO's this way is actually worse than using singletons but i think he removed or something.
@fukodafufu6662
@fukodafufu6662 3 ай бұрын
@@GabrielBigardi Glad to see someone that finally get it! I think most of the people loving this architecture are either making really small games, or are switching game before even finishing them. But I still think it's pretty cool to base a part of your architecture on it for the fast prototyping, like any pattern : Those are not omnipotent, they are good if you use them well for a specific context. People tends to forget that.
@nnx7631
@nnx7631 3 ай бұрын
Hey man, I've seen most of your videos and I love them. I see that scriptable objects are really good way of creating a whole game, however I still cant grasp the idea behind their power. However, I saw your tutorial for FSM on enemies + scriptable objects. Could you maybe in future create a tutorial for FPS character that uses FSM with the new unity input system + scriptable objects? I think it will be super beneficial to many people because there is no solid example out there how to actually do it correctly. Thank you!
@dabmaster6874
@dabmaster6874 3 ай бұрын
Scriptable objects is usual a way to contain data/behaviours. Its advantage is that the modification you do to the data within the play time session or in the editor/play mode are permanent. SO statemachine is one way to share data and behaviours between many scripts. In the case of a fps controller, the use of SO is overkill if used for behaviours. But a scriptable object for the data could help you test many configurations of the data you use within your fps controller. You can try using different data presets for movement speed, rotation speed , jump height or maybe different weapon data presets that use fire rate, muzzle flash and bullet types to make a shotgun, minigun, smg... For the input system you could also include SO to make different input keys that you can plug and play, I used and it was a very useful way to make modular pieces of code/ data driven behaviours
@harddev9181
@harddev9181 3 ай бұрын
TRY Game dev breakdowns there r good
@foxes-oy6ip
@foxes-oy6ip 3 ай бұрын
Just add a simple null check before referring to singletons can solve the dependancy problem already
@dreamcatforgotten8435
@dreamcatforgotten8435 3 ай бұрын
I don't think you understand what solving dependency issues means if you think null checking is the solution.
@foxes-oy6ip
@foxes-oy6ip 3 ай бұрын
@@dreamcatforgotten8435 I thought about it again. What he did was make the script depend on an SO file instead of the singleton. Why not just check if the singleton is null and save all this trouble? Also, if the script can in fact run independently, the best thing to do is to explicitly write out how it should handle the situation when the singleton does not exist, so as to avoid logic errors.
@ayyappaj8111
@ayyappaj8111 Күн бұрын
Is this a fad? Or I'm only feeling it? 1. SO's are no more than "Drag-able Singletons" when you try to modify the contents of them at runtime for data sharing. 2. SO’s better if they are read-only. 3. Sad to see no one addresses about the probelms and many resources along with popular Unite 2017 talk (Ryan Hipple), Chop Chop unity project, some assets and lots of youtube videos uses/favours read-write SO’s (SO variables). 4. Using SO’s as events is just extra code with a benefit of making them draggable in unity editor. 5. De-coupling between objects is as important as knowing which depends on what. 6. If your project is “small”, SO’s runtime variables are an easy and quick option than DI route. 7. Dependency Injection is still the way to go when it comes to have maintainable code.
@CyberAngel67
@CyberAngel67 3 ай бұрын
SO's are not the best use for this, as they can lose scope fairly easy.
@newsystem3667
@newsystem3667 3 ай бұрын
Now lets talk about performance
@OIndieGabo
@OIndieGabo 3 ай бұрын
Nice. Can you start? What is concerning in this case?
@Coco-gg5vp
@Coco-gg5vp 3 ай бұрын
First
@Sim2322
@Sim2322 3 ай бұрын
Ok guys. DO NOT DO THIS. Especially the very dumb last example where he stores a 'current health' variable in a scriptabe object. I repeat: NEVER, UNDER ANY CIRCUMSTANCES, DO THIS. Your project will break, it's that simple.
@dreamcatforgotten8435
@dreamcatforgotten8435 3 ай бұрын
I think it depends on the project and how it is used. If the number of Players is static, and there is no chance of scaling the project up to multiplayer, it's reasonable to have data that would typically be considered 'local' to be on a SO. However, for Enemies/Multiplayer Scenarios/etc - things that should be dynamic - it makes much more sense to have current health be localized to a component of that entity.
@Cooo_oooper
@Cooo_oooper 3 ай бұрын
This tutorial offers nothing new compared to the 2017 Unite talk this was taken from
@goldone01
@goldone01 2 ай бұрын
First of all, I'm sorry, but why do you have to he so negative? Secondly, if you've already watched the unite talk, you are not the target audience. And I am surprised how it isn't obvious that a 13 minute, easy to follow youtube video has a different purpose than a more than one hour long unite talk.
@Cooo_oooper
@Cooo_oooper 2 ай бұрын
@@goldone01 It's not negative, it's critique. It's literally the same content and code as in the Unite talk which already explains it in an easy way
@de0o0
@de0o0 Ай бұрын
I don't like that architecture, you are using singletons, you do have dependencies and your data is not separated from logic
SPEED UP Your game development with these 10 TOOLS! (Unity)
13:25
Sasquatch B Studios
Рет қаралды 8 М.
10 Unity Tips You (Probably) Didn't Know About
7:09
Sasquatch B Studios
Рет қаралды 7 М.
Русалка
01:00
История одного вокалиста
Рет қаралды 6 МЛН
I Can't Believe We Did This...
00:38
Stokes Twins
Рет қаралды 108 МЛН
아이스크림으로 체감되는 요즘 물가
00:16
진영민yeongmin
Рет қаралды 56 МЛН
How I Would Start Gamedev (if I had to start over)
9:02
Sasquatch B Studios
Рет қаралды 16 М.
Events & Delegates in Unity
13:20
Game Dev Beginner
Рет қаралды 50 М.
The LIES You've Been Told About Gamedev
9:41
Sasquatch B Studios
Рет қаралды 10 М.
7 DEVS Make a GAME without COMMUNICATING! (centipede edition)
17:16
Blackthornprod
Рет қаралды 1 МЛН
This Problem Changes Your Perspective On Game Dev
25:51
Jonas Tyroller
Рет қаралды 363 М.
⚡ Всё про события в Unity 3D
21:38
Emerald Powder
Рет қаралды 103 М.
OPTIMIZE your Unity game using these performance tips | Tutorial
11:20
Sasquatch B Studios
Рет қаралды 10 М.
The Power of Scriptable Objects as Middle-Men
17:41
samyam
Рет қаралды 119 М.
20 Advanced Coding Tips For Big Unity Projects
22:23
Tesseract
Рет қаралды 165 М.
НУБ ИЩЕТ ЖЕНУ В GTA SAMP
22:34
STRAYF
Рет қаралды 685 М.
Как сбежать от РОДИТЕЛЕЙ в Schoolboy runaway???
12:26
idontfirst GAME
Рет қаралды 1,1 МЛН