Creating The Player Character - (2021) How To Make A PLATFORMER GAME (Love2D) 2/6

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
now that we have a map with collision it's time to add the player we will start by creating a new lua file named player inside this file we will create a table for the player as well as the three base functions load update and draw we will use a colon here to make us able to use the keyword self to refer to the player this will be very important later on when we start working on objects that will have multiple instances we need to require the player file so that our game knows it exists then we need to call the three player functions inside their respective love function make sure that you call the draw function after the scale is applied but before the pop we can now return to the player file and continue working on the player itself first of all i will create two variables that will be used to keep track of the player position i will name them self.x and set it to be equal to 100 and self.y that will be 0. next i will create two variables for the dimensions one named with which i will set to be 20 and one named height which i will set to be 60. inside of the player's load function i'm going to create a new table that will store all of the player's physical collision information the first variable we will add into the physics table is the body it will keep track of things such as position velocity and rotation in other words where it is and where it's going i will store the body in a variable which i will name self.physics.body and set it to be equal to love.physics.newbody this is a function that takes four arguments the first one being the world to create the body in so we will simply pass the global variable world that we created in the last episode next it wants the x and y coordinates that we want to create the body at i will use the self.x and self.y variables finally we need to pass in a string that will tell it what kind of physical object it will be there are three types of physical objects static which means that the object has an infinite mass and can never move dynamic which is the one that we want to use for the player it's able to move around and is affected by collisions the final one is kinematic and they only collide with dynamic bodies but don't react to forces in other words kinematic bodies can make contact but aren't otherwise affected essentially like a train hitting a person by default dynamic bodies can rotate we don't want this behavior for our player so i will call set fixed rotation on the body and pass in the boolean value true this locks the rotation of the body next we need to define the shape of the physical body a rectangle will fit the player sprite the best we will store the shape in a variable named shape and call love.physics.new rectangle shape on it this function takes two arguments the width and height of the rectangle we will use our width and height variables that we declared earlier now we have a shape and a body but they aren't connected yet in order to connect them we need to create a fixture which will bind them i will declare a new variable named fixture which i will set to be equal to love.physics.newfixture this function takes three arguments first the body and the shape that we want to connect in our case self.physics.body and shape then the density for the fixture we don't need it since we just want to use the collision part of box2d so we can omit it in order to make our player move we need to declare some new variables first we need to store the player's current velocity in two variables x val for the x-axis and y-valve for the y-axis these velocity variables will be applied to the body later enabling it to move by default the player should not be moving so we will set both of them to be equal to 0. next we need to declare a maximum speed variable i will name it max speed and set it to be equal to 200. this will determine how many pixels per second the player is able to move we do not want the player to go from zero to maximum speed instantly this would feel very cheap and unsatisfying instead we are going to declare two additional variables acceleration and friction this will be used to increase or decrease the velocity of the player i will set the acceleration to be equal to 4000 and the friction to be equal to 3500 since the maximum speed is 200 it will take 0.05 seconds for the player to reach maximum speed and since the friction is 3500 it will take approximately 0.06 seconds to stop tweaking numbers in a platformer game is very important these are just a suggested starting point however you should experiment and try to find values that you think feel good this is a good time to draw the player it will help us understand if our code is working when we start to implement the movement inside of the player draw function we are going to use a love function which draws a rectangle it's named love.graphics.rectangle and it takes 5 arguments first it wants a string that is either fill or line which will determine if the rectangle is going to be completely solid or just an outline i will go with fill the next two arguments are the coordinates for the rectangle so i will pass in self.x and self.y finally we need to pass in the dimensions self.width and selfset height which will determine the size of the rectangle if we run the game now you can see a white rectangle which is stuck in the air there are a couple of more things that we need to fix before the player is able to move first we need to synchronize the physical body with the player's x and y position i will do this in a new function which i will name sync physics remember to call it in the update function inside of this function i will set self.x to be equal to self.physics.bodygetx this function will return the x position of the physical body i will do the exact same thing for the y position except that i will use get y as a side note you're able to get both of these at the same time by calling the get position function instead which returns two values in lua you are able to set multiple variables to be equal to the returned values from one function by separating them with a comma sign we can go ahead and remove these since we don't need them anymore next we need to make the body use our velocity variables we do this by calling set linear velocity on the player's body this function takes two arguments first the x velocity then the y velocity for testing purposes we can set the y velocity variable to a positive number to see if the player actually moves if we start the game you can see that the player indeed does move down however there is an interesting problem that occurs the player is going halfway down into the tiles this occurs because box2d has a different origin point than love in general love.graphics.rectang draws the rectangle from the top left corner this is known as the origin point meanwhile the origin point is the center for box 2d in other words the player will be drawn offset by half of its width to the right and half of its height downwards all we need to do in order to solve this is to offset the x and y positions that we draw the rectangle at by half of the width and height respectively if we rerun the game you can see that the player is now properly colliding with the world time to make the player able to move to the left and right i will first create a new function and name it move remember to add dt into the parentheses and call it in the update function inside of this function we need to check for input to do this we will create an if statement and call love.keyboard.isdown this function takes the input that you want to check as an argument and returns true if that key is currently pressed down the function can take multiple arguments in case you want to check for multiple keys in our case i want the player to be able to move with both the a and d keys as well as the arrow keys let's start by making the player able to move to the left i will pass in d as a string as well as right which is the constant for the right arrow key you can find all the key constants on the love to the wiki i will leave a link in the description inside of this if statement we are going to create another if statement this will check if the current x velocity is lower than the max speed variable if this is the case we will make it increase the x velocity with the acceleration multiplied by delta time this would kind of work but it won't be a hundred percent precise because the player will almost always end up on a slightly higher speed than allowed this is because we check if the current speed is lower than the allowed speed and then add the acceleration which can be larger than the difference between the current and the maximum speed to fix this we need to create another if statement that will check if the current velocity plus the acceleration times dt will be smaller than the maximum allowed speed if that is the case then we can go ahead and increase the speed to make sure that the player is able to reach the top speed we need to create an else statement that will handle when the player is below the maximum speed but adding the acceleration would make it go above it in this case we simply set the x velocity to be equal to the max speed variable next we need to make the player able to move towards the left i will create an elsif statement and call love.keyboard.isdown i will insert a and left as the keys that will make the player move towards the left when the player has a positive velocity it will move to the right a negative velocity will move it to the left this means that we can simply copy the code that we wrote for moving towards the right but flip it we need to check that the current x velocity is greater than the negative maximum speed then we check that the x velocity minus acceleration times dt is greater than the negative maximum speed if that is the case we subtract the acceleration times dt from the x velocity finally we make an else statement that sets the x velocity to be equal to negative max speed now we are able to move towards the left and the right though there is an issue the player character thinks that it's forest gump and will just continue running this is because we haven't implemented friction yet so let's go ahead and do that first i will create a new function and name it apply friction the friction code will resemble the movement code the key difference is that the goal of friction is to bring the player to a standstill so instead of checking against the maximum speed we are going to check the x velocity against zero we are going to make an if statement that checks if the x velocity is greater than zero if that is the case we will check if the x velocity would still be greater than 0 if we subtract the friction multiplied by dt from it if that is the case then we will go ahead and do so otherwise we will set it to be equal to 0. now we just need to do the same thing for when the player has a negative x velocity i will make an else if statement and check if the x velocity is lower than 0. if that is the case we will check if the x velocity would be lower than 0 even after adding friction multiplied by dt and do so if that is the case else we will set the x velocity to be equal to zero finally we need to make sure that we call the apply friction function i will create an else statement inside of the move function and call it there that way the player will only start to slow down when it's no longer moving if we start the game you can see that the player slows down and comes to a full stop when i don't hold down any of the movement keys falling at a constant speed forever sounds more like my stock portfolio than a good game mechanic let's go ahead and implement gravity first of all i will create a new variable named gravity and set it to be equal to 1500 next we need to make a new function named apply gravity inside of this function we will increment the player's y velocity by the gravity variable times dt remember to call this function in the update function and set the player's y velocity back to zero now the player starts at zero velocity and falls faster over time there is a problem though after a short while you won't be able to move because the y velocity has grown so large that it's holding the player in place to fix this we need to implement a system that will keep track of whether or not the player is on the ground and only increase the y velocity if the player is not on the ground later when we implement jumping we will also use this to check if the player should be able to jump or not to keep track of whether or not the player is on the ground we will use the books to the world callbacks begin contact and end contact callbacks are functions that are called during certain conditions for example love.load it's called when the game is started the begin contact callback is called when two fixtures collide and the end contact is called when two fixtures that were colliding no longer do in main.lua we need to set the callbacks on our world by calling setcallbacks this function takes up to four arguments but we only need the first two we can name them whatever we want but it's best to just name them begin contact and end contact now we need to create these two functions they both have three arguments the first two are the colliding fixtures we will name them a and b the third is the contact object that is created upon collision which contains information about the collision itself we will name it collision now we can copy this function and rename it end contact let's go back to the player.lua file and create two functions these will also be named begin contact and end contact and will handle the collisions that the player is involved in make sure to include the three arguments a b and collision in order for these functions to be called we need to make sure that they are called inside of the world callback functions we made in the main.lua to make the player able to land we need to make sure that the object it collided with is below it we do not want the player to be able to walk on the ceiling to be able to check this we need to get to the collision normals inside of the player begin contact function we are going to call get normal on the collision this will return two values the normal for the x and y axes since it returns two values we can store them in two local variables separated by a comma sign i will name them nx and ny so what will the value stored in these variables be and how can we use them it returns the coordinates of a unit vector that points from the first object to the second one if b is below a then the y normal vector will be a positive number and vice versa that's great because we are interested in knowing if the object that the player collided with is below when two objects collide begin contact will trigger only once this means that the player might be a or b which object becomes a is determined by the age of it the oldest object or in other terms the object that was created first will always be a this means that we need to check both a and b to determine if the player was part of the collision let's start by creating an if statement that checks if the player's fixture is equal to a if the player fixture is a then the normal vector will tell us the direction towards b with this in mind we can check if n y is greater than 0 meaning b is below the player if that is the case then the player has landed we should go ahead and create a function named land and call it inside of the begin contact function let's think about what we need to do when the player lands first of all we want to set the y velocity to 0 so that the player is no longer falling then we want to store the fact that the player is now on the ground i will do this by creating a boolean variable for the player i will name it grounded and set it to be equal to false by default now we can set the grounded variable to be equal to true inside of the land function we should also create an if statement at the top of the begin contact function which checks if the player is already grounded then we can skip the rest of the code by typing return end next we can use the grounded variable to make sure that gravity is only applied when the player is not grounded with boolean variables we can type out the comparison in a couple of different ways for example by typing if self.grounded equals equals false an if statement will trigger if the condition is true since a boolean always has the value of true or false you don't need to compare it to something in order to get a boolean value instead we can type if self.grounded then this would be the exact same thing as if self.grounded equals equals true we want to check if it's false though in order to flip it we need to use the not keyword now we need to go back and handle the case when the player is the second fixture in the collision to do this we create an elsif statement that checks if b is equal to the player fixture if this is the case then the normal will be pointing from the other object to the player this means that we need to do the opposite to the first case if ny is smaller than 0 then we call land if we run the game you can see that we are finally able to move around again and what's even more cool is the fact that we have now made most of the groundwork for implementing jumping let's go ahead and get that working now one of the differences between the action of jumping and moving is that for the movement we need to constantly check if a key is pressed down for jumping we only need to know when a specific key was pressed to do this we will use the callback function love.keypressed which will trigger once every time a key is pressed i will declare it inside of the main.lua file we only need the first argument key which is the key that was pressed next we will create a new function inside of player.lua and name it jump remember to add the same key argument and call it in the love.keypressed function now we need to decide what button to use for jumping i will use the w and arrow up keys i will create an if statement that checks if the key that was pressed is equal to w or if the key is equal to up now we can define what happens when the player presses the jump button first of all we need to set the player's y velocity to something negative i will create a new variable name jump amount and set it to be equal to -500 in the jump function i will set the y velocity to be equal to the jump amount if we start the game and try to jump you will see that while we indeed are able to jump it's a bit excessive we don't want our player to go to the moon the reason this happens is because our game still believes the player is grounded meaning gravity never kicks in all we need to do in order to fix this is to set grounded to be equal to false in the jump function now the player is no longer able to fly well unless i press the jump button again to fix this we need to make sure that the player is only able to jump if it's grounded we can do this by adding and self.grounded to the if statement whenever you mix the or and the and the keywords you need to be very careful to not cause logic errors currently our game believes that the player is always able to jump if you press the w key but if you press the up arrow key it checks that the player is also grounded before it jumps to fix this we need to put the code that checks the keys into parentheses now the player is only able to jump when grounded regardless of which of the keys was pressed the next thing that we need to sort out is the fact that if you walk off an edge the player never falls down this is because currently the only time we set the player to not be grounded is when we jump this is where the other collision callback comes to use we can use end contact to set the player to no longer be grounded when it loses contact with the ground however we first need to store the collision when we land to do this we need to pass collision to the land function remember to also add collision as an argument next we just need to store the collision in a variable i will name it current ground collision inside of the end contact function we will check if the a or b fixture belongs to the player we don't need to know which one the player is since we can instead check if the current ground collision variable is equal to the collision if that is the case then the player has lost contact with the ground and we can set grounded to be equal to false i think it would be cool if the player had a double jump and i want you to implement that yourself depending on your experience it might seem very scary but trying to figure out how to do things on your own is probably the most important part of becoming great at anything in the next episode i'm going to go over how to do it so don't worry if you struggle a bit a good tip is to try to describe the mechanic that you are trying to implement what is a double jump when can and can't a player use a double jump try to define it in normal non-programming terms then start thinking about how to turn these rules that you have made into actual code thank you for watching if this video was helpful leave a like and subscribe so you don't miss the next episode i read all comments if you have any questions don't hesitate to ask [Music] you
Info
Channel: DevJeeper
Views: 5,752
Rating: undefined out of 5
Keywords: programming, coding, lua, love2d, game development, Platformer games, platformer, platformer tutorial, unity, godot, how to make a platformer, tutorial platformer game, tutorial platformer, scratch, game dev, programming tutorial, Tiled, how to make games, how to use love2d, programming in lua, making the player
Id: AWGd6T3B2OA
Channel Id: undefined
Length: 22min 20sec (1340 seconds)
Published: Sat Oct 31 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.