Adding Collectable Coins! - (2021) How To Make A PLATFORMER GAME (Love2D) 4/6

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in the last episode i asked you to try to rework the friction code using math.min and math.max if you managed well done if not don't worry we will go over it now the main difference between the friction and acceleration code is the target when we accelerate the player our target is the maximum allowed speed while the target for our friction code is 0 since we want the player to stop when the x velocity is greater than zero we want to compare the velocity after we have subtracted friction to the target zero then we want to pick whichever of those numbers that is greater to do this we will set the x velocity to be equal to math.max then we will pass in the x velocity minus the friction multiplied by dt as the first argument and 0 as the second the same thing applies when the x velocity is smaller than 0 except that we want the smaller number and use math.min so we will set the x velocity to be equal to math.min and pass in the x velocity plus the friction multiplied by dt as the first argument and 0 as the second if we run the game you can see that the friction still works just like before currently we have the platforming part but not much of the game part let's add an objective for our player in most platformer games there is some kind of a collectible item that rewards the player for taking a more dangerous path or just reaching further in the level we will add a coin so far we have created a player which is kind of a single tone in that there is only one instance of it with the coin we want there to be multiple instances of coins there are multiple ways to approach this i will show you how to do it using meta tables to emulate a class because technically lua does not have classes and isn't an object oriented language like java for example to explain meta tables i have quickly made a new empty project let's start by creating a table named person inside of the table i will create a new variable name and set it to be equal to bob then i will create a function named display name inside of this function we will simply print the name of the person if we wanted to have multiple people with different names we could create multiple tables each with the same functions it's pretty easy to see that this would quickly turn into a nightmare especially if the table has a lot of functions instead we can use meta tables to inherit the functions and properties of our person table to each new instance that we want to create to do this we need to first create a table that will serve as the meta table i will name it metaperson and set it to be equal to curly brackets just like with a normal table the difference is that we will add an index inside of the table that will point to the table that we want to inherit from to set the index we simply type two underscore characters followed by index and set that to be equal to the person table we can now create a new function which handles creating new people i will name it person.new and add the name as an argument to it each new person needs their own table that will store the specific instance and its properties to do this we create a local table which i will name instance but instead of setting it to be equal to curly brackets we use the lua function set meta table sorry to interrupt previous me said he would make a local table but didn't don't be like him add the local keyword like this okay let's continue it takes two arguments first the child table that will inherit the functionality and then the meta table that has the information of where the functionality should be inherited from in this case we just want a new empty table for the child and then pass in the metaperson table as the meta table now we can move on as normal and initiate variables that we want to use i will create a name variable and set it to be equal to the past value name when we are done we need to return the instance table now we can create a couple of test people we can do that by setting a variable to be equal to the person.new function i will create three different people and pass in different names to them then we can call the display name function on them let's go ahead and run the program and as you can see each of the instances of people have printed out their own name when we call display name on a person it will first look for that function inside of that table then it will realize that it does not exist and checks if the table has a meta table if it does have a meta table it will check if that meta table has an index and then look inside the table or function that the index points to in this case it goes into the meta person gets the person table from the index and looks inside of the person table and finds the display name function there is a way to do this which in my opinion is slightly cleaner we can have the person table be its own meta table with an index pointing towards itself we do that by removing the meta person and instead setting the index variable of the person to point to itself now we can set the meta table of the instance directly to the person table both of these methods accomplish the same thing i just think it's easier to grasp the concept first when the meta table is its own separate table let's use our newfound knowledge with meta tables and create a new file named coin inside of this file we will create a new table named coin and then set the index of the coin to point to itself now we can create the function that will handle creating new coins i will name it new and give it two arguments x and y which will set the position of the coin inside of the function we will create the instance table sorry to interrupt again but previous meme managed to forget to make the table local again do what i say and not what i do and all that alright previews me take it away by setting it to be equal to set meta table and passing in an empty table and the coin table next we will set the x and y positions to be equal to the past in x and y arguments we want the coins to have an image so i will create a new variable and name it img and set it to be equal to love.graphics.new image inside of the parentheses we will pass in the path and file name of the asset next we can go ahead and store the dimensions of the coin into two new variables width and height which we will get by calling get width and get height on the coin image finally we need to remember to return the instance to test that our code is working so far we should draw a couple of coins to do that we need to first create a draw function inside of this function we will call love.graphics.draw we will pass in the image followed by the coordinates i also want to change the origin point to the center since we are going to create a physics body for the coin later to do that we need to first set the rotation to 0 and the x scale and y scale to 1. now we can reach the origin offset and pass in half of the width and half of the height now we can go into the main.lua file and require the coin file to test the coin we will create some temporary instances inside of the load function i will just name them coin 1 2 and 3 and set them to be equal to coin.new with some random x and y values finally we need to call draw on the coins remember to do it on each of the coins that we have created don't worry we're going to do this in a much cleaner way soon all we want to accomplish right now is to see that we are on the right track if you run the game you should be able to see that we have some coins spread around the level let's clean this up so that we don't need to keep filling our main file with some random variables instead of storing each of the coins in a separate variable we can insert them into a table for this i will create a new table named activecoins inside of the new function we are going to replace the line that returns the instance with table.insert this is a function that allows you to insert elements into a table the first argument is the table that you want to insert into and the second argument is what you want to insert in this case we want to insert the instance into the active coins table now we can create a new function named coin.drawall this function will make sure that each coin that is inside of the active coins table gets their draw function called to do this we need to loop through the active coins table previously we used a simple for loop we are going to use a slightly different type of loop which looks like this for i v in pairs do the key difference is that we don't need to manually set the amount of times the loop should run it will loop until it finds the first occurrence of nil in order for it to know which table it needs to iterate through we need to pass in the active coins table another very useful part is that we get access to each of the elements as it loops through it saves it to the variable currently named v we can name it whatever we want and to make it slightly more intuitive i will rename it instance now we just need to call the draw function on the instance to summarize we loop through each coin inside of the active coins table and tell each coin to draw themselves using their own draw function we also need to update the coins so let's create an update function we will leave it empty for now and create an update all function where we loop through all of the coins and call the update function on them now we can clean up the main.lua file by removing all of the old coin code and replacing it with calls to the update all and draw all functions we can also remove the variables that used to store the coins all we need to do is call the new function and it handles storing the coins in the active coins table which in turn is managed by the drawall and updateall functions that make sure that each coin is drawn and updated individually we have an update function but we don't update the coins at all let's make them feel a bit more alive by making them spin around we could do this with an animation but there is also a trick that you can use in order to make sprites appear to be spinning around by altering their scale let's create a new function and name it spin remember to call it in the update function here we will use one of my favorite features with the math library math.sin if we print math.cin and pass in the game time which we can get by using love.timer.gettime then you can see that it returns a number which goes between -1 and 1. it does this in a sine wave meaning that it accelerates and slows down as it reaches the endpoints you might remember that setting the x scale to negative flipped the image we are going to use this to give the illusion that the coin is spinning let's create a new variable named scale x and set it to be equal to 1. in the spin function we can set the scalex variable to be equal to the math.sin function now we just need to replace the hard-coded scale value of the coin with the scale variable when we run the game you can see that our coins appear to be spinning around personally i dislike that they are synced to fix this i will create a new variable named random time offset and set it to be equal to math.random this function will return a random number between two numbers in other words if we pass in 0 and 100 it will give us a number between 0 and 100. to make it affect the spinning we will add this variable to the love.timer.gettimecall i also want to speed up the spinning so i will multiply the time that we get by 2. if we start the game now you can see that the coins are all spinning faster and out of sync the next step is to make the player able to pick up coins to do this we need to add a physics body to the coins we will do this in the same way that we did for the player first i will create a table named physics then we need to create the body and pass in the world and the coordinates the key difference with the coin is that we don't want them to move so i will set the type to be static we could create a circle shape for the coin but since we can get the dimensions out of the art asset i will use another rectangle it's close enough and the small difference is in the player's favor finally we create the fixture and pass in the body and shape if we run the game now you can see that the coins have a physical body and that the collisions look good however while we don't want the coins to block the player from moving we still want them to have a collision that triggers the begin contact callback the key to having both the cake and eating it is to use the set sensor function on the coin fixture and passing in true a sensor is exactly that a physical object that can trigger the begin contact and end contact world callbacks while it never causes an actual collision one final problem remains the player's begin contact code is going to set the player to be grounded as you can see that is causing some unwanted behavior we can fix this and make the coin disappear at the same time we do this by creating a begin contact function for the coin remember to add the three arguments a b and collision here we will loop through each coin in the active coins and check if either a or b is a coin if that is the case then we need to check if a or b is the player if it passes through both of these if statements then we know that a coin and a player have collided if the player has collided with a coin it means that the player has not collided with the ground i know quite shocking right if we know the player collided with a coin then we can go ahead and skip checking everything else to accomplish this we will return the value true instead of just calling coin.begin contact in the begin contact function in main.lua we can create an if statement that checks if the coin's begin contact returns true and if it does then we call return which stops the function from continuing down to the player begin contact there is a very important thing to keep in mind you are not allowed to remove or make any changes to the physics world inside of one of the collision callbacks this is due to the fact that box2d locks the world to get around this we will mark the object and then remove it outside of the callback i will create a new variable and name it to be removed and set it to be equal to false in the begin contact function we can now set that variable to be true now we need a function that checks if the object is to be removed i will name it check remove and call it in the update function all we need to do is to create an if statement that checks if the coin is to be removed next we need to create a function that actually removes a specific coin i will name it remove inside of this function we will loop through all of the coins and check if the current instance is equal to self meaning the coin that called this function if that is the case then we can remove it from the active coins table we do this using the table.remove function it takes two arguments first the table and secondly the index that we want to remove since we are inside of a loop we have access to the local variable i that is equal to the current index remember to call the remove function inside of the check remove function the physical body of the coins is stored inside of the world and does not get deleted even though we remove the coin to get rid of it we need to also call destroy on the coin's physics body if we run the game you can see that the coins are disappearing all that remains is having the player actually receive the coins that we pick up instead of incrementing a player variable inside of the coin file we should call a function that handles it but first we should create a variable that stores the amount of coins that the player has inside of the player's load function i will create this variable and name it coins the player should not have any coins at this torch so i will set it to be equal to 0. now we can create a new function named increment coins inside of it i will set the amount of coins to be increased by one let's return to the coin.lua file and go ahead and call the increment coins function inside of the remove function to verify that it works we can print the player's coins variable if we run the game you can see that when we pick up coins the correct amount of coins that the player has gets printed in the console we want to give this information to the player in a better way than through the developer console let's create a gui for the player we should do this in a separate file which i will name gui first we will create a table named gui and then the three base love2d functions load update and draw then we need to head over to the main.lua file and require the gui file after that we need to call each of the three functions that we just made in their respective love functions when it comes to drawing the gui we want to make sure that it's drawn outside of the transformations this is due to the fact that we are going to implement a camera later and we want the gui to be static next we will create a new table inside of the gui that i will name coins the first variable that we need is the asset that we want to draw i will name it img and set it to be equal to the same image that we used for the coins from this image we can get the width and height and store them into variables using the get width and get height functions next we want to store the scale of the image i want it to be slightly larger than the in-game coins the reason for this is to make it obvious that it's part of the gui and not collectible i will create a new variable name scale and set it to be equal to 3 meaning 300 scale finally let's create two variables that will store the x and y coordinates i want it to be in the top left corner so i will set the x to be equal to 50 and the y to also be equal to 50. let's go ahead and draw it i will do it in a separate function which i will name display coins remember to call this function in the draw function let's start by drawing the image itself by calling love.graphics.draw we will pass in the image followed by the x and y coordinates next we'll pass in 0 because we don't want to rotate the coin then we will pass in the scale variable twice for the x and y scaling of the image if we run the game you can see that we are drawing a big but currently useless coin in the top left corner of the window in order to make it less useless we need to display the amount of coins that the player has to do this we will use the function love.graphics.print the main difference between print and love.graphics.print is that print will use the console to display what we passed it while love.graphics.print will draw it on the game window the first argument is this string that we want to print i will concatenate a colon which has a space on each side with the player's coin variable next we need to pass in the x and y positions we will use the coins x and y variables we run the game you can see two problems first the text appears in the top left corner of the asset and second the text is incredibly small to make the text centered and on the right side of the coin we need to add the width of the coin multiplied by its scale to the x position to the y position we will add half of the height multiplied by the scale this line of code is getting very long we should break out the x and y calculations into local variables and then use those variables inside of the function this increases the readability a lot if we run the game you can see that the text is printing at a much better position though since its origin point is in the top left corner it's a bit far down let's fix that and also increase the size of the text the default font doesn't really fit our game either so we will fix that as well i will create a new variable that will store the font that we want to use i will name it font and set it to be equal to love.graphics.newfont we only need to care about the first two arguments first we will pass in the file path to the font that we want to use next we will pass in a number that will set the size of the text i think 36 should do the trick to apply the font to our text we need to call love.graphics.setfont and pass in the font that we just created if we run the game you can see that it is a lot bigger and has a more suitable font however it's still offset to fix that we can use the font that we just created to get the height of the text by calling get height on the font variable to raise it by half we just need to subtract the height of the font divided by 2. if we rerun the game you can see that the text is now placed exactly where we wanted it to make the text pop a bit and be easier to read we will add a small shadow to it this is really easy all we need to do is duplicate the line that draws the text we will set the color to black for the first one with half opacity the second will be white and have full opacity finally we need to offset the shadow by a couple of pixels on both the x and y axis if we run the game now you can see that the text has a nice shadow meanwhile the coin looks very flat let's do the exact same thing for the coin duplicate the draw offset the first one and set it to be black with half opacity the second will be white with full opacity this function is a little bit big now and kind of does two different things let's break out the text printing code into a new function named display cointext remember to call this in the draw function that is it for this episode thank you so much for watching if you found this video helpful please leave a like and subscribe so you don't miss the next episode i read all comments so if you have any questions don't hesitate to ask [Music] you
Info
Channel: DevJeeper
Views: 2,019
Rating: undefined out of 5
Keywords: programming, coding, lua, love2d, game development, how to make games, scratch, godot, unity, platformer, platformer tutorial, platformer games, gamedev, game dev, tiled, how to use love2d, game with lua, make game with lua, oop, object oriented programming, lua oop, lua object, metatable, lua index, inheritance, coin, collectable, pickup, currency
Id: fKuWvf7nwtA
Channel Id: undefined
Length: 24min 5sec (1445 seconds)
Published: Sat Nov 14 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.