The Most Common Mistake Beginners Make in Unreal Engine | UE5

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
imagine this problem you have a widget that should update the number of enemies remaining as you kill them and you have a door that should open when all enemies are dead so all of these objects need to communicate together the widget the door the level even the enemy and the player so what is the right way of implementing this and how do you avoid the most common mistake the answer is the Observer pattern welcome everyone to this new series on software design patterns in Unreal Engine starting with in my view the most important one if you don't know what a design pattern is it's simply a template or a description of a solution for a very common software engineering problem the problem here being how do I get different objects in my game to communicate and share information with each other in a way that is scalable and easy to maintain let's take the example that I just showed you earlier how do we update the widgets in our UI when an enemy dies the most common mistake people make here is they say well in the death function of my enemy I'll just get a reference to my widget and change the count so this is a mistake because what you did now is called coupling the enemy and the widget or also known as creating a dependency between these two separate objects now this is bad because now there is logic related to the widget inside the enemy class this means that if later down the line you want to change the widget you have to change the enemy as well and vice versa and if you keep creating these dependencies then making one simple change down the line means that you probably have to rewrite a huge portion of your game which can get messy very very fast so what is the Observer pattern and how does it help us here well the Observer pattern and sometimes referred to as the publisher subscriber pattern is based on the idea of having a signal broadcasted or published when an event occurs such as an enemy dying and another object somewhere in your game subscribes or listens to this signal that was was broadcasted and reacts to it that way you can have one object broadcast a signal from somewhere and not care about what happens with it then multiple other objects or actors in your game can listen or subscribe to this event and react differently to it so how does this work in Unreal Engine well in blueprints it's very simple it's done through defining event dispatchers and in C++ it's done through defining a delegate now in this tutorial I'm going to focus on the blueprint implementation but the idea itself is the same in C++ just the implementation is slightly different uh and I will leave additional C+ plus resources in the description so let's jump into our first practical problem all right right now when I kill an enemy the widget uh count doesn't update so let's see what we can do well let's jump right into our enemy blueprint and see what we have uh well right now I want the enemy to be a publisher to broadcast the signal that hey I died if anyone's interested do something so here in the death event we just do some ragd doll and uh disable some collisions and that's it so what we're going to do is on the left here we're going to add an event dispatcher and we're going to call it on death now usually event dispatchers you name them on something uh because it's a trigger for something that happened so now that we added an event dispatcher this will be the publish event or the broadcasted signal so at the very end of the death event here I'm just going to drag this event dispatcher and say call Now by doing so I just publish to this event after uh the death uh functionality has finished now you can also pass input to this if you want in the uh details panel when you click on the event dispatcher you can add inputs um to uh pass information to whoever is subscribing to this event but in our use case we we don't need any inputs so I'm going to leave it like that and that's all our enemy has to do to become a publisher all right so now we need to subscribe to this on death event in our widget and do something with it so let's open up our content browser and go to our widget and in the graph here right now all I have is as soon as the widget is constructed we just get the length uh of all the enemies in our level and set that as the uh enemy count text so that's why it's starts with three um but it doesn't decrease and this doesn't change because we're only doing this on event construct well now you might be asking well can't I do this on tick then and keep checking uh how many enemies are left or how many enemies died and then update this value well yeah you can do that but you'd be checking this around 60 times a second for no reason because it only changes once every few seconds or even every few minutes so this is a waste of resource sources and bad for performance so instead what we're going to do is we're going to subscribe to this event now to subscribe we use the bind keyword uh or bind function from Unreal Engine uh but we need to First Loop over our array because the bind you bind to a specific reference of the enemy meaning that each one of these enemies is broadcasting or publishing a separate onde event so I need a reference to each one of them and bind to their own on death event so here I'm going to just pull off of this and say four each so now I'm looping over all three enemies and for each enemy I'm going to search for bind on death on death is the name of the event that we event dispatcher that we added and over here I'm going to pull and make a custom event and I'm going to call it um I don't know uh decrease enemy count all right so now this in the loop I'm only binding but in here this is what will actually happen when the event is published so what I want to do is um get the number of enemies in my array so let me actually make that into a variable so I'm going to promote this to a variable call it enemies count and all I'm going to do here is get my count and say decrement decrement just means subtract one and after that I am going to set the text again to this new value and that's it so as soon as the enemy dies um uh and a signal is broadcasted called on death and here I'm binding to it on the event construct and each time it's called I'm going to decrease one from the number of uh enemies remaining so let's test this out so now enemies remaining is three and as I kill them it decreases by one by one and by one perfect now the most useful thing about this pattern is that you can have multiple uh actors or objects subscribing to the same event and doing different things so right now uh I want when all of the enemies are dead this blue door to open so I'm going to subscribe to the same on death event and then open this door but what's the right place to do this well I could have multiple doors opening and closing for multiple reasons so I'm not going to do it in the door blueprint but in this specific level this door opens when all enemies are dead so I'm going to do it in the level blueprint so to open uh the blueprint specific for this level you click on this icon and say open level blueprint here in the Lev level blueprint I just um add the widget I don't do anything else and um so we want to open the door uh when all enemies are dead now to open the door you simply get a reference to it so I if I click on the door and then go to my uh blueprint I can rightclick and it will already have a reference for my door here say create reference this just takes the element that you were focused on uh in the level and the door has a function called open and that's how you open the door U so I'm just going to create a new custom event here and call it uh Open Door so whenever this is called uh the door will open but now when do we want to call it is when all three enemies are dead so we're going to do the same thing that we did in our widget here so we're going to get all actors uh of class BP enemy and we're going to Loop over them well first let's get their length to store how many we start with promote that to a variable called enemies count so now we know that we start with three enemies and now we Loop over each enemy and bind to the on death uh there's also a shorthand for bind called assign on death what it does is it binds and creates the event for you uh so you don't have to bind and then pull and say cust it's just a short hand and here we're going to name this event uh check enemy count or something because we want to check how many are left um all right so now when an enemy dies uh I want to also decrease the enemy's count so I'm going to get this and say decrement again we're decreasing it by one and now I'm going to check uh is this number equal zero so are all enemies dead and I'm going to do a branch if all enemies are dead then let's uh I don't know wait 1 second and then call Open Door all right now let's test this out so I'm killing enemies the widget is updating as soon as all enemies are dead Waits a second and the door is open yay and we're free to go great now let's quickly recap uh what we've done the Observer pattern is useful when you want to communicate between objects in your game when an event occurs it allows you to publish an event from one place and subscribe or listen to it in multiple different places and react differently we did so by calling the event dispatcher when the enemy dies thus publishing an event then we bind to this event in our widget to update the count of enemies in the UI this is our first subscriber and we also bind to this event in our level blueprint to check when all enemies have died to open the door and this is our second subscri subcriber so what are the benefits of this approach well now we have decoupled our enemy from our widget from our level thus having them all independent actors and making them very easy to update and maintain in the future because they all have their separate concerns and don't know anything about each other we also ensure that our code is easily extendable meaning that we can add new Publishers without changing the subscriber and vice versa and most importantly we make our codes easier to maintain and less prone to errors because the publisher and the subscriber are independent from each other so this reduces the risks of unwanted side effects now in future videos of this series I'm going to be explaining different design patterns such as the object pool pattern or the component design pattern and I'll be explaining when to use them what are some of use cases and so on so if you find this useful or interesting please consider giving a like And subscribe and as always always thank you for watching and I'll see you in the next [Music] one
Info
Channel: Ali Elzoheiry
Views: 69,171
Rating: undefined out of 5
Keywords: Beginner mistake, Beginner tutorial, Beginner tutorial unreal engine, Design patterns in unreal, Observer pattern, Software design patterns, Ue5, clean code, common software design patterns, design pattern, design patterns, game dev, game dev motivation, game dev tips, game dev tips and tricks, game developer, game development, indie game dev, indie game development, ue5, unreal, unreal engine, unreal engine 4, unreal engine 5
Id: YFtLd-bKl-U
Channel Id: undefined
Length: 12min 17sec (737 seconds)
Published: Fri Feb 16 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.