 This video was brought to you by my patrons, a special thanks to God of Grants, Kishu, Kyle, Mike King, Shayla and Tic Biscuit. Thank you so much for your support. If you want to support me and the work I do, you can also become my patron. All the links will be in the description. This video was inspired by Bracket's video about how to make a health bar in Unity, but instead we'll see how we can achieve this UI element in God of Engine. At the end of this video, we will have a functioning health bar that is decoupled from the actual health object. This way, we are more compliant with object-oriented principles and we can actually reuse this health object in many other ways, aside from the health bar. In the next video of this mini-series, we will also see how we can use this health bar and this health object in 3D and 2D actors. So it will be inside the actual game world and not just a HUD element. So without further ado, let's get started. So let's start with the health object. In God of Engine, since the engine is designed with object-oriented design in mind, we will also try to be compliant with this paradigm. So in my experience, the most important principles of object-oriented design are the solid principles, in particular the single responsibility principle and the interface segregation principle. So instead of having two responsibilities in the same object, both managing the health values and displaying the health values, we will instead break down this responsibility into two objects. So we'll have one for managing the health and another for displaying the values. So let's start with the health object that will manage these values. I will create a node because this way we can use this node easier to compose new scenes later on and also because we use the ready callback to initialize this object. So let's call this health and I will save it inside this health folder, health scene and let's attach a script to it that will also be called health. Let's take rid of everything here and let's start by exporting a variable. And I will export an integer because I think it's easier to handle. And this will be the max amount. And by default, it will be 10. We are exporting this value because by exporting this variable, we can set it through the inspector. You can see that we have the max amount in the inspector here. And also this will serialize this value to the scene file. So different scenes. So if we want to compose three different actors that all have health, they can have different health right through the scene file instead of having to procedurally set this maximum value in runtime. So this is very convenient. So next let's have an unready variable that will be the current amount. And I will call just current. And we are using the unready variable because when the object, when the health node get instantiated in the scene when we are running the game, it will get whatever is set through the inspector. So whatever is serialized in the scene as the maximum amount, and it will set this value to the current. So without that, this will just take whatever is set in the script and not whatever is exported. So not what is set in the inspector. So this way by using unready, we make sure that it will initialize its value taking whatever is set through the inspector. Okay, next up, let's make some signals. So if you are not familiar with Godot, signals are the way Godot implement the observer pattern. So we can set some signals and then we can subscribe some observers to this signal. You'll see later on in this video how you can achieve that. So the first signal that we'll make will be the max changed so that the health bar can be updated with the maximum amount of the health play of the player's health. And we'll pass a value that will be the new max amount. Next we'll have another signal that will be the, I think that I will just call it changed, and it will be the new amount, it will communicate the new amount. So this will be when this current amount, so when the current property changed. Now to notify these changes to notify when the maximum amount and the current amount changed, we will create two methods. So let's start with the max amount function, set max, I think that I will just call like this. And it will receive the new max value. And we'll do the following. We'll set the max amount to be the maximum between one and the new max. Why we are doing this is because we don't want the max amount to be smaller than one. This doesn't make any sense, right? Since we are using integers, the next, the value below one will be zero and it doesn't make sense to have a max amount of zero, right? Next, we will emit this signal, not find that the max, the max amount changed and we'll pass the max amount and we'll pass the max amount and not the new max because the new max can be can be below one. So since we are preventing that from happening, when we are setting the max amount here, using this max method, we will instead use the max amount directly because this value will always be greater than one or at least greater than zero, actually. Next let's make the set method for the current. So set current and we will receive a new value here, a new current, a new value. Yeah, I think that this makes more sense. So we are basically do the same thing, but with a twist. Instead of having a max like we did here, we'll clamp this value. So we'll set current to be clamped between what this value is and the minimum amount is zero and the maximum amount will be the max amount. So this value, this variable here, this property will never be below zero and will never be greater than the maximum health, right? After that, we will also emit a signal telling that the health changed and will pass this current value here. It will also be interesting if we can communicate that the health is depleted. So we can trigger a condition of death, for instance. So let's check for that if current is equal to zero. We can emit a signal telling that it is depleted and let's create this signal here. Now let's encapsulate this maximum value, this maximum amount and this current property into the respective methods. So to do that, we can use the set get keyword and this will encapsulate this variable to the set max method and let's do the same to the current. So set get, set current and this will make so that whatever object, so when a 30-party object, so when an outside object tries to set these variables, instead it will pass through these methods here. So they can try to access these variables, but when they set them, they will actually trigger these methods, right? And this is what we want. And finally, let's add the ready callback at the top here. And here we will call a initialize, initialize method and this method will be private. So I will put it right below, right at the bottom here. And inside this initialize method, basically we'll just emit both these signals to communicate right at the beginning what are the current values of this health object to other objects that are subscribed to these signals. So let's emit the signal telling that the maximum changed and passing what is the max amount. And let's also emit the signal changed telling what is the current value, what is the current health. And with that, we have our health object ready to be used by other nodes. So let's close this and let's start with the health bar. To create our health bar, I will start by using a progress bar. So progress bar is a control node and control nodes are nodes that are designed to be used as interface elements. And the progress bar specifically is a node that is specialized in displaying a range value. So a valid ranging from its minimum value to its maximum value in a bar format. So if we pick this, you can see that is basically just a bar perfect for what we want right. So I will turn on this grid snap, and I will configure this snapping. Actually 10 by 10 pixels is good enough. And I will zoom in a bit. And I will also turn on the helpers so that we when we are resizing everything, we can see what are the pixels of the pixel displaying the size of this control, right. And I think I will make this a 300 by 30 bar. Yeah, this will do the trick. And let's take grid of this percentage that is being displayed by going into the percentage category and turning off this visible property. So now let's also add a texture, a texture rect. And this texture rect is a UI element that is specialized into displaying textures, right. And for the texture of this texture rect, we use this heart texture here. And I will turn on the expand property. And we'll change this stretch mode to keep aspect centered. And this will make so that we can scale this object. But it will try to maintain the aspect, and it will try to keep the drawing of this texture to the center of the element to the center of the texture rect. And this is what we want. And I think that I will make this a 60 by 60, 60 by 60. So let's go to layout and we'll make the anchor of this element anchored to the center left of the bar, so that when we scale the bar, it will always try to maintain its position to the center to the left center of this bar, undo that, and I will move this to the left bit more central right here, so that it's centered to the anchor of this bar, right. So if we want to rotate it, it will rotate the heart right at the center there. Actually I will move it to the top a little bit. Yeah, I think that this is better. Now let's make this bar prettier because this plain gray is not pretty at all, right. So the first thing that I will do is change this value to 50. So we can see both the background rectangle and the foreground rectangle. And I will fold this percentage value and let's go to custom styles. This is what will be used to draw this rectangle that represents the health bar. So let's start with the background property with the background rectangle and let's create a new style box flat and let's edit it. You can see that I have the pure 36 color palette. This is the color palette that we use in GD Quest. And I wrote a post about some art guidelines that we are following in GD Quest. So if you want to check it out, I'll put a link in the description and there you can find some resources about where you can find this pure 36 color palette. And also the heart texture that I'm using is part of our graphical assets that we are using to follow these guidelines. So you can also find it there. I will put all the links in the description for the background color of this bar. I think that I will use this dark purple here. So I will go to the background color and I will use the color picker to pick this color here. And I will also use a border width of two pixels. For the border, I think that I will use a plain white. And I think that I will use a corner radius of eight so that the corners are rounded. I think that this is prettier than just a plain rectangle, a flat rectangle, right? And I think that with that we have our background rectangle. And for the foreground rectangle, the foreground bar, I will just copy and paste this rectangle, this style box flat that we did, that we are using for the background. But I will make it unique. And this is because Ingo.Engine resources are shared references. So if we don't make it unique, it will be just a reference to the same style box that we are using in the background property. So let me show you that. So I will clear and I will just paste it. And I will change the background color here. So something like this. And you can see that both are changing and we don't want that. So I will undo that. And I will make this unique. And now I can use the color picker to pick the same pink that we are using in the heart. And you can see that only the foreground bar changed. And this is precisely what we want. So I will take rid of the color palette, delete. Yes, let's reset the zoom and rename this to health bar. I will save it. Okay. And there we have it. This is basically what compose our health bar. And now it is ready to be used together with the health notes. So let's give it a try. So I will close the scene and let's create another one that will just be used to test this. It can represent an actor that will use both the health note and the health bar. So let's call this just health test or health bar test. And let's create an instance of the health, the health note. And another instance of the health bar. And I will send to the health bar to the viewport. So the viewport is everything inside this blue rectangle, these blue lines here. And for that, I will just change the layout to center, center, center. Yeah, this. So there we have it. This is just we can visualize this better when we are testing. To hook the health to the health bar, we use the signals. The way we subscribe an object to another object notifications is by going into the node tab. And there we have the all the signals, all the notifications that this node can emit. And you can go both to connect or you can double click this signals. So since we don't have any script in the health bar, we only have access to the building methods. And to connect a notification to building methods, we have to toggle this advanced mode here. And we'll have a more complex panel. But everything that we need is right here at the receiver method. And let's connect the health changed signal to the health bar set value method. This is the method that is used to set what is the current value that the progress bar is displaying. So we will connect it. And let's also connect the max changed to the health bar set max, oops, set max method connect. Now I will save the scene and yeah, health bar test. But before we actually test the scene, I will go to project, project settings. And here in the display category, we have the window settings. I will turn on this always on top property so that we don't lose focus off the window when we are testing, I will turn on this close. And let's test the scene. And you can see that it already set the current value. So the value that the bar is displaying to the maximum amount. So seems like it is working. But to actually test everything that we need, I will go to the remote scene. So right at the left here, you can see that we have the local scene and the remote scene. So the remote scene tree actually. And this is the scene tree that is actually being rendered. So the scene tree that is actually being processed here in our test. So if I go to health and go to the inspector tab, if we change these values, we will change the values that are running in our test. So if I change the current, for instance, so I made a small mistake because I forgot to set the current value in the set current methods. So first, we will actually do the following, we will set the current to be equal to the new value. And then we'll try to clamp it and we will actually do the same for the maximum amount. So maximum amount will be equal to the new max. And then we'll try to clamp it between one and the maximum value. So if we save that, go back to the scene and test, I will go to the remote scene tree to the health node. And if we try to set this to decrease it, you can see that now everything is working and the health bar is synchronized to the health node. And also let's play a bit with this value. So let's try to make this minus something, and you can see that it is clamping it to zero. And let's try to make this above 10. And you can see that it is also clamping to 10, because this is the maximum amount. So let's try to increase the maximum amount as well. And you can see that is currently is 10. And now the maximum amount is 28. And let's try to make this above 28. And yeah, everything is working. So yeah, now everything is working as expected. So that's the most basic way I could think about making a reusable decoupled health bar system. And you'll see in the next video where we play with hooking the health bar to in-game actors, why it is important to keep the health management and the health visualization decoupled from each other. But for this video, that's it. Don't forget to leave any questions you have in the comment section and subscribe to the channel if you didn't yet. So this way you can get updated when the next video came out. So that's it. Thank you so much for watching. Keep developing and until next time.