Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Scriptable Object Architecture and triggering events/methods from data

Discussion in 'General Discussion' started by atcnk, Aug 26, 2022.

  1. atcnk

    atcnk

    Joined:
    Apr 10, 2020
    Posts:
    2
    Hello everyone. This is my first thread, I hope this is correct forum. :)

    I have question about Scriptable Object Architecture. If you don't know what SOA is, i strongly recommend you watch this talk. It's really inspiring.



    Lets say i have 'health' float variable. In this architecture, i need to reference this health data to scripts that will use it.

    Lets also say i have a method that should be called only when this health data is changed. I can easily check if health data is changed on that script's Update method. But I'm trying to avoid Update method as possible for better performance.

    Before i know about SOA, I used to trigger methods when this float data is being set. But is it good approach for this architecture? Should data be used only to get data or is it okey to use it for triggering? Or checking if health data is changed on Update method is not that bad for performance? :confused:

    Or is there any other way to solve this problem using this architecture?

    Thanks! :)
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    You can use a callback to broadcast when the value changes. I wrote an example here: https://forum.unity.com/threads/ui-not-tied-to-player-or-gamecontoller.1324710/#post-8379801

    If you're not familiar with delegates, time for some studying!

    Word of warning though, don't go overboard with tons of individual value scriptable objects. Best to take the video as small example of what you can do with scriptable objects, and build upon that.

    I find scriptable objects work well as containers of various data fit for purpose, rather than singular values.
     
    atcnk and Andy-Touch like this.
  3. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,196
    In this talk, he also goes into detail on SO events. You can mix the two: SO stores your variable, SO Event is used to forward changes to subscribers.
     
    atcnk likes this.
  4. Andy-Touch

    Andy-Touch

    A Moon Shaped Bool Unity Legend

    Joined:
    May 5, 2014
    Posts:
    1,448
    IMO, this architecture works fine for a small game and a small team but drops off a cliff as soon as you use it at scale or for anything involving a ton of dynamic systems (so... most games)

    Scriptable Objects are very good as editor-friendly configs for tweakable game data (like settings of a character controller, a container for SFX data or stats of a weapon). Anything extra (like what ryan gives examples for in that famous talk) will bite your project as it grows.
     
  5. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    can you give an example of where it becomes a problem at scale?

    and what is a dynamic system? i googled but the results i see probably aren't what you mean.
     
    atcnk likes this.
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    One I can think of is that there's no built in way to determine how many objects are referencing a particular SO. So when your event systems are this web of visually disconnected objects, it becomes quite hard to know what is doing what and where.

    Kinda thing where some more robust sub-logic systems probably work better in larger projects, such as a high-level node editor to handle common gameplay stuff.
     
    atcnk and BIGTIMEMASTER like this.
  7. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,148
    Aren't scriptable objects another Unity invention for things that have always been done some other way (so I've stayed away from them) - maybe they are great, but maybe you should just store data in any other form (xml, csv, JSON, text, WAD!) and load it into a static/singleton/etc class at runtime.
    Use delegates for data change events.
    If you can do it in standard C# without Unity-specifics - do it!
     
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    Well, none of those you can just drop into a field in the inspector. The fact Scriptable objects are UnityEngine.Object's is what makes them so versatile, that they're fully supported and serialisable by the inspector.
     
  9. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,148
    Yes it is nice from an editor point of view, true.
    But if you want designers, testers and other non-Unity users changing those values, do you have a problem?
     
  10. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    Not really? There's a million and one tools to edit large numbers of scriptable objects easily.
     
    xVergilx and atcnk like this.
  11. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,337
    It feels like you're overthinking it.

    If your health is property, you can create a C# or Unity event called "onHealthChanged" and trigger it when the value is altered.

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/event

    This is somewhat similar to Qt's signal/slot approach.

    I'm not sure if it is WORTH it, however. Scriptable objects were made for simple inspector support, and inspector works on fields, not properties. So to support your tracked property, you'd need to write a custom inspector.
     
    Rodolfo-Rubens and angrypenguin like this.
  12. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    4,196
    Btw, there are a gazillion implementations of the ScriptableObject Architecture on github alone.

    One of the most advanced is this one:
    https://github.com/unity-atoms/unity-atoms

    Also very popular:
    https://github.com/DanielEverland/ScriptableObject-Architecture

    And a couple more:
    https://github.com/SolidAlloy/GenericScriptableArchitecture
    https://github.com/chark/scriptable-events
    https://github.com/kadinche/Kassets

    Just because in case you don't feel like going into wheel invention mode. ;)
    At a minimum there's a ton of nice little solutions for just about everything around this architecture.

    When it comes to complexity: I have had SOA in just one large project (team of 4 working on it for 3+ years) and there it was mainly used to take a lot of grunt work and potential points of failure out of the UI. We had many different modes that affected UI (can't do this in that mode, limit this slider to other values based on some other setting) and different UI modes as well where the same functionality was accessible via drop-down menus, world-space UI (hotspots), VR specific UI and then VR + LeapMotion hand controlling GUI.

    Let's just say without SOA it would have caused TREMENDEOUS headaches, and in fact it did until we added SOA just about one year into the project. Until then, it was common for UI to break, based on modes or changes to business logic, which aggravated the client (are you even testing? :rolleyes:).

    I would hesitate using SOA for anything BUT decoupling the UI or potentially some other kind of "external source" like synchronization with a Web or DB API (ideal for caching and using local value store for testing). I wouldn't want it in game logic, unless we'd be dealing with a plethora of (configurable) variables.
     
    LasOne and Voronoi like this.
  13. liquify

    liquify

    Joined:
    Dec 9, 2014
    Posts:
    175
    I think the one used in Unity Open Project 1 is a bit different than what Ryan Hipple presented, since the event channels and the connected scripts in UOP 1 are still trackable in Visual Studio IDE?

    As one of UOP 1 developers, do you still recommend the ScriptableObject event channel architecture for a sizeable game project? Or better stick with singleton or Dependency Injection?

    I'm also worried that those patterns are no longer useable for Unity DOTS in the future.
     
    atcnk likes this.
  14. Andy-Touch

    Andy-Touch

    A Moon Shaped Bool Unity Legend

    Joined:
    May 5, 2014
    Posts:
    1,448
    I did not work on UOP1. :) (Except for contributing 2 shaders)
     
    atcnk and liquify like this.
  15. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,493
    My personal approach is to ask the question: Is this data needed or defined in the editor outside of playmode?

    If yes, consider SOs (consider does not mean "always use").

    If no, then use game objects.

    The current health variable is clearly only meaningful in playmode, so not sure why to consider SOs.


    Yeah singletons, static variables and sometimes prefabs were the solutions before but since SOs, they have become unncessary workarounds with inferior usability unless you had some custom or 3rd party tooling for this.

    Give SOs a chance :)
     
    andyz likes this.
  16. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,185
    From what I remember of the talk the primary purpose of Ryan Hipple's approach is to tie systems together not to be a way for the people you listed to change the properties of the systems. That said if you wanted to do that you could just have the SOs get their default values from external files.
     
    Last edited: Aug 26, 2022
  17. atcnk

    atcnk

    Joined:
    Apr 10, 2020
    Posts:
    2
    Thank you all for answers. It's great to read different opinions.

    Thats the anwser that i'm looking for, thanks. Time for some studying! :)
    Hmm. Actually I work on a small games (hypercasual/casual mobile games) with a small team. For now I'll stick with this archutecture. Thank you so much for your answer. :)

    @CodeSmile I'll check these implementations and also thanks for sharing your experience. :)

    @DragonCoder I really like your approach, it's good and simple.
     
  18. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Yes, these are just Unity's version of storing data that isn't a part of a scene. However, I'd argue that they're great precisely because they save you from needing to do that other stuff in most cases.
     
    spiney199 likes this.
  19. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,886
    Important to point out that he also very clearly talks about how its good for opening up things for designers not necessarily actually shippable systems in a released game. I think ryan intended this to be a way to give designers a tool to express their designs, with programmers "cleaning" it up and making it all "work" later on.

    I cant imagine ever using this sort of architecture in anything shippable beyond say a game jam sized game.
     
    Andy-Touch likes this.
  20. Voronoi

    Voronoi

    Joined:
    Jul 2, 2012
    Posts:
    571
    I just finished a very UI heavy project and it was not pretty! I would love to see an example of how a SO could be used to simplify exactly what you are talking about.

    What I did was a nightmare of hooking up buttons to suit the mode. For example, a button to show a screenshot gallery would open a gallery/grid panel of thumbnails (same button disabled the main UI), but if there were no thumbnails, I need a different tutorial/information screen to open. The close buttons on both closed their own panel and 'enabled' the main UI again.

    That worked fine for one, simple UI but then the client needed many more 'modes' and it's a delicate mess of hooking up this to that, etc. Does Unity have a single authoritative example for how to set up UI's correctly that will scale?

    I feel like the UI Toolkit will ultimately do this best, so when/if that tutorial is ever writting hopefully it will use UI Toolkit. Of course, I had to use animated UI's and so couldn't use UI Toolkit. This is why having 3 built-in UI systems is a PITA, just pick one already!
     
  21. Andy-Touch

    Andy-Touch

    A Moon Shaped Bool Unity Legend

    Joined:
    May 5, 2014
    Posts:
    1,448
    Based on the current roadmap and answers from the UI Team in the recent Dev Blitz event, I wouldn't expect to see UI Toolkit feature parity with UGUI until atleast 2024 (which makes it 2025 for LTS). Probably better off sticking with UGUI.
     
    MadeFromPolygons likes this.
  22. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    To me, that sounds like a lot of logic on the button that the button probably shouldn't be trying to deal with. How many different object references does it need to decide what content to display?

    I'm a big fan of the "Single Responsibility Principle", which in this case would have the button only responsible for opening the correct screen, and then the screen being responsible for displaying the correct content inside itself. That alone would save quite a bit of error-prone work when it comes to creating and maintaining buttons.

    It also means that when Screen X is misbehaving I can see the relevant code attached to Screen X, rather than having to look for external objects which are telling Screen X what to do.

    Do note that this video is ~5 years old, and I'm pretty sure that it pre-dates some built-in solutions to some of the problems it solves. So my number one suggestion is to ensure you understand the problem that each of these things is solving for you, and see if other changes since the video was made might offer better solutions.

    As one example, he talks about minor variations between different enemies being a pain because prefabs can not share data. That's not true any more, Unity has Prefab Variants to do exactly this, so that's an entire class of use cases for which I think this is now outdated.

    As another example, C# has the concept of "Interfaces" which exists specifically to solve the problem of references having to be explicitly typed. Unity didn't support it at all in the past, and it unfortunately still doesn't in the Inspector, but it's been supported by GetComponentOfType<> for a while now, which means that we can use it when looking for objects whos' events we want to listen for.


    I do wonder if some of that is because the examples are being taken out of context?

    The examples in that talk are trivial, and because of that he can have his fields wrapped in SOs which are stored as Assets which can be clicked on in the Project view, which is neat. But he also points out that they can just exist in memory, which I imagine is the case 99% of the time. I strongly suspect that when an enemy spawns it just instantiates its own, memory-only FloatVariables for relevant fields. Showing up in the Project view is neat, but is only relevant for stuff that you want to put in a designer's hands, and is probably an unwanted overhead elsewhere.

    The important part is this:
    upload_2022-8-29_11-14-27.png

    Yes, he shows how to get that reference by dragging it from the Project view, and I've often scratched my head when people showed me this as a great new trick they'd learned. But from watching the video I wouldn't be populating most of them like that (outside of test scenes, which he makes great points about), I'd be doing some kind of dynamic lookup at initialisation time and/or when a relevant event is raised.

    The concept of "Runtime Sets" is nothing new, but at first glance I do like the idea of having references to them as asset-type objects which can be dropped in the Inspector. I'd have to experiment with the idea a bit to see if it's actually any nicer than just having plain C# objects to do the same job, which is what I currently do.
     
    Voronoi, NotaNaN and neginfinity like this.
  23. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    This is kinda on and off topic, but I've just realised that prefab variants are akin to that strange prototype pattern.

    I've always found it quite an interesting pattern but have A: haven't had a situation where I thought I could use it, and B: have no idea how I'd actually do it code, save encapsulating every value and filter its access through properties.

    That said I've always wanted to figure out a way to do this with scriptable objects.

    Personally I don't see the point of making instances of scriptable objects at run time. It's just plain classes with more work, as you have to manage the lifetime of the managed UnityEngine.Object.
     
  24. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    It'd be purely about interoperability with the design-time objects.
     
  25. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    I'm gonna pretend that I understand that and say.. fair enough.
     
    JoNax97 likes this.
  26. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,886
    Its also nice to know you are not accidentally editing the source data set at runtime :)

    If you make an instance, you always know that any changes will not affect the source data

    So many times I get contacted by developers for help who dont realise that by using an SO directly they have directly edited its data when making changes, and due to it being an asset those changes can persist outside of play mode(or may not, depending how the SO is being handled such as with custom editors etc)
     
  27. Voronoi

    Voronoi

    Joined:
    Jul 2, 2012
    Posts:
    571
    Exactly! This is helpful to remember.

    I started out that way, but as it turns out if the gallery is empty, the designer wants an animated tour guide to come in and explain things rather than showing an empty gallery. I think doing this again, I would keep this principle in mind and have the menu activate an empty parent object with various child objects (gallery + tour guide). When enabled, the parent decides do I show the gallery or the tour guide and makes that happen.

    My problem is I gathered all the tour guides together in another parent object, so like I said, it's a bit of a nightmare of button interconnections. I find that uGUI encourages this sort of crazy wiring up of the buttons though. Everything works, but I don't look forward to opening this a year from now and understanding what's going on!
     
  28. Voronoi

    Voronoi

    Joined:
    Jul 2, 2012
    Posts:
    571
    This is why I don't understand why a Players health would ever be stored in a SO. You are play testing and constantly changing the health so the next time you play test, it has more or less health than last time.

    I use SO more like a .json file to store minimums and maximums of health, but not the current values, that should be a temporary variable in the game. The advantage of a SO over .json is that I can also store things like audio, animation or graphics that are used to indicate things about health as needed. It's a neat setup that is easy to access from various scenes without the fragility of being a prefab.
     
  29. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,185
    He touched on that in a follow-up blog post. His sample code in the talk is a simplified version of what he uses in his projects. His actual code has more features, custom icons, and a generic base class to simplify the creation of new types. He showed just enough to get his point across.

    http://www.roboryantron.com/2017/10/unite-2017-game-architecture-with.html
     
    Last edited: Aug 29, 2022
    MadeFromPolygons likes this.
  30. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044


    This seems like a complete and total nightmare unless the game logic is very very simple.

    It strikes me as a mega hack for lack of a visual scripting language.
     
  31. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    is that not a reference dependency visualization?
     
    angrypenguin likes this.
  32. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    yeah it is.

    The point though of this scriptable object architecture in general, would be to give designers the ability to cobble together code (i think)

    I've never used unreal, but I'm sure that blueprints in unreal have some method for feeding input that isn't awful. So you can do something like a healthbar without needing a bunch of assets files linked to game state (health.asset, stamina.asset, etc).
     
  33. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    i dunno, it may be scope over my head, but you can still screw things up pretty bad in blueprints :)

    it doesn't protect you from creating a gross entanglement of class dependencies. You have to know how to use interfaces and composition and such to reduce coupling.

    i was under the impression that wrapping data/logic into objects is just an organizational thing. Makes it easier to understand, easier to search, etc, and doesn't preclude any other data management practices.
     
    angrypenguin likes this.
  34. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,337
    That's a singleton.

    Player.GetInstance().PlayerHP.
     
  35. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,493
    Well, if you create multiple of those prefabs, you could wire them with multiple independent instances of "players".

    Their addition somehow does not resolve that fundamental problem ._.
    Yeah they have a "DefaultHealth" and "CurrentHealth", but they set CurrentHealth in the onEnable method. That's only called when creating the prefab and think on the run of a build. During testing in the editor however, the CurrentHealth will still retain the value between plays...

    Unless they did what I did for different reasons and implemented the Start() method for scriptable objects themselves.

    Sometimes at least for dialogues, people use a graph-based system to organize the whole procedure with their dependencies etc. There are some assets for that in the store.
    However for a complex UI, think there won't really be a truly universal solution.
     
  36. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Why? As in, what negative impact do you think it will have on the people making the game, at what stage in development?

    What you see there is nothing more or less than wrapping a variable in an object.

    I suggest watching the video, as he explains the three intents behind this quite clearly.

    The main one that diagram is showing is decoupling of reference types. None of the things on the right need to be aware of what type of object the thing on the left is. All they know is that it has a float property which they need to work with. It's the same underlying problem that Interfaces in C# are to address.

    No, it's not at all. You can have more than one of them, there are no static references to them, and they do not self-instantiate.

    It's clear from the opening minutes of the talk that the guy has a rack of pitchforks just to chase away any whiff of a Singleton. In particular, your example snippet would run directly into a number of issues he's trying to solve at the start.

    - - -

    The bit about that diagram which grinds my gears is actually something he showed elsewhere in the talk. It's this bit:
    Code (csharp):
    1. class FloatVariable : ScriptableObject
    2. {
    3.     public float Value;
    4.     ...
    5. }
    So, referring back to that diagram, the UI and the enemies and the audio system can all mess with that value. I know that this code is a stripped back example, but I'm not aware of any reasonable way to enforce rules about who is and is not allowed to modify that object. So that approach gains in flexibility and decoupling, but then loses out in encapsulation. Is my health variable in a valid state? No idea, because anything could mess with it at any time. I understand that scope is being limited in other ways, which brings me to...

    He also mentioned that in order to provide visibility, debuggability, etc. they'd written a whole bunch of extra functionality into their classes. That's a good thing to be doing with custom editor tools, so in principle that gets my thumbs up, but I also recognise that at some point you reach a level of complexity in this particular type of tool where you may as well just teach your designers some code. After all, they're working as game developers, they're having to learn something either way, and understanding some simple code would be super duper advantageous to them anyway. And that'd be transferrable to any project, rather than one of the talk's stated ambitions of encouraging this as a standardised approach.

    I could go on at length (I typed out way more!) but I'll leave it with one other thing for now. At some point in the talk he says something along the lines of "by moving this from code to data we make it the designer's responsibility instead of the programmer's", and I just fundamentally disagree with that. The stuff he talks about is a cool approach and I can indeed see it being useful in some circumstances. The thing is that flexibility is not a panacea, and a programmer's job ultimately isn't "write code that works", it's to help the team achieve its goals. You can't just write some code and say it's someone else's job now. I'm sure he didn't intend for that statement to be taken literally, so I won't hold it against him, but I do think it's worth pointing out that sometimes the most efficient way to do a job is to enforce some rigidity.
     
    MadeFromPolygons, NotaNaN and Ryiah like this.
  37. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Yes, that would exactly be my suggestion. If there are responsibilities which can't be mapped nicely onto existing objects, I'd consider reorganising my objects to better represent the updated design. For UIs I've commonly used a container which has the sole responsibility of picking between child objects based on context, because that responsibility can't be cleanly mapped onto the child objects (because they then all need to be aware of each other, which quickly spaghettifies. I mean, doing it once is no big deal, but when does it ever happen just once?).
     
    Voronoi likes this.
  38. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    From the CPU's perspective it makes things much slower. In the vast majority of cases that will make 0 difference, because most code in a competently written system is only being run occasionally. But in those rare cases where lots of data needs to be crunched I'd argue that this would be a terrible approach.

    Ideally, you identify those areas during prototyping or early development, then you make purpose built code and interfaces and tools to meet your team's needs on all fronts.
     
  39. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    that's what I've ended up doing as well. I only interface with containers, and the container manages its members.

    My project is small but I do have a ton of images I use for some tutorials - this setup has helped me make it so that I only load individual images at the exact time the individual image is needed, rather than loading inadvertently.

    It's also relatively easy to manage because it follows a similar principle to real life communications you'll find in many professions: big boss talks to just a few managers, managers talk to team leads, team leads manage a squad/group, etc.
    (not a precise analogy, because my managers and bosses don't do any directing, they only broadcast important events and then the team leaders in the field (the containers) react to that accordingly.)


    understood. And I read recently somewhere that it's also not the sort of approach you'd want where you are handling high-speed stuff and need to avoid latency. Like movement/actions in a multiplayer game. But people making projects like that, hopefully, already know what the heck they are doing :).

    Personally, I am trying to think about, for all of my future projects, how to make games where the code can get simpler and simpler. Games where the fun and interest comes from making decisions - not so much from impressive animations or high-speed reflexes.
    I just don't think I'd be able to stay independent/solo and do anything other than that to a professional, polished result. Kind of a different topic but I just trying to point out that my strategy is such that if technical questions like this are becoming vital to success, I probably have put myself onto a suicide mission ( i think its worth mentioning endlessly because it's easy to get into that trap, especially if a lot of wanna-be devs are young and haven't had experience in risk-management, or managerial roles, etc).
     
    angrypenguin likes this.
  40. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    I can't imagine why it'd make a difference in those cases, but that's another topic for another time.
     
  41. BIGTIMEMASTER

    BIGTIMEMASTER

    Joined:
    Jun 1, 2017
    Posts:
    5,181
    something to do with like, passing data through interfaces or components versus a more direct shot straight to the target.
    I kinda glossed over details because its not a concern for me but the basic idea I got was, the more abstracted and decoupled it gets, the longer time it takes for message to get to target.
    It could very well be one of those masturbatory articles written by somebody wanting to impress with their lowest level concerns, but the author didn't seem like a moron.
     
  42. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    That's true, but it makes zero practical difference to input latency. We're talking about something that a computer can do billions of times per second as opposed to something which a computer can do tens of billions of times per second.

    As an example, standard USB devices poll at 125hz, where fancy gaming ones poll at 1000hz. That sounds like it should make a huge difference - it's 8x faster! But if you look at the actual timings involved, it's a difference of 0.007 seconds. That's about half a frame at 60hz, or about one tenth of the fastest unconscious human reflex response time. It might make an occasional difference to top tier players when a play is super close. Top tier play is all about the close moments, so it makes a lot of sense for them to care about it. For the rest of us, it's marketing.

    And that 0.007s difference is already thousands of times bigger than anything you'd get by changing memory access patterns for your (competently written) input code.

    Assuming that your game is already running at the native refresh rate, what would make a difference is making sure that your game supports sub-frame input polling, and actually uses that data in its mechanics. In that broader context, yes, applying more efficient memory access patterns (e.g. "ECS") throughout your whole game could indeed increase how fast everything goes which would include reducing effective input latency. Similar math to the above will apply for the practical effects.
     
    Last edited: Aug 30, 2022
    Meltdown and MadeFromPolygons like this.
  43. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,337
    I"ve watched it since the beginning, it is not 3 minutes, but 26, and I think I got the crux of his idea.

    There are several problems with his reasoning.

    * If you have Inventory Manager that needs to talk to UI System, then regardless of whether it is implemented via a singleton or dependency injection, there's going to be a dependency. So when debugging scene you'll have to drop both subsystems into the scene, no matter how you go about it. By switching to dependency injection you simply shift reponsibility of who is going to be the singleton, and the dependency does not disappear. It is simply being moved around, to a different singleton.
    * His talk about singleton being non-polymorphic is not correct, because singleton can be a polymorphic abstract base class that is hiding concrete implementation behind a facade.
    * The idea with FloatReference comes with a bunch of problems. Basically the point of having different scriptable object types for, say, enemy stat blocks, is that you'll be UNABLE to assign stat block to a wrong slot. Compiler will protect you against that, inspector will protect you againt that. The type system will protect you from doing that. Here, he removes protection of the type system, loses compile time sanity check, and basically now you can assign "Sound Volume" to "Max HP" and there will be no sanity checks in place to detect that. Basically, his designers are assembling struct within a file system. That does not appear to be a sound approach to me.
    * His talk about Player having to access UI when health changes is strange. That's what EVENTS are for. C# event or unity events. Player only needs to signal that something happened to his health, but the player doesn't need to know who is listening. So, basically, at some point UI can subscribe to player and monitor health changes. The player doesn't need to know who is subscribed to the notifications, it just need to broadcast them. This way, player can work without UI system being present and does not need to know that it exists.
    * If my memory serves me right, at leatst at some point in time accessing scriptable objects under editor immediately altered them on disk. I might be misremembering it (it could've been happening to materials or prefabs), of course, but basically, there seems to be a good chance of wrecking your config during play mode, because all fields have read/write access.
    * Unless I'm missing something, you'd have to make all those connections by hand in inspector. The thing, is, with a singleton-based approach, you don't have to. You grab instance, and if it is not there, you bail and yell into the log. Here, every FloatReference is a failure point that can be null due to misconfiguration. This does not feel like a good trade to me.

    So going back to the original post...

    I don't see much point in following this approach. The video smells like "everything looks like a nail" to me, and the idea comes with drawbacks. There are other ways to go about notifying about health change, one of them being C# events I already mentioned. In t his scenario, coupling will be one way. Player would not know who is monitoring its health, and would be able to function with all other systems missing.
     
    Saniell, Marble and Luxxuor like this.
  44. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    Do you mean drop a reference to them onto an object in the scene? Because no, you don't need to drop the system itself into the scene and, in fact, you can't because it's a ScriptableObject and they can't be put in scenes.

    There's no compile time sanity check anyway. The compiler will happily let me do this if they're both floats:
    Code (csharp):
    1. player.hp = audioMixer.volume;
    But I do agree that "move EVERYTHING into data" isn't necessarily a good idea. One of the things I removed from my previous post was: when the need arises, how the heck to you go about refactoring stuff? And, I mean, of course you can, I just imagine that it's going to be a heck of a lot harder if a great deal of your functionality is shotgunned throughout your content and data.

    Edit: I tend to agree that while some of the stuff in the video is cool, it definitely is swapping one set of compromises for another.
     
    Marble likes this.
  45. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,337
    The type system, however, will not let your designer do that through editor. That's the reason for having HealthStatBlock separate from AudioParameterBlock.

    As far as I can tell, you pretty much don't. It will be a massive collapse of every connection carefully configured by hand.

    Frankly, it feel like this guy took C# and tried to turn it into python or javascript.
     
  46. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,519
    There are definitely other ways to make the connections, and I imagine that you'd only have to make them at all where you want a data point to be shared.

    But I digress. Some cool ideas? For sure. One game architecture to rule them all? I don't think so.
     
    neginfinity likes this.
  47. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,148
    Looking at the video, he seems to be effectively creating loads of single instances where each instance is a scriptable object representing a single variable! It is like loads of Singletons, but in a different form.
    He is transferring a lot onto the inspector side for designers but not without potential issue if variables get dropped and replaced with new logic

    Are there any game-code patterns for handling of a global variable or class of data and messaging listeners when changes occur? (not hard to write with singleton and some Observer, but interested if pure code/C# versions of this logic have been suggested, in the same this very Unity specific one has).
     
  48. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,493
    How about delegates and properties?
    Every watchable property has a delegate the listeners can add a method or lambda to and in the setter of the property you execute all those delegates.
    Pretty much what Unity's UI events do for example (like button clicks toggle changes etc.).
    If I recall right, if you do use UnityEvent you can even expose this in the editor like said UI components do.
     
  49. andyz

    andyz

    Joined:
    Jan 5, 2010
    Posts:
    2,148
    Well yes delegates and properties are it - I guess there are just a bunch of ways to set them up.
    But yeah, I would rather use such a common code-orientated architecture than the SOA
     
  50. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,493
    The purpose of SOs is originally something else after all. Yet doesn't keep people from setting up the strangest architectures :)

    Btw. maybe it's just me but I tend to put as little code flow definition in the editor as possible. Never actually used a custom UnityEvent variable and for UI's, I only use them in the most self explanatory ways. For example the "Options" button will call the "ShowMenu()" method of the OptionsMenu controller.
    Guess it just depends what you started out with. Programmers who learned programming command line programs or had to "manually" cobble together UIs with stuff like TKinter or Java Swing will like code-only approaches most. Web devs and users of JavaFX or the "modern" TKinter editor will prefer the approach Unity's UI Elements have. Then people who learned programming\development with Unity's traditional object-based UI will prefer that.