Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

How a longtime programmer develops in Unity... Me and my unorthodox way

Discussion in 'General Discussion' started by GarBenjamin, Jun 26, 2016.

  1. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Some Background

    I've been programming for a very long time now. Started on the TI-99/4a near the beginning of 1983 and switched to the C64 in late 1984 / early 1985. Went on to the Amiga, an IBM PC clone in DOS and then Windows. During this time I used a lot of different programming languages and yes nearly everything I was programming was games and game dev tools.

    When I first moved to Unity I didn't care much for it. I was used to game programming being lean, mean and straightforward (you either programmed in something like Assembler and handled all of the graphics, sound and music support yourself, used C/C++ and chose one of the available libraries (or you could roll your own of course) or used something like AMOS or Blitz.

    I spent the first week or two researching trying to figure out how to open up Visual Studio and start developing with the Unity API. I knew it had an editor but I thought I could just link to the API as usual and it never occurred to me that I had to use the Editor and begin every project there. Because I never had to do that ever before in my life.

    Anyway, just to fast forward here... I've spent a lot of time coming to grips with development in Unity and during this time moved from working heavily inside the Editor & using the built-in animation systems, component-based design and so forth for my very first Unity game dev experiment to my current development style.

    I now use the Editor only to start each project, get the basics set up and use the scene editor itself as an object pooling system. I don't use component-based design any more and I do the bulk of my work outside of the Unity Editor (just programming everything inside Visual Studio). I program games basically the same as I used to before moving to Unity.


    What's The Point?


    Several people have contacted me asking for more information about the way I am developing in Unity. These folks all have the same kind of background having previously programmed games in Assembly, C, C# & XNA, etc. And I have seen comments a number of times on the forums where a person says they come from a similar background and are having a lot of difficulty changing over to the Unity Way. It's just such a massive change.

    So, I wanted to address this by explaining how I develop in Unity and actually build a game that I will provide the source to so you can download, check it out and experiment.

    It's my hope this will help the folks who have contacted me and also help others coming from a low level game programming background to make Unity work for them.
     
    Last edited: Jun 26, 2016
  2. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    In another thread yesterday I mentioned kind of wanting to make a Space Invaders style game in Unity.

    Today I thought "ya know... this would be a good game to use as an example for how I develop in Unity".

    Of course, it won't be an outright clone trying to look and sound like the original arcade game. It will be my unique twist on the game. Sure it will share a lot in common especially in the beginning but I figure it will change more as time passes.

    First these are vampires. Vampire aliens. Alien vampires. Vampaders. And to dress it up a bit like the old horror movies and recognize Unity at the same time... these Vampaders come from the planet Unity. :)

    So this afternoon before I left to watch the new Independence Day Resurgence movie (excellent movie btw) I started knocking out some graphics for the game. I decided on a low res fairly low color pixel art display. I usually do. Just because I really don't want to spend so much time just making graphics. I want to make some nice graphics get it done with so I can actually build a game.

    Tonight I returned to work. I launched Unity and started setting up project.



    AudioPlayer, Configuration, GameManager and Sprites are the only objects that have scripts attached to them. These are all Singletons.

    Sprites is simply a resource class. It has public variables that allow me to specify the sprites for the player, the vampaders and so forth. Anytime I need to display a sprite I can easily get what I need by making use of the Sprites class.

    StateTitle is just a "folder" game object and beneath it are all gameobjects that are needed for the Title state of the game.

    Likewise, StateGameplay does the same for the Gameplay state.

    When the Title state is active the display looks like this:


    When the Gameplay state is active the display looks like this:


    And that is all I had time for today. I will continue on this tomorrow.

    -----------------------------------------------------------------------------------------------

    Sunday 2016-06-26


    I just spent some time on this project.

    A bit more time spent on graphics. Created the special enemy that moves across the top from time to time. Also creating a simple mountain range. Oh and I changed the images slightly for the ground and barriers. Mainly just different colors.


    Later I will add some twinkling stars backdrop as well but that is not something that is needed at this point. Mountain range wasn't either but I figured I'd slap it in and have it done.

    Okay, so what we want to focus on is the important stuff related to procedural programming oriented development.

    Originally, I looked into object pooling in Unity. Again, this is something I've thrown out as far as the way object pooling is normally done in Unity. In fact, I am not even using prefabs any more.

    Objects are pooled right inside the Editor. For example here is the pooling for the top row of enemies:


    And here is the pooling for the projectiles the enemies shoot at the ground below:


    So, the question you may have is how does this actually work?

    Let's take a look at the project inside Visual Studio:

    This structure will remain the same for any and all games. Regardless of game type. Regardless of 2D or 3D.

    Right now we need to focus on the WorldQueryManager class in the Utility folder.

    The purpose of this singleton class (it exists outside of the Editor) is to provide methods to easily gather up references to all of the objects sitting inside the Editor.

    For example, I create a method that searches the scene, finds the enemies, packages them up (inside an EnemyObject class) and then adds each to a list. Each enemy object will have a reference to the SpriteRenderer (for animation... I don't use the Animator in the editor), GameObject (for enabling and disabling), the transform's UnityInstanceID (providing a unique key that can be used to identify and differentiate one of these GameObjects from another) and the type of the Enemy will be specified along with other data such as it's initial position, state and so forth.

    All of those GameObjects in the Editor will be disabled inside the editor. So at the start of the game none are enabled. It is the responsibility of the various manager classes I will be creating to manage the enabling and disabling of the GameObjects as needed.

    For example, when an enemy launches a projectile... the list of EnemyProjectiles will be used. Each EnemyProjectile will have an EnemyProjectileState enum property. When the GameObject is disabled the state will be Inactive.

    All I need to do is scan the list looking for an EnemyProjectileObject.eState == EnemyProjectileState.Inactive and I know that projectile can be used to represent the enemy projectile the enemy just launched. That EnemyProjectileObject is returned from the method that is called to find an "empty" projectile slot to use.

    Then I will simply call an Activate method that will both enable the GameObject (remember there is a reference to the GameObject inside each EnemyProjectileObject) and change the state to EnemyProjectileState.Moving.

    If no objects are found that are currently inactive the enemy cannot shoot a projectile. Hopefully you can see how this works very much the same way we did it in Assembly and C. Typically we'd search a list of indexed memory locations/array of available objects that could be reused. The approach described above is doing exactly the same thing.

    And that is how pooling is done.


    Important things to keep in mind

    Any additional references needed for your GameObjects are always stored in the associated object class that gets added to a list. For example, in my 3D game the CharacterController is part of the EnemyObject and PlayerObject classes. When the WorldQuery manager finds the gameobjects it sets up all of this Unity specific stuff one time before adding the objects to the list and returning the list to the caller.

    In this way all references are cached inside the objects and are available from that point on.

    Also, I know some of you coming from an Assembly and C programming background don't have experience with OO concepts. And that is fine because in my quest to simplify everything I have thrown out the majority of OO and focused more on a straightforward procedural programming paradigm.

    Objects are used but they are only container classes. Just think of them as structs. Little packages of data. They have no methods. The manager classes have all of the logic.

    We won't be using OO, Inversion of Control / Dependency Injection, Interfaces, Event Systems or any other modern "gee whiz" stuff here. It simply is not needed and only serves to add additional layers of complexity.

    What we are doing is focusing on getting results fairly quick. A way to jump into the development and work kind of "on the metal" rather than spending our time trying to engineer everything to have less dependencies and so forth. Although in the end you'll see it is all quite logical.


    Can you show me an example of how the World Query Manager works?


    Here is the PlayerObject class.


    That's it. Like I said there are no methods in these classes. They are simply containers. I could have used structs but I am not that nitpicky.

    At the top you'll see the Unity specific data. References to the GameObject, Transform and Renderer (actually SpriteRenderer in this case). This one doesn't need the Unity InstanceID because there is only one player. I use the InstanceIDs to identify exactly which object I need to work with in the case of multiple objects using the same Unity Layer. There is only one object using the Player layer in this case.

    Here is the start of the WorldQueryManager class. It is a singleton. Not a Unity singleton but just a plain ole singleton class.


    The first method in here is GetPlayerObject and it accepts a string identifying the name of the GameObject that represents the player in the scene.

    The method searches for that GameObject and sets oPlayer.gameObject reference to what was found. It may be NULL in the case of not finding the player. So the next bit just checks for that case and exits if the Player object was not found.

    Next I just set the references to the transform and renderer and return the object.

    So what is this object returned to? What is calling this method?

    IMPORTANT

    For every unique object type I have a manager. This means there is an EnemyManager. And likewise a PlayerManager.

    All of these managers have a public Init method and a public Update method. They are all singleton classes and they all exist outside of the Editor. They are not monobehaviours. It is very important to keep that in mind. The Unity system does not know about these although they do use the the UnityEngine API.

    Here is the PlayerManager's Init method:

    And there you can see the call to the GetPlayerObject method.

    I really should be checking for failure and will add that at some point. Although it should never happen it is always possible. For example I could rename it as I recently did to PlayerVehicle. ;)

    For now just ignore that.

    The next question would be... what calls PlayerManager.Init?

    This leads us to the root of my way of doing things. One of the few singletons that exists inside the Unity Editor is the GameManager. It is a monobehaviour and it is the central key for everything. It has the standard Start and Update methods

    In the Start method each Init method of all of the various game managers are called.


    And that completes the process.

    Unity calls the GameManager.Start method. GameManager.Start then calls the Init method of each of the different gamemanagers. Each of those Init methods uses the WorldQueryManager to locate and initialize the data of the various GameObjects.

    Basically this is all done so we can extract everything we need and be able to focus our efforts outside of the Editor working almost entirely inside the code (just like the good ole days!)


    Where is the main loop?

    I've not actually got to the update part yet but it is also very straightforward.

    Unity calls the Update method of the GameManager every frame. GameManager.Update in turn calls the Update method of PlayerManager, EnemyManager, ProjectileManager and so forth.

    GameManager.Update is the equivalent of the main loop from the good ole days. :)

    You can basically think of GameManager.Update as an interrupt timer call from the C64 and DOS. Every frame this method will be called exactly as it would be had you manually set up an interrupt call in C64 assembler or DOS.

    It is also the same thing as the Update timer event firing in XNA.
     
    Last edited: Jun 26, 2016
    ZJP, hippocoder, iamthwee and 9 others like this.
  3. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Better reserve one more just in case
     
  4. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    And maybe just one more.
     
  5. Martin_H

    Martin_H

    Joined:
    Jul 11, 2015
    Posts:
    3,915
    Although I don't have a programming background and I've somewhat given in to using Unity the "normal" way, I'm still very interested to see how you work. One of my first posts on this forum was asking for how a code-centric approach to Unity gamedev could work and I still think it is a very valid choice for many games, maybe even superior in some cases.
    Looking forward to read more about this!
     
  6. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Updated the second post with more information.

    I agree @Martin_H that it is hard to come by good tested information on developing in Unity in a more straightforward programmer-oriented way.

    Hopefully it will at least be interesting to people if not helpful. :)
     
    Ony and Martin_H like this.
  7. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    Your archiecture and mine are and aren't too different.

    A core concept I subscribe to is a delineation between Content, Behavior, and Presentation.

    Content is the stuff in my game. For instance, the player character, their abilities, the enemies, their abilities, etc., are all content. Content should be defined in data, be realized by Behavior, and presented to the user in a clear way via Presentation. Put differently, the responsibility of content is to define stuff in the world.

    Behavior is how stuff works. Players are defined by Content and Presented to players, but for the entities (including the game world) themselves to interact is entirely the realm of behavior. Behavior is set up in code, and in a limited way in the Editor. The responsibility of behavior is to determine how stuff in the world interacts.

    Presentation is how stuff is presented to the player. This does encompass Content and Behavior, given that there is first-order metadata needed to determine how to present stuff to the user, and the fact that the presentation layer has its own unique code in order to work in the first place. Nonetheless, the responsibility of Presentation is to let the end-user manipulate Content via built-in Behavior with minimum cognitive load.

    If this sounds like Web Development...well, now you know what my day job is.

    I don't use the Editor too much - usually when setting up a scene, or creating a prototype prefab. I used to use prefabs heavily, then I realized that prefabs are more or less Unity's purpose-built way to encourage using the Prototype Pattern.

    The end result? My code is set up as such:

    Code (csharp):
    1. /Assets
    2.     /Game
    3.         /MVVM
    4.             /DataAccess
    5.             /Repositories
    6.             /Mapping
    7.             /Models
    8.        /Behavior
    9.             /Actuators
    10.             /Managers
    11.             /Triggers
    12.     /Resources
    13.         /Data
    14.         /(Other Resource Types - Sounds, Models, Textures, etc.)
     
    Last edited: Jun 26, 2016
    CDDelta, Ryiah and GarBenjamin like this.
  8. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @Asvarduil Yes that makes sense. Absolutely more than one way to skin the beast. And each person will likely end up making some changes to make the development approach I am describing more to their liking. I am just focusing on what I am doing. It's definitely not the only way but is the best way for me personally. :)
     
    Ryiah and AndrewGrayGames like this.
  9. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    I think that's an important part of programming - if you ask two programmers how to solve a problem, you should get no less than four possible answers, but two (or more) recommended answers. Programming is a trade - science and art as one.
     
    Kiwasi, Ryiah and GarBenjamin like this.
  10. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,618
    I'm pretty much the same.

    I don't even have prefabs other than simple ones (like a particle system).

    Everything is built up from code on start-up.

    I was working towards Inferno having 2 objects in a scene. MainCamera, GameObject with one script. Everything else is loaded/setup on startup. Im not far away from that point. A few things I havnt done.
     
    Ryiah, Ony and GarBenjamin like this.
  11. Ony

    Ony

    Joined:
    Apr 26, 2009
    Posts:
    1,864
    Interesting thread, thanks for sharing, @GarBenjamin and @Asvarduil. It's cool to see how different developers approach a system. I'm slightly less organized than you, that's for sure. Here's a fairly standard breakdown of my own process:

     
  12. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @Ony Thanks for that. Gave me a good laugh.

    @JamesLeeNZ thanks for weighing in. When first thinking about doing this I wasn't sure whether to do it here or on my own website. I wanted to help people out who are wrestling with this stuff but at the same time I wasn't sure how it would be received by the community in general.

    I figured people would quickly start commenting "this is not the Unity Way" and leave a link to the Learn section. :D
     
    Ony likes this.
  13. JamesLeeNZ

    JamesLeeNZ

    Joined:
    Nov 15, 2011
    Posts:
    5,618
    It became a very easy decision for me back when I was using V3 (before I owned pro, so source control was not available)...

    I corrupted my scene and lost weeks of prefab setup work. From that moment, I pretty much vowed to never use a prefab again.

    As for the 'Unity way'... people can take that sort of opinion and shove it! There is no Unity way as far as I'm concerned. Do what you want in a way that works for you. Might be backwards to some people, but IDC about any perceived 'thou shalt use Unity like thus' mantra.
     
    ZJP, jtsmith1287, Ony and 1 other person like this.
  14. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    958
    I was one of the persons @GarBenjamin was referring to, asking him on how he organizes things, after reading his developer blog. I am a hobby programmer since c64 6502 and unfortunately, I never felt as much in control again (haha, except VB in Excel).

    I am quite excited about this thread, to see some different approaches. I just finished my first game/prototype in Unity and I somehow follow a very smiler approach to Gar. But I am not happy with the overall architecture, I.e. I did not figure out a good system of how objects/classes communicate (direct references).

    My setup is as follows:
    - Scene with 2 objects: camera (script to scale + script to init main manager) and event system
    - Singleton Manager Class (main manager, that mostly Inits various game managers and holds references to them)
    - various game managers (logic, sound, ui, etc) that run the game
    - various prefabs that only get instantiated once (i.e. They could also just be in the scene and I could use find or the inspector, but I load them from the resources folder, for no specific reason...
    - Various prefabs that 'deserve' to be prefabs, pretty much independent objects that get spawned / instantiated various times and typically get customized by code via a table / array that holds parameters

    Thank you @GarBenjamin for sharing this. I wish I could share something back, but I think, I am too novice. Will send you some source code of how I organize, who knows, maybe something of interest...
     
    Ony and GarBenjamin like this.
  15. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @sngdan great to see you drop by the thread. I was going to send a message and let you know I had started on it. Just hadn't done that yet. Wanted to make sure there was enough to check out so I didn't waste your time.

    I'll be getting into communication before too long. Basically I do everything in a very simplistic way. But I also try to keep the architecture clean. Like you that is very important to me. And I imagine you ended up using a similar approach because we both have the same kind of background experience.

    The short version is that I just allow the managers to communicate with each other. A key to it all working is the unique Unity InstanceIDs.

    With all of this writing now I am thinking maybe I should have just written a book "Unity for C & Assembler Programmers" lol
     
    JasonBricco likes this.
  16. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    Sounds to me like the answer is 42, regardless of if the swallow is European or African. The same answer may also apply to bluejays, but that part of the equation escapes me.
     
    Socrates and Ony like this.
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,522
    Good stuff. Perhaps I should start a thread on "How a chemical engineer develops in Unity". It's about unit operations and systems and data flow.

    Nah, we only do that to the people who can't actually make games because of old C habits. As you can make games, your way has merit.
     
    Ony, Ryiah, GarBenjamin and 1 other person like this.
  18. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    M_R, Ony, Kiwasi and 1 other person like this.
  19. salgado18

    salgado18

    Joined:
    Jul 15, 2010
    Posts:
    84
    Thanks for sharing your way of developing. I personally never got much into the low-level paradigm of coding (meaning C, Assembly and procedural languages). But I also never really got OO right.

    In that game, I'd make the objects in the scene (enemies, projectiles, player, etc) manage themselves, each being a prefab with a script. Then a singleton controller for each type of object (enemies controller), then one GameController tying all up. Is that the Unity way? :p

    Also, if you are good at procedural and low level programming, why not just use a low-level engine, or even develop in OpenGL? Maybe creating your own mini-engine, maybe one for 2D and another for 3D. I don't get why use Unity when you could develop your own custom solution. (not saying you shouldn't, just trying to understand) :)
     
  20. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @salgado18 I'm not certain if what you described is the Unity Way or not. When I think of the Unity Way I see a lot of wiring up references in the Editor, every single object being a monobehavior and having one or more scripts, animation via the Animator, physics via the built-in physics, using the collision event system. Basically all of the stuff they show in videos and articles here and around the web.

    The reason I don't drop down to making my own game engine is because I don't want a game engine. All I want is a way (API, etc) to easily load audio & visual content and then be able to easily display & play it. The reason for not making my own framework on top of OpenGL is because it is just work for no real benefit.

    I suppose it might not seem like it but developing the way I am showing in this thread is much faster for me. Unity is a great framework. And I get easy multiplatform as a bonus.

    It's probably hard to see since I am building the game in a very lazy manner and also spending time updating this thread here explaining each thing. But the main benefit of this approach for someone like me who is used to doing things very much in this way is dev speed.

    I expect that for many other people doing things closer to the Unity Way may be much faster.

    One of the things I hated was jumping back & forth between the Editor and Programming. It's a waste of time IMO. At least the way they show to do it. Think of something you need to add. Go into Editor, add a new script, now switch to programming and write the script. Switch back to the Editor, add a new script component, switch back to programming and write the script.

    Of course, you can just write your scripts all at once then add them. But I don't even like having to hook them all up. With all of the code outside of the Editor we remove all of that "busy work".
     
    Last edited: Jun 27, 2016
    salgado18 and AndrewGrayGames like this.
  21. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,595
    I like your simple approach to pooling. I do the same kind of thing a lot, but when I want a more dynamic pool I usually code those with prefabs and instantiate only when new ones are needed. But anyway yeah cool write up @GarBenjamin !
     
    GarBenjamin likes this.
  22. salgado18

    salgado18

    Joined:
    Jul 15, 2010
    Posts:
    84
    That makes perfect sense. I'm not too fond of jumping back and forth between code and editor. Also playing with scenes and prefabs and references looks so frail, it looks like it will break something any moment hehehe
     
    AndrewGrayGames and GarBenjamin like this.
  23. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    581
    It is always nice to hear other peoples work flows and the reasoning behind them. I should right a thread on "How a person with half a clue develops in Unity". My project has taken over two years at this point so much of it was written when I had no clue. I have a state manager that manages different states. The states themselves are not monobehaviours so I also have a data manager for storing references. I have a Mediator based C# messaging system, a playersavedata class, and a mismash of other code. I have to accommodate Oculus and Steam VR code. My game sometimes feels like one big hack.

    One question: if your classes are not monobehaviours and your gameobjects are not active, how do you find them? Or do they all start active and you deactivate them once you have found them?
     
    AndrewGrayGames, Ony and GarBenjamin like this.
  24. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,235
    Nothing wrong with procedural + structs :)

    I do wonder why even use Unity if that is your style though. You could put a couple week into SDL2 and have a custom 2d engine that you could reuse for the next 5-10 years and it wouldn't be fighting with a huge editor and ecosystem.
     
    orb, Martin_H, frosted and 1 other person like this.
  25. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Yes that is correct... kind of.

    Some things start out active. Lightweight stuff such as the Player. GameObject.Find can then find such objects and deactivate if necessary.

    However (and I am planning on covering this and of course it will be available to check out in the source once I finish and release it).... the case for multiple objects is different.

    Enemies for example are all children of a parent GameObject such as EnemiesContainer. Only the EnemiesContainer needs to be enabled in the Editor. All of the enemy children GameObjects can be disabled in the Editor.

    This allows GameObject.Find to locate the container GameObject. The actual processing to gather up the information for the enemy GameObjects is different from the player. In this case I simply loop through all of the child transforms of EnemiesContainer. When looping in this manner ALL GameObjects (or rather transforms) are included regardless of whether they are enabled or disabled in the Editor.

    So at the time the game first runs a few GameObjects will be enabled and the bulk of the GameObjects are all disabled.

    Of course, if I wanted to I could deactivate everything in the Editor other than the State GameObjects. All of these other GameObjects are children of a StateGameObject such as Title or Gameplay. In this case I could simply loop through every child to find what I am looking for.
     
    Last edited: Jun 27, 2016
  26. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Believe me... last year I spent a lot of time checking into alternatives for 2D game dev. And I settled on Monkey X. Then I searched for alternatives for 3D game dev and came to the conclusion Unity3D was the best for me to use as base. So I then focused once again on streamlining the development in Unity for 3D projects. Basically building on the work I had done previously and kind of starting fresh in some ways. At the end I realized I had actually created an approach that can be used for both 2D and 3D projects.

    So... I'll probably do any new games 2D or 3D in Unity from this point forward.
     
  27. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,235
    Sure, makes sense if it is working for you. Development style is one of those things that I think is very personal to each person(for those who make it out of copy paste land).
     
    ZJP, Martin_H, CDDelta and 5 others like this.
  28. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    This is so true. I think a lot of people like the "Unity Way" because it is probably their first time (first experience). And it does work. If this was my first exposure to game programming I'd no doubt like it better as well.

    Mine may be a somewhat odd case in that over the decades I loved learning and using the newest concepts and used them all... interfaces, events, IoC/DI, the various gof patterns, 3-Tier/N-Tier, MVC and so forth. Then recently I took a long hard look at it all and thought "how crazy this has become over the years. What used to be incredibly straightforward has become shackled with all of these best practices and paradigms".

    I do think there is value in them. But they all come with their own cost of adding additional development & testing time and additional layers of complexity "hiding" things because abstraction became one of the most important drivers

    So I dropped down to a very simplified approach. Basically trying to remove layers of abstraction and work more directly with entities and data. Very much like how I used to do it in C and Assembler.
     
    Last edited: Jun 27, 2016
    ZJP and salgado18 like this.
  29. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,814
    Nice! My method is usually to code the same thing 5 times because I've a) forgotten I coded it and b) forgotten how it works and c) it doesn't work.

    I came to Unity from blitz, pascal, C++ ... never really dabbled much in C, and I thought the component way was confusing at first, but I got used to it and it seems fine, haven't had a hankering to return to the old ways.
     
    Alvaro_Spain, MV10, frosted and 8 others like this.
  30. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    LOL That definitely happens for me sometimes just because halfway along I think of a better way then 1/3 in I think of a better way. Of course, it most likely happens when I jump into programming before actually thinking about it. Just having fun doing experimental design.

    I don't think the component-based system or other Unity things are bad. I think it's more that I have been reaching this point over the years more and more of asking "why?" instead of embracing the new paradigms. I really think that is a key part of it and it all just happened to reach a boiling point about the time I found Unity.

    It's actually a real testament to the flexibility of Unity that someone like me can come up with a way to development in it using a very different more programming-oriented approach. It doesn't lock us in to only one way. :)
     
    Martin_H and AndrewGrayGames like this.
  31. tiggus

    tiggus

    Joined:
    Sep 2, 2010
    Posts:
    1,235
    Entity Component Systems are the best thing since sliced bread in my opinion and definitely not just a Unity thing. State machines, factories, also staples of my diet.

    Many other patterns I find little use for as a solo dev because I don't need my code to be understood/readable by a team of constantly changing colleagues. They slow me down since I usually implement them wrong rather than sticking with the simple approach that I fully understand.
     
  32. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Yeah it's interesting because I am of two minds on it. For my work I still have the mindset these things are good and that is how I develop every day. Outside of work for my game dev projects I used to do the same but now I don't.

    I dunno maybe it's just that business software development is more suitable to the paradigms. It kind of seems that way to me. Maybe it is that I just want to question / challenge those things by stripping them all out and seeing if I really get into trouble. I don't think I will but I may. I kind of think this stuff is all pretty simple and people want to make it complicated.

    Of course, I am sure there are people who think the way I am doing things is making it more complicated. Just a very personal thing as you said.
     
    tiggus likes this.
  33. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    2,960
    Needs more mention of delegates.
     
    GarBenjamin and AndrewGrayGames like this.
  34. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    No delegates either. No need for them. lol

    Which is very funny considering I just coded a delegate for a callback function about 5 mins ago for my job to notify the "parent" app that a form had been closed.. But yeah we won't be using those here.

    Looking forward to working on the game project again tonight.
     
  35. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    581
    Delegates are a great example of me outsmarting myself. I was running into a problem where, if I left one game state and returned to it, I would get double the number of enemies. If I exited and came back again, I would end up with triple. It turned out it was because I thought I was being really cool and subscribing to my event system with this:

    Code (CSharp):
    1. mediator.GameStart += (s,e) => StartGame(e.GameRun);
    and then unsubscribing with this:

    Code (CSharp):
    1. mediator.GameStart -= (s,e) => StartGame(e.GameRun);
    It turns out that the unsubscribing code wasn't working and since my game states are not monobehaviours, they were sticking around still listening for events.
     
    GarBenjamin likes this.
  36. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    That's why some classes need to implement the IDisposable interface.

    Code (csharp):
    1. public class SomeClass : IDisposable
    2. {
    3.     public Action<object, Event> StartGame;
    4.     // ...
    5.  
    6.     public SomeClass()
    7.     {
    8.         StartGame += (s, e) => blah;
    9.     }
    10.  
    11.     // ...
    12.  
    13.     public void Dispose()
    14.     {
    15.         StartGame = null;
    16.     }
    17. }
     
  37. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    Please don't fill the thread with this modern dev junk. :)

    Make a new thread "How I use all of the modern paradigms in my Unity dev" or whatever. And I promise I won't comment "but instead of all of that you could have just used this". Although I will say there is a use case for such things. And delegates do kind of fit with C and Assembly programming experience. Indirection. Function pointer.
     
    Last edited: Jun 27, 2016
  38. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    581
    Sorry, not meaning to hijack your thread. I will continue to follow intently.
     
    GarBenjamin likes this.
  39. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    No problem I welcome the discussion just didn't want it to turn into a dumping ground where people started posting all of their coding stgles and such just because that could get really confusing to people very quickly who come to this thread from a C or Assembly background or just want to find a simpler way of handling game programming in general.

    It is all interesting stuff and I think it'd be great if more people around here made such threads and showed exactly what they are doing and why. I think we need more of that kind of thing around the forums. :)

    I've got an AudioManager, MessageEventSystem and other stuff I had written previously for my Unity games and from time to time I think about throwing them out here for anyone interested in using such things. Like I said, I used to apply most of these modern practices in Unity but decided recently to throw them out and see how it worked to just simplify.
     
    Last edited: Jun 27, 2016
    salgado18, Ony and AndrewGrayGames like this.
  40. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    961
    I like the whole composition thing rather than the deep class hierarchy thing so I actually implemented my own component system and then use Unity as an API much like what you're doing. I do have a few additional manager Monobehaviours and most of the UI uses the editor, but otherwise Unity is just a nice cross platform API for my game and works in a very similar manner to yours. Anything that needs an actual real game object to display just gets a special EntityGameObject component that will create the Unity game object and pass through the appropriate properties.

    I had various reasons for going that route - the drag and drop reference thing seems a little fragile, didn't want to be 100% tied to Unity, and to provide modding support. Anyway, my point is that - as you discovered - Unity is flexible enough that it provides for many different architectural styles. You can go for a 100% (well, 99%) self-rolled architecture or mix and match as you feel comfortable.

    Edit: Uh... just read your latest and I guess this may be off topic from what you wanted - say the word and I'll remove it.
     
    GarBenjamin likes this.
  41. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    Functional/Delegate programming isn't at all modern - it's merely come back into style, but it solves some problems we have in games. For one thing, it makes the Command Pattern ridiculously easy to pull off.

    For instance, if you want to write a control manager? What's better, this:

    Code (csharp):
    1. public void ReadInputs()
    2. {
    3.     if(InputManager.GetAxis("Horizontal") > 0
    4.     {
    5.         // Commands...
    6.     }
    7.     else if (InputManager.GetAxis("Horizontal") < 0
    8.     {
    9.         // MOAR COMMANDS LOL!
    10.     }
    11.     // No, I'm not writing any more of those.
    12. }
    ...or this?

    Code (csharp):
    1. public class ConditionCommand
    2. {
    3.     public Func<bool> Condition;
    4.     public Action Command;
    5.  
    6.     public bool EvaluateCommand()
    7.     {
    8.         if(!Condition())
    9.             return false;
    10.  
    11.         Command();
    12.         return true;
    13.     }
    14. }
    15.  
    16. ...
    17.  
    18. public List<ConditionCommand> InputConditionCommands;
    19. // ...It gets initialized somewhere...
    20.  
    21. public void ReadInputs()
    22. {
    23.     for(int i = 0; i < InputConditionCommands.Count; i++)
    24.     {
    25.         ConditionCommand current = InputConditionCommands[i];
    26.         if(!current.EvaluateCommand())
    27.             continue;
    28.  
    29.         break;
    30.     }
    31. }
     
    GarBenjamin likes this.
  42. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    It's fine. lol Thanks for sharing.
     
  43. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,814
    I dunno all this fancy event delegate stuff. I would give it a go but it seems like the sort of thing that would create bugs due to my ancient crappyness.
     
    Martin_H likes this.
  44. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @Asvarduil that's the key question, right? One to which there is no true one answer. If you asked me last year I'd probably have said oh for sure the second one. That is using a gof design pattern!! Now I'd say the first one. Reason being it's super simple, has far greater clarity due to not trying to abstract away what it is actually doing and so forth. I think anyone can easily see at a glance exactly what is going on in the first code. Can anyone see what is going on in the second code? Only that it is doing something. Using the command pattern to process... something. To understand they must trace the code around here, there and perhaps over there. And that is one of the biggest things I have questioned about modern dev practices.
     
    salgado18 and AndrewGrayGames like this.
  45. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,814
    In VS at least you can see what is actually calling what. I guess it relies on correct debugging.
     
    AndrewGrayGames likes this.
  46. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    And it was a troll question. ;) As you say - there is no right answer.

    One thing I'd caution any programmer about, though - just because a pattern "is a Gang of Four pattern" doesn't mean it's good, or suitable, or the best tool for the situation. It's just a pattern, one of many ways of doing things. I find that the whole appeal to something being from the Gang of Four to be an Appeal to Authority, a logical fallacy.

    Also, in the article I linked on the Command pattern, the guy talking about programming patterns even says, "their description of this pattern sucked." His short explanations - either a reified method call, or a way for a class-based OO language to emulate closures - was way more informative.

    As for what it's doing, the point is to set up a look-up list with a bunch of cases of, "If this condition is true, execute the command." The "ReadInputs" method, instead of becoming a logic-heavy part of the code, instead becomes more like an engine to chug through the possibilities, letting you spread out what would be a metric crap-ton* of logic into more manageable places. Divide and conquer at its clever-est.

    *: A metric crap-ton is defined as 1,000 metric kilo-craps. That's a lot of crap.
     
    GarBenjamin likes this.
  47. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    958
    haha @GarBenjamin and @Asvarduil

    I just caught up on reading the thread and I looked 3 minutes at the control manager example and thought, I wish I could understand the second example in 3 minutes :) I can't, makes me feel like a bad coder, I probably am, haha.

    But I give a vote for simplicity (no offence). The way I function is: (1) as simple as possible and (2) if this at the end does not get the framerate, optimize for performance...back from the C64 days, where all was about performance only (no loops, just written out line by line...)

    But I would like to arrive at a simple design pattern in Unity to make sure the code is readable and understandable... this was the downside of the good old assembler days...I like some of the new concepts (like the interfaces, the OnABCD methods -- they remind me a little of interrupts...)

    Great thread...
     
  48. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    25,814
    I dont use any patterns nor research them, but from what I've heard from other people, I naturally use them. The code uses whatever pattern is the most direct I can think up, ie I hate spaghetti.
     
    salgado18 and Martin_H like this.
  49. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,823
    It doesn't, I just use a technique that now you've seen. Not knowing something is not a criminal offense; however, awfully misusing something you do is typically most offensive.

    Besides, @GarBenjamin has a point - there's something to be said for a simple pattern, even if the code to it's a bit bloated. I've been messing with procedural mesh generation some, and hit cases where trying to do clever things like that have been a bad idea, not because they're bad for the code, but because of performance. Layers of indirection have a cost associated to them, that you might or might not be in a position to pay.
     
    Martin_H, sngdan and GarBenjamin like this.
  50. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,442
    @sngdan I think the goal should be to write code so simple that any programmer can instantly understand exactly how it works and what is going on. Basically simplify. It makes development faster. It makes debugging easier.

    So while you may wish to understand the second code snippet... the thing is it is not possible. He would need to include more code so you have the big picture. By itself that snippet could be processing anything. Like I said this is one of the biggest things I am challenging about modern dev best practices. The focus on always abstracting away the details. Basically if you cannot understand what something is doing that is seen as a good thing. All of the details should be hidden away. "Oh it's just a black box don't worry about it... just use it and go on your way" ... "damn we have a bug some place... can you fix that?"

    And really thinking about that it just doesn't make sense to me. Exactly who are we encapsulating and hiding this stuff from? And why? Wouldn't it be more sensible to make everything as clear as possible, as simple as possible?

    @Asvarduil hit the nail on the head. Just because you can do something doesn't mean you should. Hasn't anyone watched the first Jurassic Park movie? lol
     
    Last edited: Jun 27, 2016
    sngdan and AndrewGrayGames like this.