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. Dismiss Notice

Unity best Architecture and Design Pattern

Discussion in 'General Discussion' started by asil92, Aug 8, 2016.

  1. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
  2. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I wouldn't compare C# to C or C++ because under the hood they are very different. In C/C++(my favorite languages for a long time) I used function pointers a lot because they just fit the languages better IMO.

    However, in those cases while you still may take a performance hit (depends on compiler) it is just the cost of a dereference. And of course CPUs have provided direct support for this kind of thing since the 8-bit days. Indirect calls. Basically you can do a jmp/jsr/call (memory location) that is direct method access or a jmp/jsr/call (indirect memory location meaning this address points to the real address). Some compilers auto-replace it to a direct call just depends on the compiler and how the method is defined.

    For C# it is an entirely different beast. We're not writing code that drops down to the metal. And there is more overhead for using delegates in C# than using function pointers in C/C++.

    And Interfaces have a bit more overhead than delegates do.

    So for me... these kind of things are just a wasteful practice in C# that really adds no value while adding complexity and performance overhead.
     
    Deeeds likes this.
  3. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,027
    Last edited: Aug 28, 2016
    Kiwasi likes this.
  4. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    Have you checked that, though? For example, with ILSpy. I've tested delegates for android, basically as long as delegate is pointing to a static method and does not access any data that is not passed through its parameters, it seemed to be pretty very similar to a function pointer. Once you start passing in lambdas that refer to local variables or assign delegates to class methods, compiler starts adding extra magic (that can generate garbage), but static methods seems to be okay.

    And speaking of interfaces, stackoverflow discussion on that matter has disassembly. Virtual method call (alternative behavior) is 4 assembly commands while interface call is 8. and that's it.
    Also see: http://www.dotnetperls.com/interface-virtual-performance
     
    GarBenjamin likes this.
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Honestly I don't really care what happens under the hood. The performance differences between a switch and a delegate matter in so few cases as to be irrelavant.
     
  6. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    I haven't checked it out with ILSpy but it is common sense. It's not going to be the same efficiency as using the same things coded in C/C++. Even if Microsoft themselves has an article saying it is I won't believe it. I'm hardheaded that way. lol

    I just don't use the stuff anymore (for my game projects... at work for business software I still do) so don't think about it except when in a discussion like this. I get no value from using them in the first place. That is the biggest thing. Any performance differences are just an added benefit.

    Like @BoredMormon just mentioned though I think a lot of folks around here don't really care about that kind of thing. I've just got it ingrained it my mind from years of working on slower CPUs. Combined with the philosophy of just keeping things simple. Simple direct code is generally code that CPUs can burn through very quickly.

    In reality, the biggest performance hits will come from the interaction between our C# programs and the Unity C++ API. Callbacks such as calling all of the Update() methods on a bunch of monobehaviours and so forth. I don't know how much, if any even, performance hits occur from calling the C++ API methods from C#.Net.

    Basically, I just see it like this. When using something like Unity there are already performance hits going on so why make it worse by adding more of our own?

    Anyway, I've gotta get some work done on my game.
     
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    I wouldn't use a "common sense" argument. In case of programming it is a good idea to assume that common sense is lying to you. "profile before optimizing", "murphy's law", etc.

    The whole idea of IL code (IIRC) was to make sure it gets compiled to target architecture, which is governed by JIT compilation. And it wouldn't surprise me if some subroutine could end up being faster in a specific scenario, especially when compared against a program that wasn't compiled to utilize full CPU instruction set in order to be as portable as possible. Anyway, I haven't verified how JIT compilation works (assuming it even works in unity), so I can't make any claims.

    I see it like this: By old school standards my current computer is nigh-omnipotent. Therefore the best idea would be to ignore performance concerns until they become an actual problem and concentrate on code readability, since it reduces project's development/maintenance costs. Readability comes first, then it is KISS, YAGNI, "profile befor optimizing" and "Murphy's Law".

    Either way, I sorta think the discussion diverted too far into discussing specific technical details of a language, which is less interesting than high level concepts/approaches.
     
    TeagansDad, Martin_H, Ryiah and 2 others like this.
  8. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    Ha ha! True. It's the kind of thing people strongly believe in that kind of leads to dropping down to other details a bit. As long as we are all getting stuff done and happy with what we're doing then we're doing alright.

    Anyway, I agree. the overall structure and such is probably more what the thread was made for.
     
  9. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    I too tend to focus on writing efficient code rather than the 'lazy' code that has become commonplace, and it does go back to days of working on slower hardware and need to be careful about this kind of thing. Nowadays it seldom matters as much with such fast processors but to me I also feel it doesn't hurt to squeeze some extra performance out. Although a lot of that has to do with the algorithm and how it's implemented.
     
    GarBenjamin likes this.
  10. tatoforever

    tatoforever

    Joined:
    Apr 16, 2009
    Posts:
    4,325
    That's the way I code in Unity. Everything have a state,=. The game have a global state (such as scene warmedup, loaded, etc), managers does have states (enemies prefabs, players prefabs, controllers are ready, etc), objects states (doors are ready to be used, AI is ready, etc). But I also do try to separate objects behavior in components (and share among related objects).
    It's also important to well structure your project files so you can find your components easier instead of try to guess what does this component do.
     
  11. NicoVar

    NicoVar

    Joined:
    Sep 21, 2012
    Posts:
    40
    I strongly agree. I wrote a small article about this:
    http://initiative.online/p/demystifying-unity-for-large-projects-6-rules/
     
    Deeeds and GarBenjamin like this.
  12. Elzean

    Elzean

    Joined:
    Nov 25, 2011
    Posts:
    584
    I don't think this has been mention but Entitas is pretty good to keep things clean and clear imo:
    https://github.com/sschmid/Entitas-CSharp

    MVC or ECS (ECS feels more appropriate for most games) may not feel important in solo / small projects, but otherwise it is a great way to reuse code over over multiple project and extremely useful when working with several programmers or bring new ones to the team. Not matter what it make it easy for a programmer to read and understand others people code because it always based on the same concepts.
    Following an ECS pattern makes your project easy to read / understand, debug, extend etc....

    I'm surprise no one talked about Entitas, its a powerfull free framework and i wish more persons would use it and make a larger community around it.

    For the lazy ones:

     
    Last edited: Feb 7, 2017
  13. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    I like the "make your own package" advice for Asset Store content (and agree that source is a must). I haven't ever heard that suggested before, but it directly addresses my general discomfort with using Asset Store content in multiple projects or on multiple systems. I tended to handle it as a file copy but a custom package will be so much more convenient.

    My projects are already very code-heavy but how do you quickly and efficiently switch between Unity projects? It seems that would incur significant overhead. For example, a tech tree UI seems like something that could be requested by the user on a pretty frequent basis. I have no experience working this way but making that a whole separate project "feels" pretty extreme.
     
    ChibigDev likes this.
  14. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    I'm confused. You said "In our case, we use different Unity projects for each section of the game: the base on Earth is one project (not a scene, a separate project), the technology tree is another project, etc."

    So...when playing the game, if someone wants to see the tech tree you launch a different Unity exe? Or is this just prototyping?
     
  15. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    In very large productions, developers sometimes split their work into multiple, separate projects that essentially compile as DLLs (code) and asset bundles (art) into a single "main" project. When you build that main project, it generates a single executable.

    At Unite a few years ago, Schell Games did what I think was the best explanation of how to do this. I have no idea why the video disappeared, but fortunately the Power Point presentation is still available:

    http://unite.schellgames.com/Unite_2011_Scalable_Game_Development.pptx
     
    GarBenjamin likes this.
  16. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    Just as I suspected, it's a very hands-on build process and involves custom tools.
     
  17. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    It's much simpler now. I think that was from Unite 2010, which was almost 7 years ago. Unity has made a lot of things simpler since then, such as better integration with Visual Studio. You don't need custom tools, although I find uTomate to be invaluable.
     
    MV10 likes this.
  18. Infrid

    Infrid

    Joined:
    Jan 14, 2012
    Posts:
    67
    Just skimmed through the entitas demo.. ugh, looks wack to me.. If people don't like Unity so much that they make a framework that almost means they never need to use any of the built in editor, well.. perhaps just use gamesalad or Unreal Engine??
     
  19. ThatProgrammerJack

    ThatProgrammerJack

    Joined:
    Jan 6, 2019
    Posts:
    32
    I'm still a bit confused by this. Could anyone please elaborate? Why wouldn't I use managers for things?
     
  20. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    Erdi Izgi has a good discussion of one reason to avoid managers, and a solution, here: Avoiding Singletons In Unity.

    Another reason to avoid managers is that you can paint yourself into a corner. Say you make an InventoryManager singleton to hold the player's inventory. What if you add an NPC companion that needs have to its own inventory? You're stuck because the InventoryManager singleton is global. But if the player instead had its own Inventory component, you could simply add another Inventory component to the NPC companion.

    (This is separate from the discussion in this thread about composition vs. inheritance.)
     
    Ryiah and angrypenguin like this.
  21. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    A lots changed in the last few years. ECS uses managers for everything.
     
    Ryiah likes this.
  22. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    Unless I'm missing something, the article boils down to "Dependency inversion good, singleton bad".

    Which does not make it a very sound opinion.

    Additionally, in the end it replaces singleton with a ... singleton with a bit of syntaxic sugar. Because service locator is a singleton.

    Honestly, YANGI+KISS still seems to be a better design philosophy.

    The idea in this thread was that there's no real need to use managers when you switch to MonoBehaviors, because all objects can act independently and use Unity as physical sandbox. Therefore you can simply spawn more units and make them function without any component tracking how many of them are there in the scene.

    In practice, few years later it turned out later that if you want to squeeze every tiny bit of performance from your game (and use ECS), then you'll end up using managers.
     
    bobisgod234, JoNax97, TonyLi and 3 others like this.
  23. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    I was thinking of mentioning ECS. You're still going to use managers and composition, not manage everything as a single god component. You all are right; I should've mentioned ECS. But that's a different kind of manager. One of the key issues with the original kind of singleton manager being discussed is global data. But entities have their own data.

    I've been contributing to a jam game this weekend, and that service locator pattern has worked extremely well for collaborative programming. Admittedly, it's similar to a singleton. I got a little carried away gushing over it in the moment. We were able to very quickly define a few essential interface classes and then each go about our own tasks just relying on the service locator to find others' work regardless of how they implemented it.
     
    Last edited: Jan 30, 2021
  24. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    This thread is pretty awesome, got a lot of new ideas to try out just be reading it.
    One thing that I've been thinking about though is dependency injection. Is it useful or necessary in Unity? Would a DI framework like Zenject help or is it overdoing it?
     
  25. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    Unfortunately I don't think this link works anymore. But I think it is still widely adopted. When I asked Nathaniel Hawthorne about how he works on DRONE, that's basically what he told me.
     
  26. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    I'm also a bit confused about Panda BT. Why are some people using behavior trees as a framework for the entire game? Is that sustainable and efficient?
     
  27. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,280
    Are you sure that anyone's actually doing that? I've never heard of such a thing. Usually people use BTs for character AI. It's like a FSM except with a decision tree to decide which state you're in, so an AI agent with multiple behaviors can select one of those behaviors based on a complex set of conditions.

    Of course you can use it outside of AI too, it would be useful anytime you have need an FSM, but you feel like your transition functions are getting sloppy and unmanageable.

    It's certainly possible the you'll never need one, depending on the game you're making. BT was never meant to be a one-size-fit's-all solution to organize your entire project.
     
  28. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    That's what I was thinking. Some messages earlier were praising its simplicity and readability for entire project organization. So I was a bit confused.
     
  29. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,027
    Just in case you're not aware the majority of this community is made up of hobbyists, and many people who make games as a hobby will often approach problems in ways that may make no sense to a professional game developer.
     
    Kiwasi, MadeFromPolygons and Martin_H like this.
  30. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    I see focusing on DI as a waste of time. DI is glorified callbacks. Callbacks has been around... probably since assembler times, and you'll easily add them when you need them.

    The guy who said that "Dependency Injection is a $25 name for a 5cent concept" was right. It is just callbacks, but calling it "Dependency Injection" makes it sound mysterious and important, overly complicates things and makes everything harder to understand.
     
    Kiwasi, Ryiah, JoNax97 and 1 other person like this.
  31. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,280
    A lot of BT implementations on the asset store have lots of "action" nodes that serve as wrappers for common Unity functions, so I guess it's also possible to use one of these BT packages as a substitute for visual scripting (similar to Playmaker or Bolt). Maybe that's it?
     
  32. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    I've been using scriptable objects to try to fix dependency issues and singleton issues. Especially after combing through the Open Project code it seems like a good idea. Is it a good idea to decouple code using SOs?
     
  33. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    You may still be defining global data, which you may or may not want to do.

    It also depends on the purpose of the data. It's possible that you may ultimately want to pull some data, such as balanceable settings for items and skills, from some other source such as an Excel spreadsheet where you can crunch the values for balance.
     
    Deleted User likes this.
  34. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    You need to ask yourself "what exactly do I gain by utilizing this practice".
    If you can't answer that question, then you're may be following a cargo cult, or may be doing something you don't even need in the first place. Meaning wasting time.

    For example "dependency issues and singleton issues" -- are they actual issues in your code, or are you trying to follow some random advice on the internet which said "singletons are bad"? Or, does the problem you're trying to fix even exist in the first place?

    Your first priority would be keeping code readable and making it work. Not fighting singletons.
     
  35. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,842
    I personally don't go that far to not having global managers. Game is an application with one or more global states. Instead of focusing on eliminating the natural behavior, I try to be cautious what do I put in the global space.
    "Service locator" is one of those things. I don't want to waste precious CPU cycles to trickle up and down on the hierarchy with some arbitrary message and I also do not want to handle dependencies locally. It works well, when you have scenes as units, but I tend to go towards async loading additional scenes and all. Scene isn't a standalone unit anymore. In the GameObject world I use ScriptableObjects as managers, singletons and other "glue-classes" (like events, observables and stuff).
     
    Ryiah and Martin_H like this.
  36. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    I do the same, especially on multi-scene projects because singletons just don't work between scenes.
     
  37. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    It is sometimes very hard to follow YAGNI because I keep thinking about what I will need or want in the future or the maintenance of the code etc. But in this case using SOs is not a hassle and has worked out so far pretty smoothly as well as making code more readable.
     
  38. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,301
    In case of YAGNI one possible rule of the thumb is "If you don't need it right now, you won't need it in the future." With a possible followup "Even if you think otherwise"

    One step at a time. Solve the problem you're working with right now, then see if new requirements arise or not.
     
    Martin_H and Lurking-Ninja like this.
  39. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    For 99.9% of dependency injection you need, you can just use the inspector. Unity comes with its own pretty decent dependency injection framework, we just don't call it dependency injection very often.

    I would specifically advise against zenject. In Unity you don't have access to the constructor for components, generally because Unity uses the constructor for its own dependency injection (ie the inspector). So you end up fighting really hard with intermediate layers to make the framework behave. Then you end up spending a lot of effort to do something that leaves you with pretty much the same functionality as the inspector.
     
    PanthenEye, bobisgod234 and Ryiah like this.
  40. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Its nothing like dependency injection though. With a proper DI you can just to replace container.Register<IMyFoo, MyFoo>(); With container.Register<IMyFoo, MyOtherFoo>();

    The unity way sort of make the classes as testable as proper DI though, but much less elegant, and much more hassle to replace implementation.
     
  41. skiwee

    skiwee

    Joined:
    May 30, 2020
    Posts:
    32
    Why is it more of a hassle?
    And for you would you suggest Zenject?
    Also in the Unity Open projects I saw that they must mostly use normal objects instead of monobehaviors, meaning constructors aren't as big of a problem.
     
  42. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,495
    To paraphrase a famous quote, my code is never finished, it's just abandoned when it gets the job done. ;)

    My approach to what you describe is this: when I'm adding something new to a project I make a minimal working version and get it in place so other people can start using it. Along the way I take notes for things I could improve, optimise, or where I think there are gaps in functionality. However, I don't try to implement those things until I've got real world feedback, because the problems I imagine and the problems we really run into could be very different from one another.
     
    Socrates and Lurking-Ninja like this.
  43. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Haven't used it so can't comment on it. I explained the hassle with replacing implementation?