UE5 Understanding Pure Functions - Be a better game dev

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] welcome back to another episode of beia better Game Dev in this episode we're going to be talking about pure functions now don't turn off the video quite yet this might seem like an easy and obvious topic and for some it is but you would be surprised of how many problems and errors you may be getting because you are making use of pure functions without realizing the ramifications of their use so in this episode I'm going to be going to explain what a pure and impure function is how they work some examples of when you can go wrong and a little bit of guidance of how you can make sure that you don't have these issues moving forward so let's check it out welcome back so let's talk a little bit about pure functions and by proxy also impure functions so over here you can see I have this green box here this is a pure function uh it is a pure function because it's it's green it doesn't have execution pins and it has the checkbox pure uh checked here so this is what a pure function looks like with output this is what a pure function looks like with inputs and outputs and as contrast this is an impure function and a custom event so that's what they look like they all have the execution pins so the main difference between a normal function and a pure function is simply just clicking this box right so that that's how you change it to be a pure function and a pure function is sort of like a contract from the developer promising that nothing inside of this function is going to change any values it's only going to be reading values now this doesn't actually constrain you as a developer to uh not change values but it is highly recommended that you do not change values in a pure function and I'll demonstrate that down below here so over here we have a function a pure function which will be showing up some widgets when I uh press this button and we'll be printing them out now inside of this pure function the only thing I'm doing is I have this in variable it has the value minus two I'm adding one to it so it becomes minus one I save it and then I take it as an output now this is not a local variable this is a global variable inside of this blueprint so essentially What's Happening Here is I'm going to be printing out minus one because that's what it changes to right but no pure functions get called every time they are connected to a node which means that if I run this code now I press this key you can see I get two widgets that appear one that says minus one and one that says zero so what is happening here is when this uh impure function here gets called it wants to know what its index is so it goes back here finds a pure function runs the pure function to see what is the value so it changes it from min-2 to minus1 and then it sets that as the widget and then moves on then we get to this impure function which again also wants to know its index goes over here CES it's pure function calls the pure function and we get a a zero value here and this is the reason why you don't want to have code like this that change values inside of pure functions because in this case the only thing I'm doing here is actually observing but it becomes sort of the the slit experiment with light when observing it changes it right it's uh it's not something that you want to have as behavior that just hooking it up to a print string or something like that will affect the value and therefore might actually give you different results later on right so if we were to take this pure function and turn it into an inure function instead and hook it up and do the same code and change nothing else in regards to this you can see that we will be getting a result that says - one - one 0 0 consistently showing the same values in both of these only visual information pieces right and that's the most crucial part to understand about uh pure functions pure functions will be called every time they're hooked up to a node and an impure function will store its value from its output as sort of like a local variable so the last time it was run that is the value that it will have so you can use it way further down in the code and and trust that the value is what you expect it to be okay so now we have the basics covered and we know the differences between the pure and impure functions now um how can we run into issues with uh our Pure functions now that we know this well uh for example here I have put up a event where I have our minus two value here we're adding one to it and we're saving it as a variable and then we're printing it to the widget so in this case we're pressing one we're getting minus one if we run it again we get the the plus of one essentially each time that we run this right but in this case we are setting this to minus one and if we want to for example afterwards here add a check that says also uh this value we want to check if it's greater or equal to zero or in this case we're just checking if it's less than zero which is the same we might be expecting that uh we are since we had a saved a value minus one here that we should be getting a output that says that it's less than zero but what we what we actually get here is an integer greater or equal to zero and the reason for this is again that we have a pure function so in this case we actually set our value here to be minus one and then this comparison is being done against the minus 1 + one which turns it to zero and then Compares it so again we have a situation here where if we wanted to compare against a static local variable like a pure function we would be getting a proper value like for example if we were to check the integer value that we actually saved here and check that against we could see that the integer would be below zero because now it's actually change looking or comparing against that value for the integer so it is very easy to see now I hope that even though the the pure functions are uh easy and and and not difficult to wrap your head around it it can be quite easily used in such a way that it can create bugs and I will uh try to exemplify that with my next example so so in this case I have an array of classes I have a 10 different classes in this array all named after the index that I put them in so it's easy to see that they're matching up with the index so in index one we have a bpor 0 in index 7 7 we have a bpor 7 and so on right so what I'm doing here is pretty simple uh I'm taking my array of classes I'm doing a random on it I'm saving the array index I'm then showing what class there the random brings out and then I'm showing what kind of array index that this is using now this may seem like pretty harmless and straightforward thing uh but if you're not thinking about what is actually happening here you will pretty soon discover that you get some issues because checking here you can see that I get the bpor 2 and index 9 these do not match up I get N9 and one I get one and nine I get one and nine four and one they don't match up well there is a a chance since they are 10 classes it could theoretically match up 10% of the time but what is essentially Happening Here is we want to set our array index so we run the random node on that and we get an index out here then we get to the show name notification here and we say we want to print out the class now it's going to run the random again because this is also a pure function so this will randomize something which is 90 % of the time going to be a different one than this index so this is an example of what I think is fairly clear of how this can easily and and and sort of slip under the radar give you errors in your code so how do you actually solve something like this well I think I had an example somewhere yeah over here okay so what you can do here is one of two things is essentially either you get the index from the random and then you read the array of class let's take this over here classes with that index that means that you will always get the same result here from this Index right because it doesn't change this one may change but this one will all bo be matching with this one and after that we're actually um printing out the values over here right both from the get and from the index that we saved so if we press our key now you can see that we get 9 and N 9 and N 8 and 8 5 and five and so on right and you can also do the same but inverse which is essentially you get the actor class in this case and then you find which index it exists on and then you do the same thing that gives you the same result as well now it is important to note that you will only run the pure function every time a new node is actually hooked up to it in this case here I have an example that shows we have a structure of fields um just random things inside of it and what we're doing is we're printing out every time this function gets called so we know how often this pure function is being run and the only thing we're doing here is essentially saying we want to format a text with four different values from this you might think that okay it might run four times but no we are calling only one function here which means that when we actually press the key we can see that we get one widget that is displayed over here if we were to add for example a another print string over here that prints out the vector value again you'll see that we have two widgets created because pure function gets run twice so important to note uh it will need a new node to be hooked up to to cause it to run again which is usually where the problems arise in the last example here I'm going to show uh this will showcase where usually most of the issues arise from having impure functions which is in the cases of something that's iterating over something else so like for Loops uh and timelines and things of that nature uh in this case here I have when I press the one key I'm essentially saying I want to calculate a position where I want to move my character I will run a timeline it will give me an output from 0 to one which I will then lurp on to say I want to move to the move location from my actor's location and set my actor location to be whatever this lurp determines now if I run this code now you can see that I have my character running forward a bit pretty fast what you might not have noticed is that that did not work as it should because this lurp or this lurp this timeline is actually 2 seconds long and we didn't move for 2 seconds what actually happened was we moved much much faster than 2 seconds if I show this again can see the point to where we move to where we stop is less than 2 seconds what is happening here is that we are luring between the value that is our actual location but this one will keep be upd keep being updated as this timeline goes right let's say we move 10% along the way with our first tick here this means that when we want to lurp next we get a new value here that says another 10% let's say so let's say 0.2 so then it will say okay you're supposed to move from 10% along the way to this destination so essentially just thinking that the the destination is now 90% % instead of the 100% which is technically true from the aspect of like our total speed or total distance traveled but it's not our origin position that we're supposed to be luring from um and as such this speeds up and gets us to destination quite quickly what we want to do in these cases are instead make sure that we have our values that we work against be set before before we start um something that is either being called by pure functions sorry impure functions or we are storing the values before we start processing them so that they don't possibly change during the iteration in this case I save my start location now here instead of getting it from my control pwn and I say that I want to lurp from the start location to the move location which means that this will not change during the iteration so if I now run this you can see that I will get a consistent and slow pace for 2 seconds that transports me forward along the timeline so yeah hopefully all this made sense uh pure functions can actually cause a lot of problems in your your projects and it this is not something that says um avoid them but rather be wary of how they work and you can probably avoid having some problems that doesn't make sense to you because you think the code looks fine right so yeah that's going to be all for now keep on learning take care a big thank you to all of you who like comment subscribe and share my videos or through other means support this channel you are what makes this channel grow and become a resource for other people to learn from
Info
Channel: LeafBranchGames
Views: 4,044
Rating: undefined out of 5
Keywords: learning hub, unreal engine, tutorial, unreal engine 5, blueprints, game design, game dev, unreal engine 5 tutorial, unreal engine 5 beginner tutorial, ue5 beginner tutorial, building user interfaces for unreal, engine ui design, user interface, design ui, design tutorial, building user interfaces, unreal engine user interface, Leafbranchgames, Good habits, Best practice, How to build menus and UI for Unreal engine 5, the right way, UE4, UE5, Reuse, Recycle, be a better game dev
Id: H-dA7tGQnBc
Channel Id: undefined
Length: 14min 48sec (888 seconds)
Published: Tue Jan 09 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.