CLEAN Game Architecture with ScriptableObjects | Unity Tutorial

Поделиться
HTML-код
  • Опубликовано: 27 ноя 2024

Комментарии • 83

  • @hldfgjsjbd
    @hldfgjsjbd 7 месяцев назад +8

    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 7 месяцев назад +3

      The dependencies still exist. Now they just occur opaquely through an event dispatch instead of directly through an object reference.

    • @hldfgjsjbd
      @hldfgjsjbd 7 месяцев назад +4

      @@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 7 месяцев назад +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 7 месяцев назад +2

      @@morgansmolder7891 Surely, I ain’t argue or defend one approach :)

    • @midniteoilsoftware
      @midniteoilsoftware 7 месяцев назад +1

      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 7 месяцев назад +19

    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.

    • @S_Tadz
      @S_Tadz 7 месяцев назад +6

      That last example where he stores 'current_hp' in a scriptable object made me threw up in my mouth in disgust.

    • @S_Tadz
      @S_Tadz 7 месяцев назад +4

      @@RUclipsrUser000 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

    • @S_Tadz
      @S_Tadz 7 месяцев назад +2

      @@RUclipsrUser000 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.

    • @S_Tadz
      @S_Tadz 7 месяцев назад

      @@RUclipsrUser000 a little advanced for a YT comment, but look at putting your stats in a struct, and overload the * or + operators, so you can do something like
      damage= myStats*myBonusStats
      Where both myStats and myBonusStats are of your Stats struct type.
      Much, much easier to handle after the setup, I guarantee you.

  • @AnEmortalKid
    @AnEmortalKid 7 месяцев назад +24

    You technically still have dependencies, you just depend on an event stream now instead of a concrete class

    • @rohitmore1729
      @rohitmore1729 Месяц назад

      Woow, you are technically still dependent on the c# and unity program. Hehe

  • @RigorMortisTortoise
    @RigorMortisTortoise 7 месяцев назад +2

    I feel like I finally understand the appeal of scriptable objects now, your explanation is so well put together. Thank you!!

  • @rechnight
    @rechnight 7 месяцев назад +5

    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 7 месяцев назад +1

      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 7 месяцев назад +1

      @@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.

  • @sealsharp
    @sealsharp 7 месяцев назад +13

    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 7 месяцев назад

      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.

    • @BalrogBait
      @BalrogBait 6 месяцев назад

      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.

    • @hello.4693
      @hello.4693 14 дней назад

      So... long story short:
      You can only change them in the current scene, in the next scene or scene reload they will be reset to their default values ​​set in Unity before the build.
      Right?

  • @JasonVerro
    @JasonVerro 17 дней назад

    This tutorial is tied to the "How to Build a 2D Platformer" tutorial. If you are having difficulty with this tutorial it might be a good idea to build the 2D platformer first. This should make this tutorial easier to understand.
    Thanks

  • @connorjagielski6760
    @connorjagielski6760 7 месяцев назад +6

    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.

  • @tenko1058
    @tenko1058 6 месяцев назад

    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.

  • @bgoldpanda7265
    @bgoldpanda7265 7 месяцев назад

    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.

  • @SekGuy
    @SekGuy 5 месяцев назад

    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.

  • @iosandro43
    @iosandro43 7 месяцев назад +1

    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 7 месяцев назад +1

      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 7 месяцев назад

      Can you share the touch handler you wrote with me? Thank you for replying

  • @ggwp8618
    @ggwp8618 7 месяцев назад +1

    Love you bro. Sharing some quality knowledge.
    Can you please cover jobs sytem?
    I have learnt alot with your tutorials

  • @ragerungames
    @ragerungames 7 месяцев назад

    Great video! I always prefer using scriptable object.. they are very powerful in many cases!

  • @SceneOfAction
    @SceneOfAction 2 месяца назад

    It's not every day you come across an authentic professional. Today is that day.

  • @outoftime9071
    @outoftime9071 7 месяцев назад +1

    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

  • @Diablokiller999
    @Diablokiller999 7 месяцев назад +2

    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?

  • @owencoopersfx
    @owencoopersfx 7 месяцев назад +1

    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.

  • @bgoldpanda7265
    @bgoldpanda7265 7 месяцев назад +1

    Also could you please make a tutorial on assembly definitions 🙏

  • @ayyappaj8111
    @ayyappaj8111 4 месяца назад +1

    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.

  • @ekm95
    @ekm95 7 месяцев назад

    Exactly what I want. Thank you so much.

  • @dutchiewonderz6553
    @dutchiewonderz6553 7 месяцев назад +2

    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.

  • @Surkk2960
    @Surkk2960 7 месяцев назад

    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.

  • @fukodafufu6662
    @fukodafufu6662 7 месяцев назад +1

    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 7 месяцев назад +1

      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 7 месяцев назад +1

      @@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.

  • @RodriGGod
    @RodriGGod 7 месяцев назад

    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

  • @snarf8115
    @snarf8115 7 месяцев назад +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 7 месяцев назад

      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.

  • @nnx7631
    @nnx7631 7 месяцев назад +1

    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 7 месяцев назад +1

      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

  • @_jonathancollins
    @_jonathancollins 7 месяцев назад

    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 7 месяцев назад

      Yes like key rebinding ?

    • @GabrielBigardi
      @GabrielBigardi 7 месяцев назад

      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.

  • @jerradbieno6810
    @jerradbieno6810 6 месяцев назад

    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.

  • @EarthtideStudios
    @EarthtideStudios 7 месяцев назад

    Can you do this using the old input system? As that's what we're using for our build :)

    • @AnEmortalKid
      @AnEmortalKid 7 месяцев назад

      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

  • @AstralNostalgia
    @AstralNostalgia 6 месяцев назад

    this approach is to avoid only singleton ? or make an event scriptab object system? thanks

  • @SaudBako
    @SaudBako 4 месяца назад

    You just created a singleton with scriptableobjects 9:00

  • @lizardjoshack1839
    @lizardjoshack1839 7 месяцев назад

    And what is the difference between Scriptable Object and Static Solid?

  • @foxes-oy6ip
    @foxes-oy6ip 7 месяцев назад

    Just add a simple null check before referring to singletons can solve the dependancy problem already

    • @dreamcatforgotten8435
      @dreamcatforgotten8435 7 месяцев назад +1

      I don't think you understand what solving dependency issues means if you think null checking is the solution.

    • @foxes-oy6ip
      @foxes-oy6ip 7 месяцев назад

      @@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.

  • @FyresGames
    @FyresGames 7 месяцев назад

    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 7 месяцев назад

      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 7 месяцев назад +1

      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 7 месяцев назад

      @@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 7 месяцев назад

      @@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.

  • @harddev9181
    @harddev9181 7 месяцев назад

    TRY Game dev breakdowns there r good

  • @Cooo_oooper
    @Cooo_oooper 7 месяцев назад +11

    This tutorial offers nothing new compared to the 2017 Unite talk this was taken from

    • @goldone01
      @goldone01 7 месяцев назад +11

      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 7 месяцев назад +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

    • @falgunpawar
      @falgunpawar 8 дней назад

      Ohhh, but tbh Idk i can't watch the whole unite videos..these short ones are good...I'll still check that

  • @S_Tadz
    @S_Tadz 7 месяцев назад +4

    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 7 месяцев назад

      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.

  • @CyberAngel67
    @CyberAngel67 7 месяцев назад +1

    SO's are not the best use for this, as they can lose scope fairly easy.

  • @de0o0
    @de0o0 5 месяцев назад +1

    I don't like that architecture, you are using singletons, you do have dependencies and your data is not separated from logic

  • @newsystem3667
    @newsystem3667 7 месяцев назад +1

    Now lets talk about performance

    • @OIndieGabo
      @OIndieGabo 7 месяцев назад +3

      Nice. Can you start? What is concerning in this case?

  • @Coco-gg5vp
    @Coco-gg5vp 7 месяцев назад

    First