The 8 Game Code & Architecture Mistakes We ALL Make - Unity3D

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up I'm Jason and today I'm going to show you some signs that your game architecture might have problems while I show you those science I'll give you some practical ways to address those issues and by the end of the video it should be a little bit easier for you to finish your projects and get them released before we get started though if you're interested in game architecture and this kind of stuff make sure that you hit the like button hit the subscribe hit the little alert and most important just hit the share what we're gonna do is cover eight things that I've seen appear throughout my life and just throughout a bunch of different game projects and they kind of pop up a lot so just follow along and hopefully you get a lot from this let's get started number one having game logic in your UI this usually starts off with just a little bit of state data maybe we've got things health or a things damage or some other thing that we want to show in the UI maybe it's our weapon damage or our ammo amount and the first place that we want to see it is in the UI so we just kind of hook it up there we put an ammo amount in the UI and start writing to it and then maybe start reading from it and things get really really messy we generally don't want to have any real state data in the UI other than very specific UI state we don't want to have game state data in there at all generally you want to keep that stuff out and then use a binding method or something like that where when the base data source changes it updates that UI element now I don't want to go too deep into how to bind things up there are a lot of videos out there and I'll link some on how to bind up data to a UI but don't keep a lot of logic or state data in there in general now the other problem that happens here and this is I think a bigger one when you're starting out or more specifically when you're starting out with 2d games is that people end up putting a lot of their game flow control into the UI as well so this could be a matter of we start with the menu panel and abled and when that switches over the game panel enables and then the game panel is running the things and then when that changes over we enable another panel and that's changing things and all of the state control is based on which is enabled if you suddenly enabled two panels at the same time everything blows up if things don't enable and disable exactly right things blow up if people make changes to the UI that's generally where things get really bad because we're relying on States to be a very specific way and we should run into a lot of problems it also becomes a lot harder to debug and a lot harder to fix things because our UI elements start relying on each other and really just controlling our game so what I would recommend here is to build out some sort of a class to manage the state of your game of course if it's a very simple game you're building flappy bird whatever you don't need this right but if you're building anything that you're gonna be working on for a couple of weeks or a couple of months have some sort of a game state or game manager class that's controlling where your game is in the flow of things it is it in a mode where you're taking player input if you switch between those two modes like you have a player can do things and player can't do things mode is it in a mode where you're getting like storyline stuff and cinematics happening or switching levels or anything like that keep control of that in a class and maybe consider building out a state machine now if you haven't used the state machine for game control I also have a video on that but I was thinking about doing another one so if you're interested in learning a lot more about state machines just to control a game drop a comment below and I'll get around to doing one of those quickly if nobody cares then I'll move on to other stuff but if that's kind of thing you're interested in drop comment and let me know number two is one you've probably heard about and it's one that I mentioned all the time and people talk about all the time but nobody really talks about why it happens or how to address it and that's having mega monolithic giant monster classes these are those classes that are a thousand lines 5,000 lines 10,000 lines or 30,000 lines I've seen all the extremes of craziness right where they just get bigger and bigger and bigger and this isn't something that happens intentionally it's not like people just go in and say hey I'm gonna build my entire game in this one class I take the back most of the time that doesn't happen intentionally sometimes people do that because they think that's the easiest way to do things and it's because it is at first when you start off having one class is very easy not having to deal with a second class makes it very very simple everything's right there once your project grows it of course becomes a giant nightmare because you can't change things without breaking things when you have one big giant monolith the class tends to be very very very very brittle and make it so that you can't make changes I've told the story before about my buddy jared is working on a single method there was 10,000 lines long they couldn't make changes to the inventory system because this method was so big and so brittle that any change was likely to just break everything in fact I think that was kind of the conclusion that they came to that the whole method the entire way that that system works needed to be redone to deal with the issue it was just too brittle and took six months to clean up right and this is on like a live triple-a game so having big classes it's not something that only happens as your noob or only happens to people who don't know how to code it happens as a side effect of time as we keep building and we keep adding things on it's very easy to just slap another thing on and slap another thing on and add one more property and add one more method and we'll clean it up later and to get into that mindset but what you really need to do is just clean things as you're working split things out as you're going as soon as you see things getting large you see your class getting to 300 lines long look at it investigate it and say hey does this make sense as one class or is there a way that I can split this into multiple classes a way that I can separate the the logic here into maybe it is another system or another set of controllers or some other objects or maybe I can split out the data from the the logic or something else usually it's that the class is just doing committee things and we can split it out and separate it out and a lot of the time that's because the class is well it's doing things for a bunch of use cases and we're going to talk about that a little bit more later when we jump into interfaces number three having everything be public now this happens really often when people first start out and that's because they see things and they see that they need to make things public to edit them in the inspector so they'll create a monobehaviour add a bunch of public fields to it and then start using those fields all around this causes the very obvious problem of people sometimes getting confused between the data from the prefab and the state data of an object maybe we've got you know a weapon and it has a damaged amount on earth let's go with something even better like an enemy and it's got a health on it and we're setting up the health on the prefab we've put in a value there and then we're spawning the guy and then reusing that health value this tends to cause all kinds of problems the biggest problem being that well we're kind of reusing our initial health as a health as a current health and not separating those things out so we don't have a way to even tell what the initial health is without referencing back to the prefab and if we reference back to the prefab we can accidentally change the prefab we could reference the prefab modify its health and have that thing go up and down that's one of the issues but the other problem that you run into with having everything public is that you find yourself having a project full of spaghetti code where things are referencing properties and methods on other classes back and forth all around the place and it's very hard to follow the flow it doesn't happen all the time and it's not necessary to happen but it's very likely to happen when things are public you generally want things to be public only if they're intended to be used by another class if there's no intention of them being used by another class make them private or if they're going to be inherited from like an abstract class or a base class make them protected don't make everything public by default make it private by default and only expose it when you need to and then when you expose it really think about it think is this right should I be exposing this should this be public does it make sense that doesn't mean like overthink it and don't make anything public ever but don't just do it by default without giving it any thought think about the other opportunities and other ways that you could do it is there something else in that class that could modify the thing should that class be modified by the other thing if it's a property or should the other thing be calling my methods if not then change it up and just start to think about it and be aware whenever you have too many public things it's usually a very bad sign number four is having setters with side effects to show this I really wanted to bring up a code example so here we go we have a vehicle and our vehicle has a damaged property on it and when we get hit with any collision we're just saying damage plus equals one we'll just add one point of damage to the thing nice and simple right and it might seem like okay something's damaging the vehicle the damage amount is going up but let's um take a look here let's go take a peek at damage maybe we see that hey every time we're hitting this guy we're getting a spike we're getting a lag spike or a little bit of slowness or something else and we just hit f12 and go out and here and expand it and look and see what's going on we'll realize that our setter here isn't just setting an inch so when we're doing plus equals 1 our setter is doing some other stuff it's setting that damage value to the new one so it's reading damage calling the get and then it's setting it to the new value of that plus one right here and then we're calling this send a damage method and then just incrementing hits taken okay so we're going to send a damage take a peek expand this out and I didn't implement it but I've seen this time after time after time on all kinds of projects not just multiplayer projects but single-player stuff where it's maybe not a network thing but something else but something is happening in this send damage maybe we're sending out a network call we're writing something off to a database or we're just performing like something that takes a screenshot who knows it could be some kind of crazy thing that's happening that's slow a lot of the time this would be like a network call though so every time we change our damage our our network call is being made and it's so imagine we set something up that's like incrementing damage a couple times that we have a loop here for one to ten maybe this is some damage over time thing I don't know and we loop over it now we're doing it ten times we're sending that message ten times and we don't know it the reason that this is a problem it's not a problem to send the damage or increment the number of hits taken it's a problem to hide that this looks innocuous it looks simple like it's not gonna hurt anything and it's causing a ton of extra work this is a good way to accidentally kill your project and accidentally cause all kinds of performance problems it also really just hides the complexity of what's going on here and it's probably doing things that we don't necessarily want to do but there's more it hits taken we go check out hits taken we're just incrementing that right let's expand it out oh yeah that one also does this so this one has a setter where we check more stuff we increment the value of hits taken by the by the amount in fact that's wrong so we break it that should be equals the value so we set the value here and then we check to see if it's too many hits it's too many hits we call break armor which who knows what that does maybe it breaks all of my armor here it just throws an exception and if it's not then we save off that number of hits and write it out to a database again some of these use cases may not be exactly what you'd have it could be just that you're writing out to a web request you're saving off some player state data sending off some you know HTTP requests to a server or to some other thing that you're doing or maybe you're just writing player prefs and every time you change the value you're writing that player preface thing for no reason hurting performance and just doing bad things for no good reason because they're hidden oh really because they're hidden so how do you get around this how do you avoid having this problem this secret little hidden stuff well what I would recommend is have your setters never do anything special just have them be kind of blank get and set they just read the data unless they're doing some sort of special caching if they're doing a caching like a singleton does kind of where we get something store there the one time and we don't pull it again then sometimes that's okay but for the setter if you want to do something special make a set method make a set method that either has should I do the hard part as a parameter like set and then an optional thing to propagate that on the network or replicate it out or save to the database like a boolean parameter that defaults to false or have a set and then maybe a set and replicate or a set and persist type method that does both of those that does the set and the persisting part at once so that you can separate that out and make those calls intelligently so that when you want to change the value you can change the value but you can change it without necessarily doing the special stuff now if every time you change it you need to do whatever the special thing is then just spell that out in the method right have that set and save method and only use that and then when people use it they're gonna know hey every time I call this I'm also saving so let me be intelligent about it maybe cash the number up there whatever it is that I'm saving and then do it all in one shot all right number five is when we have giant prefabs I've been you know guilty of this before I've done it myself plenty of times or they just build up a prefab and I started off small and slowly start adding more and more things to it this often begins with UI prefabs we've done it with characters items all kinds of things and the prefabs get bigger more complicated and harder to manage now this isn't one where I think I really need to even explain the problems the biggest problems are just that it's hard to work with other people it's hard to make changes to it and it's hard to save and then it's also hard to reuse functionality across a big prefab so those are the issues let me just tell you what I would recommend to fix it and that's to split your prefabs into multiple smaller prefabs if you have a big UI put that into a level consider using a scene as a prefab or a scene full of prefabs instead of a giant prefab or consider using nested prefabs the new nested prefab system is pretty easy to use and it's available now so you can set up a prefab in the nest other child prefabs underneath its and you can have a bunch of little prefabs and then one that's just kind of a container for them the other option that I would recommend and one of the ones I really like is to use prefab variants these came with the new prefab workflow as well and if they make it so that you don't have to create a bunch of different prefabs for things or you don't have to create a very complex prefab I guess so what I've seen people do is like maybe create a monster and under that monster they've got ten different models obviously not the best way to do it and there are other ways around it but another alternative to just having all of those and enabling and disabling to get the correct one available is to just use prefab variants so if you're doing something like that consider the variants they allow you to just make a base prefab that has the the core part of the prefab all of the functionality and the logic and then swap out components or visuals really really easily without having to write a bunch of code and I get that that's why a lot of the time people do that they'll build a prefab with a bunch of things underneath it because they don't want to write the code to load those dynamically maybe it doesn't matter for your project but going to variants will make it so that you don't have to do that and make things easier now if you're interested in prefab variants again just let me know drop a comment below and I'll do another video on how to use variants to shrink down prefabs maybe do another one on you eyes too just let me know in the comments so if that's the kind of thing that you want to see number six not using interfaces and I understand why this happens a lot of people are listening on what's an interface I've never even heard of that and if that's the case I highly recommend you just go look into interfaces watch one of my videos on how to use interfaces in unity and well listen to the rest of this cuz I'm gonna explain why it's a problem but first I want to mention that it is really easy to misuse interfaces it's easy to add just too many interfaces and add interfaces where you don't necessarily need them when you start off with them it kind of happens to a lot of us where we'll just make interfaces for everything even though we're not ever going to swap out the implementation it's also just is bad though to never use interfaces to not figure out what they are not learning how to use them and not get the benefits that are there because they really have a big part to play I think in just general c-sharp development and they're really helped a lot in game development so if you're not using interfaces you need to figure them out you need to understand them and get a real good grasp on how to use them in your project now I want to give a quick example or a quick explanation of cases where you would want to use an interface and the biggest ones are where you have a system that needs to interact with two different types of objects but in the same kind of way maybe you've got a player or a character and a crate and they both need to take some damage one way you can do that is have like a shared health component that's just a mono behavior that's a health that takes damage and that's if you look for the health part on them and they take damage and that's something that a lot of us will do set up something just like that but then you run into these weird cases or say you've got a health component but maybe your crate acts differently when it takes damage it doesn't die maybe it resets or it um and maybe it's not a crate it's a thing that you shoot a couple times it opens up and then it closes and you got to do it again and you want to override that functionality what tends to happen is then we end up with a health script that's more complicated and it has these special case checks - oh when I die don't die open up a thing or here are the events to fire off when I die or it does something different and we have to hook up things either in the editor or have designers change things and we end up with a more complicated health script instead what I would recommend and what interfaces allow us to do is define a common interface like an eye take damage or an eye have health or something like that and give it a public method while interface methods are all public you'd give it a method like take damage and then you make both health components your player health or your character health and your great health implement that I take damage interface they can implement it in different ways they can do different things with what needs to happen and you don't end up having well dirty code that does different things based on what type of object it's hooked up to so look at interfaces that's only one of the dozens of different things that you can do with interfaces or use cases like I mean I could think of probably an infinite number of them oh not infinite but you get the idea there are a lot there's one other benefit though and that if you use interfaces it makes unit testing your code dramatically easier now you might think like hey I don't unit test my code you might want to one day you might get into the case of hey I'm tired of things breaking I want to have some tests on my code and know when stuff's going wrong and be able to prevent that interfaces are kind of the first step along the way of making that possible number seven completely ignoring garbage collection and performance issues this happens a lot this happens for pretty much everybody and it's I think a side effect of us starting off with prototypes and practice projects where it just doesn't matter having garbage collection problems in your hackathon thing or your little game that you threw together in a week isn't gonna matter nobody's gonna care nobody's gonna notice but it gets you into a habit or upset of bad habits where you can start just allocating things that you don't necessarily need or doing things that are bad for a performance for no real reason other than you just didn't think about it and there may be easier faster simpler ways to do it that are also more performant so you want to get into the habit of at least investigating your garbage allocations in the profiler and checking on your performance a bit don't do it kind of obsessively like don't be in there every time you make a change go in and profile that change you might be in the case where you need to do that but for most of the time most of us don't need to do that and you don't need to get too worried about code as you're going through it if you see little things where there's a minor performance increase don't don't stress about it and don't think about it too much you may end up breaking something if you're not sure especially if your codes not tested but if you see bigger architectural issues or bigger problems where you know something this happening that doesn't need to happen or you know there's an easier faster way to fix it try to fix those up and most importantly look at what the profiler is telling you find the problems in there because that's gonna tell you where the actual issues are and prevent you from wasting time on things that don't matter and kind of let you focus on the stuff that does matter number eight this is the last one and probably one of the most important ones and that's not sharing what you're doing not sharing your code and your architecture and not getting any feedback on it this also includes not looking at other people's architecture if all you ever see is what you're working on and maybe the stuff that you create and perhaps it's the stuff that somebody else created before you you're not gonna grow and you're not gonna learn new ways to do things and a lot of the time and will come into a project and will see stuff that was there before and we just kind of pick up those patterns I know when I first started out coding you know decades ago that's exactly what I did right I don't I guess was less than decades single decade plus ago I started I look at code and I kind of followed and copied some of those patterns some of those patterns were from people who didn't know exactly what they were doing at the time and didn't like those patterns later right they come and go why are you doing this oh hey I copied that and said oh that was me that was terrible I shouldn't have done it that way let me show you how I do it now and if you just kind of stay with one project and one example it's easy to fall into that where you just kind of go with that thing and you don't grow and try out new stuff you don't learn new easier ways to do things to keep stuff simple and fast at the same time so I highly recommend that you share as much as you can if you're able to share your projects you're able to share your code share them with other people that you know run friends through it explain the code to them especially if you have other friends at work in game development explain things to them get feedback on them and get advice from them and start implementing the advice try to do even if you can do it live there if you can get on a call with somebody and just kind of go through and get step-by-step feedback and start changing things up that is an amazing way to just get better at it or just look at other people's stuff like I said before find other people's game architecture or find other people's code fine that want you to look at their stuff go look at their stuff give them feedback you're gonna grow you're gonna learn more about it now if you don't know where to do that it's kind of hard to find places for that I'm gonna put a special link to the discord server down below it's normally I think just just patreon we're getting in there but I think you still get a special badge if you're on patreon also if you're on patreon definitely special thanks really appreciate it show off the special badges and discord to everybody else and if you have architecture stuff just feel free to hop in just join us and talk and share your stuff other than that most importantly again don't forget to share the video if you got to the end just hit share and drop it wherever it doesn't matter if none of your friends like game development stuff I don't think for sure anyway thanks again appreciate it OPI is like the stuff if you have questions or comments just drop them below I'll try to follow them and a lot of other people are also great at answering those really appreciate it alright thanks again bye you
Info
Channel: Jason Weimann
Views: 77,500
Rating: undefined out of 5
Keywords: game dev mistakes, game developer tips, game development mistakes, game design mistakes, indie game development tips, tim ruswick, devlog, game dev underground, game devlog, solid, clean code, clean architecture, game dev log, unity, brackeys, unity tutorial, how to make a game, game development, unity devlog, unity game devlog, game devlog unity, unity3d, unity3d college, game programming patterns, game dev, indie game devlog, gamedev, game architecture
Id: 8Hy4JvtfUb8
Channel Id: undefined
Length: 25min 44sec (1544 seconds)
Published: Sun Nov 03 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.