5 Tricks to Shorten Your Godot Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone um in this video i want to talk about some practices and tricks that i learned over the year that will help you shorten your godot code so um let's jump straight into it so very often we will be using signals let me um disconnect everything there's nothing here and there's nothing here okay so very often we'll be using signals and we very often will be using signals for very simple tasks for example when i click on this um our free the the sprite will be free right so what we usually do is okay i want to free the sprite so let me create a connection and we put in kill free here and this surely works it works but what if i tell you that this these two lines are completely unnecessary because let's think about what we do when we connect signal by code by code we always say the first node one dot connect and then we pass in the name of function we want to connect to and the function we really want to call is q3 instead of this button press because for just for this case um there's no this is this is very simple function this is a very simple thing we want to do like a built-in function already does it for us so there's no point in writing in creating this actual function anymore so in fact this function is completely unnecessary and the way to achieve the same result is to toggle the advanced button here and select sprite and receiver method let's just do q3 connect and you can see here that we are connecting to the sprite and the receiver method is q3 instead of on button pressed and it does exactly what we want it to do so this is only for simple simple signals like this you might wonder okay if i want to passing an argument it can still be done if you want to call some different function that requires a few arguments it can still be done as you can see here you can passing several types of variables but not not not every type of variable so just be careful here and if you have more logic in your signal then of course if that is the case you have to write say um button pressed write a function like that so that is the first trick i would say i'll call this a trick to get rid of a few lines of redundant code in your game now let's go to the second one use a utility singleton so um so this one you might be this one might not be very intuitive but you you might not know why why we have to use a singleton to do this but as your game becomes larger as your game becomes like more there are more systems there are more enemies there are lots of lots of things that require some common function then at that point you should really think about oh does it make sense to say um do this in the enemy class and in the player class can i just because can i just create a single term which which will return whatever i want then i don't need to like write the same code for two different classes and that is idea so here i prepared a utility node and this will be made a singleton and if you're new to godot you probably don't know what the single tank is but i will show you how to um how to create how to auto load the singleton and so there are lots of common functions that almost every game will use for example i want to create some random numbers i want to create some vectors i want random vectors i want to create some random integers and it doesn't make sense to say hey um i put this is my say this is for example this is level one of the game and here i say var r and g is equal to random number generated on you and in another thing i create another random generator and another thing i created another random generator and essentially all i want is to get some random numbers and in three different things i created three random number generators and created many other ways to generate random methods but in fact there should be only one random number generator and there should be just one method that generates all the random values that everything else needs right your your player might need some random numbers the enemy might need some random numbers the the environmental objects in your game might need some random numbers and you just need one central random number generator to do that and the idea is to put such common functions into a utility script and write your logic here here you also notice that we only we are only instancing one random number generator and not multiple and there are some very common um things i find in in my game deaf career so far like scheduling some jobs random number generation and checking dictionary stuff so these are just functions that i find very useful and they occur again and again for very various objects so um so i put them here by no means this might not be like necessary for your game or this might not even be the best way to write something but i just want to show that having a utility script really helps you because you don't need to write the same function many times for many objects you just need to write it once because in essence you just want to get a random number right so let me show you how to make this into a single term so if you just click on project here and then go to project settings and then autoload here it's asking for paths i'll just click on the scene here and i'll give it a name for example i'll just call you youtube utels edit and um a singleton is basically a script or or an object that is created before your game loads and it is only created once so um if you if your project is like a rpg main character's data might be stored in a singleton because first of all you because your main character may switch things but say the health is always the main character's health and the health should not be saved in the individual thing this the house should be saved in a controller in a central object that holds these values and dissolved and there should be only one such object that holds these values and here i created the singleton and let me show you how to call it if i just go back to main and now instead of let me just um now let me just show you something this is kind of dumb but um let me just connect the signal and every time i press the button i will print a random number right so earlier i if you remember i named my let me double check utils so all i need to do here is utils dot random number and suppose the lower bound for the run number is -1 the upper bound for this is one and that's it so you get the advantage of using this keyword util sorry this is not really an advantage but um we can just call utel anywhere from any other script because utl is a single term it is always loaded and it's loaded before everything else so let's see now when i click on click me um if you see here we get a random number every time and this kind of leads to the next idea to simplify your code which is we should use method overloading i'm not really sure if this is the correct terminology i don't know maybe or set default values things like that um so the idea is suppose i want to generate well this is not really an idea this is very practical this happens a lot suppose i want to generate random numbers random integers in this case does it make sense for okay and for for almost all the use cases i have i just need a random number between 0 and 100 right and but there are there are some other cases where um you might need um random integers in some different ranges say between minus 10 and 10. and you can see here this function random inked takes in two arguments lower and upper and lower and upper they both have a default value so that means even if i don't specify the arguments um when i call this function if i don't specify any arguments the default for lower will be zero and the default for output will be 100 and if i do specify one argument that argument will be considered to be lower and upper will still be 100 and if i specify two arguments then the first argument will be lower and the second argument will be upper so we actually don't need to say i i i don't need to write another function just to return for example just to return a random integer between 0 and 100 right because i know okay for 99 for 90 of the case i just need a random integer between 0 and 100 but for the rest of 10 i might need some upper and lower bounds i don't need to write another function to achieve that i can just simply specify um specify the default values here and i think it's called some some or some sort of overloading i am correct me if i'm wrong so let's see how this works so instead of a random num i'll just do random inked and i'm passing nothing so by default as i explained earlier this will generate this will just use the default values i set here 0 and 100 and we should only get random integers between 0 and 100 indeed and now if i um if i want to um if i if i'm being more specific i want some upper and lower bounds then it works too so this really saves us some this really saves us some effort right we don't really need to rewrite another function just to achieve that and very often at least in in my gamedev career very often i write some function do this and it does something but then i realized okay maybe it should receive depending on the state of the game depending on the state of the game it really should be it should do something else but for most of the time it should just it should it for most of the time you should just do one do do number one but for sometimes it will do number two and at that point you don't want to you don't really want to separate and write another function what you should do what you can do is you can just say okay i create another um variable here just call it uh for example i'll just call it state and by default state is going to be true and so what you can do is say if if state then do one else do blah blah blah and then in this way you don't really need to write another function you just need to modify the previous one okay let's go to number four use ink and use match what do i mean by that so again these are um these are tiny things but i do believe this will increase your the readability of your code and this will um just help you write shorter code in general so oftentimes we have we we will need to compare some strings right for example the dough okay so for example this string which i'm giving it the value good o and let me just do some comparison if s is equal to g o d o t or s is equal to say now i'm not going to capital then print hello very often we'll write code like this um which i which i'll show you how to simplify so if you think about this what we are doing is we are saying okay if s is either you could do with capital g or godot with um non-capital g lower lower g and now the inefficiency in this line is that we are actually repeating s twice when we actually only need s ones right we're just saying is s g this one or is this is s equal to that one either way is fine so instead of writing that we can say if s is inside the array of two elements and our code gets a little shorter our code gets a little shorter so this in fact so when you are doing a lot of or statements to connect your logical um to connect your booleans this will actually help you shorten um shorten the the condition after if by a lot if you are saying if s is equal to a or s is equal to b or s is equal to c so by doing this you can you don't need to write that many like double equals you don't need to write s again and again and they save some spacing and i think it just makes the code prettier and now in case you don't know if you have a dictionary suppose this is a dictionary this is a very boring dictionary but there are two methods to check if an element is a key of the dictionary um the first is s dot has one or this works and the other is if one is in s so this is like the pysonic way or both i mean python has both syntax i believe um but in case you you're not aware of this you can check if an element belongs to a dictionary using ink as well and another interesting thing is another thing that is unique to godot i think pyson might have this now but i'm not entirely sure is the match statement so let me go back to a string so very often we will run into something like if this is equal to gd do something and else if s is equal to air m this is equal to something lfs is equal to and sure most programming languages for most programming languages this is the case but we are writing coding the dough and godot provides us a very provides us a great alternative to write code to write chained if statements so here all you need to do is to say match s and in a case when s is equal to g d do something and when in the case when s is equal to error m do something in any other case you just put underscore here do something now this you might not think oh how is this going to save me how is this going to shorten my code this might not be entirely obvious at the first glance but depending on the nature of your game or the nature of the method very often here you just need to put in one or two lines of code and if it's just one line of code you can fit everything in one line just like this for example if i want to return if the s is equal to gd i just put return here i don't need to like create another line just for return right i it's pointless i'm creating another line for nothing and um for example if this if s is equal to something i'm going to set another variable equal to s that's all i'm going to do then i there's no point for me to create another line right and another advantage is if in your channel if in your chained if statement you have s is equal to s is equal to a or s is equal to b if you have something like this of course as i just told you you can write s is in a or b do something and then you have else if s is in blah blah blah do something you can certainly do that but again if you use match statement you can actually say okay if s is equal to gd or dg do something and this is the this is the way you do that you just put a comma after you just put a just put a comma to separate it and this will just this will mean that if s is equal to gd or dg do this right so as an example let me just print s here and print s here and i'll put dg and let's see what will happen dg gets printed and this this will simplify our code even further right this will simplify our code even further because we don't even need to write the ink statement anymore so this is particularly useful when you have a chained if statement with like three or more else ifs yeah and so this will certainly help you a lot and the next thing i want to say is the next trick not really a trick the next um i i would say this is like a practice i mean okay this is maybe it's a trick i don't know but this is the next thing is more situational so in every node in good there's actually a function called propagate call which not many people talk about but if you just type in prop you will see this function and if we control and left click into and you'll see this does some very interesting job so what it does is that suppose i call it um so right now i'm in the main node here so what will what it will do is it will go down to every single sub node of itself and call a function which is given here as a method and it will pass in the arcs array as its arguments and the functions would will just be called and whatever the function is supposed to do will happen now so this will become very useful when um let's just think about let's just imagine a case when i have suppose i have a no 2d where i put all the enemies in in this node and then let me duplicate this a few times and let me drag them this will be very um so and okay for every enemy here i will give them uh a function called move the move takes in a vector 2 so move to that point and um i'll attach a twin to it no so um no it doesn't have it so sure let me just no i mean that would be too complicated so for for every sprite here i would just move it to the look to the point so what i would do is just say self.position is equal to p plus you test a random vac yeah so um random vac is a random vector and by default it's going to x x value is going to be between minus 100 and 100 and y value is going to be between minus 100 and 100. so um yeah so all suppose for every suppose for every sprite here i want them to move to this point not move i want them to teleport to this point but with some randomness in it right traditionally we will well before i found out about this car well what i do is i would say for sprite in um anime dot get children i air dr yen oh what can i spell children sp dot move i would just say uh move to the center uh if i mean for example 600 400 right so this is certainly a viable way to do it but i have this for loop but i have this for loop um which will unnecessarily take two lines of code and this will take we have to indent it and format it which is kind of annoying but this will certainly do the job right everything so originally the sprites were at different locations and now they're all close to this point so this will do the job but what if i tell you again this can be simplified to one line of code so what i would do is say i would just say okay i still need to get the node enemy but now i'll just say propagate call what is the method i want to call move and what is the parameter and notice that it has to be passed as an array and i will just do this so an array of one element means that there's one argument and it is this value so this will do the same thing yeah again all the sprites moved to somewhere around this point and now we are just writing one line of code and you might say hey if this is if that is a case then why don't we always use propagate call why right so it really depends um in this case we know that we know that inside the node enemy there are only um there are only sprites and there are only like actual enemy sprites and there are no other structures there are no other like random nodes for other functions so we can do this and it doesn't give us any downgrading performance but if we just read if if we just take a second to read um the description of this function again you should take note that this will traverse the entire tree under this node under the node on which this func this method is called and that means suppose if i just start at main instead of start at enemy the same thing will happen every method every every sub node that has a method move so this will call every node that has a method move and call the function and do it but it will keep going it will like propagate right it will propagate to the entire tree so it will traverse the entire tree and if i just do this the same thing will happen no problem in this example there's no performance downgrade at all because the structure is so simple but internally it's going to check this button node as well if i start at this level right if i don't say enemy if i start at this level which is the main node it will go down to enemy and c enemy has no script no no function so it will it will ignore enemy and it will keep going it will go down to sprite and see that the sprite has a function called move which is what we want and call this function and similarly it will go down and check here the button and it sees okay button has no method called move so it will ignore it so if you have a very complicated structure then you have to be very specific about where you start to propagate so in this case this structure is simple enough but it will still be best practice if you start the propagation at enemy because i know all enemy are going to be sub node of this no enemy node and this way this will help us to better this will this will be this will not harm our performance but just note that if you do it from the beginning depending on what you have in your tree this might hurt your performance and yeah so that's it so these are the practices and tricks i've learned in my gamedev korea so far i hope you find these useful see you next time
Info
Channel: T Q
Views: 61
Rating: undefined out of 5
Keywords:
Id: _1vsdizvVTE
Channel Id: undefined
Length: 30min 14sec (1814 seconds)
Published: Mon Dec 13 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.