The 6 Design Patterns game devs need?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up I'm Jason and today you're gonna learn about something that all game developers really need to understand and that of course is design patterns like you probably saw in the title down below now if you don't know what design patterns are that's actually perfect because these are really important and we're gonna give a good introduction into what they are how you would use them and how they're gonna make your game development career or game development experience in general just a whole lot better you're already probably using some of these patterns and don't even know it in fact one of them isn't even necessarily code related and could be causing some real memory issues now if you're already an expert and you know all of the design patterns then hey just follow along and let me know if you see any that are missing if you think of a design pattern that you think all game developers really need to understand that's just not in here drop a comment below and let's just kind of add it in there and discuss it and maybe we'll put it into a future video now I want to get going well before I get going I want to share the game programming patterns book because it's just a great resource it's freely available on game programming patterns calm I think just search for game programming patterns and you'll see it I'm also gonna put a link to the book down below maybe I'll use an affiliate link for Amazon or something and the final thing before we get going is to just please if you're interested in design patterns or game development in general make sure that you share this video or very least hit the like button it does help a ton views go up everybody has a blast and everybody's code ends up better so let's get started with the single most use pattern and that is the singleton pattern this is a pattern that most of us developers run into pretty early on in this pattern as described on Wikipedia is a pattern where or that restricts the instantiation of a class to a single instance and that's kind of the whole idea behind the word singleton now you're gonna hear a lot of bad things about Singleton's - it is very easy to misuse them as some global data store that a lot of things are reading and writing to you and cause problems but overall don't just write off single things and think that they're bad that you can't use them you will find Singleton's in almost every project and you'll probably want to use them quite often so what does a singleton look like let's take a look at some code real quick I have this scoretext object here and it doesn't have the word singleton in it anywhere it doesn't have any real reference to a singleton the way that you can tell that that's what this is though is that I have a public static scoretext instance and now this instance part might be named something different in your Singleton's it might be in soar this or thing or whatever a lot of the time instance is a pretty common word for it but the public static version of this class or the public static instance of this class here kind of tells me that this is probably a single can already set up the instance gives it away definitely so what's happening here is in awake we just set the instance to this now our singleton here isn't actually following that whole restriction it's not destroying any existing ones we could write a singleton that does that so we could say hey if instance is not null then destroy the new thing that's being created or maybe destroy the old one and then set instance to the new one but here we just kind of override it and we don't care because it's not going to have any impact now why do we do this well so that we could do something like our ad score call let's go take a look at this inner project see what it looks like and how it would be used so here's a very simple singleton set up with my very boring bubble clicker game I can hit play and go click on a bubble and watch them pop and look at my bubble count go up now the thing that's using the singleton here as you can probably see with my selection is this click count text which right now is showing a value of seven and it goes up every time I click about or click a bubble atom value click a bubble right so how is that work let's open up the bubble pop script and take a look so if we look down here in our mouse down what's actually happening is we wait for a click and when we click on something Mouse down fires we call our animator set and trigger to set the pop and that's just playing that little pop animation 0% related to our singleton our singleton is right here on line 14 where we're calling score text instance adds 4 and passing in a 1 so we're just adding one point to the score text so now our bubble pop doesn't necessarily need a reference to that score text now there are of course other ways that we could do this we could have a reference assigned in here where we maybe add a score text and drag it in there but we don't want to drag that in on every bubble pop we can do something like a find object of type here but we probably don't want to scan for an object every single time we just want to keep a reference to that single one because there's only one around so here a singleton just works now as projects Krogh and single things can get a little unwieldy and messy but most of the time in simple situations a singleton will really just solve a lot of these problems let's move on to number two though that's the observer pattern the observer pattern is another way for responding to events or things that happen in the game that we may or may not want to directly tie into our game now that might sound a little weird might not make a lot of sense so let's go take a look at an example here say I've got my boring bubble clicker and I want to add in a way to maybe play a sound whenever I click on a bubble but I don't want to have like a million audio sources in here I don't want to add an audio source to every single one of these objects because I know like hey I'm gonna have kind of audio source maybe it's gonna overload and play too much and maybe I want to add some extra control or something so you want to have a way to be able to toggle on and off what sounds play or control that so how would I do that the way I would set that up is using the observer pattern and we're gonna go into let's see example two here and I would create something like this an audio source that has its own script so outside of this audio source this scene has changed 0 didn't have to go in didn't have to change anything on the bubbles you have to do anything but we are gonna hear audio let's go try it out and then see what how that's actually hooked up so I cop in up some bubbles and pop said disable that suddenly it's silent ok so how is that working now this script might look a little bit weird for anybody who's really new to programming but what's actually happening here is we have an awake method that's getting fired early on right away when the object is created we're taking our audio source that's on this object and caching it so we just take this audio source here cache it into a variable so we can use it later then in our on enable so when we the object on we register for an event and an event is the thing that we can listen to from multiple places and just get notified when something happens so here we're registering for an event called on any bubble popped and we're registering it with this plus equals and that says whatever this happens add this method to the things that you do so play pop audio is going to happen and if we look at play pop audio play pop audio is actually just playing the audio source now if you're not familiar with this syntax this is just the expression body method syntax and it works for methods where we only have a single thing that's happening so I could also alternatively write it like this but I wanted to show it how it's normally written when I have a single thing for a method the final thing that we have here is a non disabled which does a B registration and removes this now the reason that we do that is when we register for an event if we don't deregister for an event it never goes away so technically if I didn't have this and I disabled my object and enabled it I would get two calls to this play pop audio and I really want to just avoid that we generally want to deregister events whenever we register for them and the event system is essentially an implementation or a framework that we can use to do the observer pattern now let's go take a look at what this event looks like and how I actually created the code to hook it up and make this all work so if I go here I can hit f12 and I can see right here that I have this public static event action on any bubble popped and I'm gonna just just delete these two regen statements because I feel like they might kind of confuse things all that really matters here is this event and normally the place that I would put an event like this is right up at the top so I'm gonna hold ctrl alt and shift with that all selected at the up arrow a couple times and just move it up to the top because that's just where I like to have my events now the way that this works is down here on line 18 on line 19 actually I guess so here let's delete 18 now its line 18 we have this on any bubble popped and then a question mark dot invoke what this is actually doing is saying hey this is a bubble popped event because of this event keyword here and if anything is registered for it if anything is has had a + equals and then some method then go call that and that's what this invoked is now the question mark here just saying only do it if something is registered if I don't have the question mark and I delete that then it's gonna give me an exception and in fact my code editor which is writer and a lot of other code editors give me a little warning that it might be null and might give me in there so I need to put a question mark there and that's really the core of the observer pattern being able to register and get notified of when things happen and then being notified of those things happening it's also worth noting that we can pass in arguments into these events or these actions so I could have an action that perhaps passes in an integer and then my on any bubble pop would need to take an integer in its method that was registering for it like if I went in here this would need to take an integer parameter and that could maybe be like a volume or something else that we maybe register for normally that's like a text value for a score or something else that's getting passed around but I wanted to make sure that you understood that that was a possibility as well the next pattern I want to talk about is really game specific some game types use it everywhere and some game types will never use it and that is the command pattern and I want to give a real quick demonstration of what it looks like to use the command pattern so here I've got a bot setup with a simple nav mesh agent and you can click and he'll move to wherever I click now if I click here and I click here and I click here and I click here you see that he never actually finishes going to those spots he'll just go to whatever to the most recent spot I clicked quest because all I do is set destination on a nav mesh agent and if you're new to nav meshes that's really all you need to do to make a move but if we want to queue up these locations and make them go to different positions a command pattern is one great way to do this now let's take a look at what that implementation looks like so I've got my capsule character here who just has again that nav mesh agent and a command controlled bot script let's open this up and if you look right here here's the part where I'm actually setting the destination and here is kind of why he's acting up by disable this line of code and enable the line of code right here by deleting comma in fact I'll just delete line 41 it's going to work the way that I want it to I'm gonna show that and I'm going to show how the commands actually work and how this is accomplished I also want to just talk about while I'm going through this and getting this loaded up that commands are used for all kinds of things games that are really common for this are things like RTS is where we have commands that we're giving to you and it's kind of like what we're doing here online games that are somewhat asynchronous any game where you're sending up a request to a server and then waiting like a you know I can think of a hundreds of different games every almost every mobile game that's asynchronous is doing some sort of a command pattern where we send off command and get some sort of a response back so let's take a look at this now I can click and queue up a different bunch of different spots and you should be able to see where I'm clicking in he just kind of goes around to those spots in the order that I clicked them now let's dive into how that code actually works how do we set up a command system I also want to note that we could do other things we don't have to necessarily just do moves so let's see we got our command controlled by here and as I mentioned he's got the nav mesh agent and in our start we actually cache that knavish agent we also have here a queue of commands now command is a class that we've written you can see it right here we'll go take a look at it in a second and Q is just a list or a collection of things in order it's just a queue that you would see at a grocery store or anywhere else a line of things where the first one in is the first one out and then finally we have a command that is our current command where we just keep that and we know what command we're currently working on in our update method we listen for commands and then we process commands not much to it let's go look at listen for commands first though so listen for commands just check to see if we press a mouse button down which is the left-click that's what 0 is we do a ray cast using our camera that main screen point to Ray because the demo so if we don't care about using camera domain and screen pointer ray will give us a ray right in from the camera and or use that main camera that's tagged the final thing we do is a ray cast and if we hit something we just in cue up a command to move to that point and we pass in the agent so we're creating a new move command here well fact let's just far move command equals that and then we're in cueing that just to make it really obvious so we're adding in this command now commands is of type command and move command is a subclass of that so it'll go right in there like call this command or I call it move command and it's going to work exactly the same now let's go take a look at the process commands so after we listen for commands we process them let's see what processing them looks like and then look at what a command actually looks like so processing limb is pretty simple if our current command is not null and our current command is not finished we do absolutely nothing so we just wait until this current command is finished there are a lot of different ways that we can handle commands being finished we kept it simple with this one the next thing that we do is check to see if there are any commands ready to be DQ'd so if there are no commands left then just return because there's still nothing to process final thing we do is d/q the current command or the next command and this is one of the methods on the queue that just gets the next one in line and then we call execute all right that's all there is to this processor so what does the command actually look like let's hit f12 go look at execute I like that it's an abstract class with absolutely zero implementation we have an abstract void method called execute and an abstract bull named is finish and an abstract class here now if you're not familiar with abstract classes don't worry you'll learn about them as we go and I have some videos on them but essentially it's a class that cannot be instantiated that must be inherited it's just like a monobehaviour you can't just add a mono behavior itself you have to have a new class that inherits mono behavior it's the same for these commands so let's go take a look at the command that we're actually using which is our move command and I have left that in this file I probably should have it in its own class file I wanted to note that because it's kind of ugly but it's okay being here so our move command because it's not a mono behavior can sit right in here and it takes a couple parameters for its constructor so the constructor here takes a destination which is just the vector 3 and the agent that's what we were passing in when we call this new move command right here when we created it we pass in the point and the agent ok let's just scroll down a little bit more and go take one more look the next thing that we do is execute which sets the destination to that destination and then we have is finished which just checks to see if the remaining distance is less than point one very very simple so you can probably imagine how this code would look outside of the command pattern and you might be wondering well why go through the process of making this a pattern if I'm just queueing up movements the nice part about this is that once you've done a command pattern like this we can start to implement further expansions like an undo so we can undo an action from our commands we can add in different types of actions so that it moves to a position and maybe guards or starts digging or picks up a resource or fights or whatever the thing is that we wanted to do we can start to mix and match these and start to give commands and then get a lot more control over it it's very easy to build similar systems that are not using these patterns or kind of implement these patterns in a halfway done very specific way to the very specific thing but just remembering that these patterns exist in that we can reuse them like this I think is extremely valuable let's go into the next pattern though and that is the component pattern and if you're not already aware of this you've actually been using the component pattern pretty much non-stop as you build in unity unity is built around a component pattern or a component design pattern for putting together game objects and prefabs when we add in our different components to objects so we drop a sprite renderer or a physics component like a Collider or a rigidbody those are all components that we're adding in and building up now when we talk about using the component pattern as unity developers it's really about building out smaller components and composing our objects of these smaller components so instead of necessarily building like a heavy tank class that's a big heavy pink with two guns on and thinking of like an RTS game we build out a mover class and a turret class and kind of combine these things and the tank would be our prefab and that would be the object that's the combination of all of these components so I wanted to point it out because the component pattern is really interesting and important one and it's one that people don't realize that they're regularly using the next pattern want to talk about is also somewhat in that vein and that's the flyweight pattern this is another pattern that we sometimes don't realize we're using because a lot of the time in in the more important parts for game development the flyweight pattern really applies to our art assets more than our code so the idea behind the flyweight pattern is to reuse data and have a shared same data so that we're not creating copies of all of this data so if I've got 3,000 items that have that are all the same item I don't want to necessarily have 3,000 strings of these giant descriptions of it I want to have one that kind of defines that item and all of these things refer back to it that's a small part of it though when it comes to actual game development a much bigger issue that I see is people accidentally miss using things like meshes and materials or game objects or ending up with a lot of unused or wasted memory now to give a good example of that I wanted to show a way that sometimes we misuse properties on materials to set colors and a way that we can reuse the flyweight pattern or pick an implementation of that flyweight pattern to make things a little bit better and that is with setting colors of a material so let's go into the next demo so here we've got a scene with a bunch of cubes that are set up to just randomly change color when I turn on this change color script and I've also pulled up the profiler under window and analysis and profiler and switch to the memory view so we can get an idea of the material count and the material memory used now these numbers are going to be small because we're using a very blank tiny little texture or no texture at all a very basic material and we're just swapping colors on cubes but this could scale up as our project grows I want you to see what's happening though so I select all of my cubes and I go check this box and look at that our materials I'm almost double dancing with our memory usage let's go take a look at how that's done and how we're actually breaking that flyweight pattern here so what we're doing is calling set color here on a material so we get the renderer in our awake and cache that then we get the material and call set color or call color equals pass in a random color that we generate but it's also the same as this set color call down below so sometimes people might think okay well maybe this will fix it I just need to call that color this is actually wrapping it and they do the exact same thing we'll get the same results that's not what we want to do what's actually happening here is that when we do this it creates a copy of that material with that random color instead what we want to do is update the existing data on that instance instead of creating a whole nother copy of the material we just want to update some of the material property data on that specific instance so that it can apply so let's take a quick look at how we would fix this and how we could use that flyweight pattern to avoid this problem not recreate a material every time and we've got this down here in this update method if I delete that I need to actually go get rid of my old update then instead what we can do is get the property block of this renderer and we can set the color of this property block object this material property block to a random color and then set the property block and this actually does that update without causing the memory wasting that we just saw so let's go try it out we hit play and go select our cubes and we watch our materials and material memory count again no increase and we still have that same effect all right now I want to go on to the last and I think probably the most important one which is the state pattern this is a pattern that gets used in almost every type of game in some way or another now sometimes we use the state pattern only in our animation controls the Meccan M system is an example of a state controller state machine system where we control states and transitions visually a lot of the time though will write these code based state machines that control the state of our objects or our game flow to make them do anything from what transition from menu to menu or menu to gameplay to control a bot that runs around fights enemies picks up things or goes and builds houses or whatever the functionality is that we want when we were building up these more complex States we can also have very simple state machines that control things like a button or a lever and when we pull this lever over to the State it can only go into the next date or whatever it is there are a lot of different scenarios for state machines and if you really want to learn how to write a bot with a state machine or get into state machines because they are important just check out the video that I did where we dive into how you use a state machine to control what about is doing have them go pick up things bring things back run away from enemies all that kind of fun stuff the things that really kind of bring some life into a game now I mentioned before that there are hundreds of design patterns out there they're probably less than 100 really but there are a lot of them out there there are definitely dozens and dozens of them most of them won't really apply to your day-to-day work the ones that we've talked about today I use almost regularly so I would recommend you at least get an idea of what they are try to understand them maybe don't try to shove them in everywhere but just recognize when they will fit and when they can help you and then when you find those scenarios when you say like hey this seems like that command pattern might fit that's when I would recommend diving in deep go look at a bunch of videos on command patterns read a lot of resources look at examples and find the implementation that works best for your project is there are going to be different implementations that vary a little bit here and there and which one is best for you it's just going to depend on you and your project so dive into it have a lot of fun with it and make sure that you're learning this stuff and your code will just get better you'll find that projects get easier to complete in you probably have a lot of fun with it other than that again I want to say special thanks to everybody on patreon you guys are awesome and please don't forget to hit that like button and remember if you have comments or just some other patterns that you think I should have mentioned just drop them down below I want to know cuz this is the list that I came up with it was the best I could do but I probably missed at least one or two that I'm gonna think ah man I should have covered that and I think that's oh and finally I should wrap it up with if you're interested I also have some courses where we dive into this stuff you find resources about that down below and lots of other videos about that stuff alright thanks goodbye
Info
Channel: Jason Weimann
Views: 189,577
Rating: 4.9575114 out of 5
Keywords: design patterns, game dev, unity 3d, game programming, game programming patterns, head first design patterns, programming, design patterns explained, design patterns tutorial, unity, unity3d, singleton, factory, command pattern, command, game undo, monobehaviour, monosingleton, game development, design patterns made easy, brackeys, beginner, gamedev, Flyweight Pattern, state pattern, observer pattern, component pattern, unity devlog, unity tips, unity tutorial, finite state machine
Id: hQE8lQk9ikE
Channel Id: undefined
Length: 24min 20sec (1460 seconds)
Published: Sun Jun 07 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.