Transcript for:
Creating Flappy Bird Game

right look what we're doing this week no hello let's make flappy bird flappy bird is a game where you control a bird that flaps and people paid thousands of dollars to buy phones with this pre-installed when they could no longer buy it on the App Store these people were suckers there is nothing to this game you press a key the bird flaps and you have to avoid an obstacle it's difficult it's designed to be difficult and the idea is to get the highest score you possibly can and invariably the highest score is a pathetically measly number of digits as you can probably tell already I'm not good at this game I don't like this game but I feel it's got some necessary points which may be useful for other game developers and as usual you'll need nothing other than a Windows command prompt in order to implement this rubbish but it's got some interesting points which I think are worthwhile learning in particular how do we create a level that never ends we've got to keep presenting obstacles to the player and some rudimentary physics the bird does actually obey the laws of physics and he's exploiting these physics and exploiting some quirks of human nature that makes the game very challenging as usual I'm going to use the one line code a console game engine and I've derived the class from it called flappy bird and we're going to override the on user create and on user update functions when I create an instance of the console curiously it's going to be lower resolution than normal so I've chosen for it to be 80 characters wide by 48 characters high and each character is 16 by 16 pixels this is a nod to one of my favorite youtubers who's just got a display that works at this resolution and I'm hoping that he'll implement this rubbish on his display now there isn't very much code for flappy bird so I think it's useful to understand what the code should do before we start coding it we'll start with the flappy physics this is a bird and our birds position is represented by an X and a y-coordinate if we differentiate with respect to time the position of the bird we get DX and dy which is also velocity and if we take the second derivative of the position ie D squared X and d squared Y we have the acceleration and I've covered position velocity and acceleration at great length in the much more interesting code at yourself asteroids video so I suggest you go and have a look at that if you're not familiar with these terms we can simplify this further because our bird isn't actually going to move along the X direction it's only going to fall down due to gravity or get pushed up when the user presses the key because the bird flaps its wings so we can do away with the X components and use single floating point scalar values to represent the Y components so starting with acceleration we can integrate back up the chain to work out the position of the bird and one acceleration force that's always being applied to the bird is gravity which pulls the bird down and when the user presses the key intermittently we apply a little bit of acceleration which is the flap and this is in the opposite direction of gravity to pull the bird up we restrict the bird to quite a complicated trajectory in that it has to be falling before you can flap the wings again and we know the bird is falling because the birds velocity will be positive and in fact we want to emphasize this because the velocity becomes positive at about this point so it would be possible to have a trajectory which looks like this which is no good it's too easy for the player to understand what's going on so instead we wait for the velocity to be positive and over a certain threshold and it's this discontinuity in trajectory which is very difficult for our primate brains to understand and predict and that makes the game difficult as the bird has no physics in its X Direction the world moves around the bird and we want to create an infinitely long world for the player to try and fly through avoiding obstacles and I'm going to borrow an idea that we used for the code at yourselff Frogger game this rectangle represents the console viewing area and our bird is in a fixed position along the x axis and is allowed to move up and down in the y axis to store the world I'm going to break the visible face intersections in this case four sections can be seen on the screen I'm going to have a hidden fifth section just off the screen each section is going to hold a single value which stores the height of an obstacle and for my simple implementation of flappy birds the obstacles are really just a gate I only need to store the lower half of the obstacle because the upper half is always going to be the lower half offset by a fixed amount to represent a portal I even have an obstacle ready for the off the screen section and as time progresses I offset the starting points for each of the sections to give the impression that the bird is flying through the obstacles this of course moves the section off the screen and when the whole of the section is off the screen I remove it from the front of the list create a new section and add it on to the back of the list and then I reset the section offset this technique means I need few resources to store a world that is infinitely large so let's start coding things up I'm going to have three floating point variables to represent the position velocity and acceleration of the bird and I'm going to start by just making sure that we get the physics right so let's draw the bird onto the screen I'll calculate its offset in the x-direction is just being the width of the console divided by three so it's always in the same place I'm just going to use the draw string function provided by the game engine to draw the bird and we can see it is too wide character strings on different rows and I choose a different set of strings depending on the birds velocity because if the birds velocity is positive the bird is falling so it's wings are going to be up and when the birds velocity is negative it's just flapped its wings it's moving up the screen you'll notice the birds aren't identical and that's because I'm using the slash character as the escape character in this instance the physics is quite simple to update the position we integrate the velocity with respect to elapsed time and we need to update the velocity with respect to acceleration and the elapsed time there's only two factors that affect acceleration and one of those is gravity I'm going to store.this is a confident and the acceleration is decided by whether the user has just pressed the space key before this frame so if they press the key the bird is going to flap its wings else the bird is going to fall due to gravity and this is where we'll change the acceleration by the gravity constant with respect to elapsed time and the physicist among you might be thinking well hang on that's not quite right in this instance F gravity is considered jerk or jolt depending on where you're from and because we don't want the bird getting out of control I'm going to put in a hard constraint that if the birds acceleration is ever greater than gravity because this is an accumulation of some force then I'm going to cap it to be gravity however when the bird flaps its wings I'm going to set the acceleration to zero but I'm going to set the velocity directly to be a proportion of the gravity and you can see I've included a minus sign here to make sure that the velocity is going up the screen so this in effect removes any falling due to gravity and artificially forces the bird in an upward thrust before we do any drawing I'll clear the screen let's have a look how this feels so the bird falls and it accelerates as its Falls and as I smash the space key the bird flaps its wings and it increases its distance on the screen the downside is I can repeatedly press space and we can see the bird moves smoothly upwards this is too simple for the player so let's make this more difficult by adding an additional clause that the space key press is only valid when the birds velocity is greater than a proportion of the gravity falling down now when I smash the space key we can see the bird has to fall a little bit before it continues on its upward journey now we've dealt with the physics let's deal with the world I'm going to create a variable F section width which just defines the width of the section in a floating-point domain and a list of integers which are the obstacle heights and I'm calling this list section in the on user create function I'm going to initialize my list to all zeros this gives the player a bit of a chance at the start there's no obstacles but it also allows me to set the F section width variable depending on the size of how many elements are in that list and this means just by how we initialize this list we can change the density of obstacles that the player has to avoid in order to give the appearance that the bird is moving smoothly through the level I'm going to create a variable called level position which stores the offset to the first section and just after our bird physics section I'm going to update this level position variable I've chosen the value 14 here because it seems about right for the speed if you increase this value the level will move faster and if you decrease it it'll move slower and of course this is with respect to every lap time this allows us to make sure the algorithm will run on multiple computers but all of the players face a consistent challenge we know we need to create a new section to add to the list when the level position variable exceeds the section width variable so we'll test for that with an if statement and the first thing we'll do is well we don't want to set our level position back to zero but we'll subtract from it the section width and that's because depending on the speed of the platform level position may have increased in a step size sufficient enough to make this reset look a little bit jerky at this point the section at the front of the list will have gone off the left-hand side of the screen so I'm going to pop it from the front of the list we're done with it then going to choose a random value to represent the size of the obstacle and I don't want my obstacles to be precisely on the zero row or the screen height row so I'm adding a minus 20 in here to make sure that there is always some obstacle on the screen and then just to make it interesting for the player I'm going to test for if the random number is less than or equal to 10 in this case I'm going to set the height of the obstacle to zero which means we won't draw an obstacle at all this will give an empty space for that section this allows the player to have a bit of a rest recuperate or get out of a particularly awkward trajectory although it is completely random which means there is no skill at all to this horrible game once I've decided what the new sections obstacle should be I add it to the back of the list after we've cleared the screen it's time to draw the sections I'm going to use a little for loop to do this because all I need to do is automatically iterate through the list and if the value of that section in the list is not equal to zero then we're going to draw it otherwise we're not remember there is going to be blank obstacles I'm going to need to know which section of the list I'm currently in so I'm going to create a temporary variable called n section which I'll update per iteration and this is because I need to relate the lists current section position to a physical coordinate on the screen given a section we need to see how we're going to draw it these are of course going to be filled in rectangles over green characters but that means we've got some sort of offset here and here within the section we don't want to fill in the whole section because it'd be too difficult for the bird to fly through and we need to have a gap for the bird to fall or rise in between and I'm going to start by drawing the bottom rectangle so I need the coordinates at this point and the coordinate of this point so this is the code used to draw the bottom rectangle let's see how it's constructed we take our current section and multiply that by the section width so that will give us an offset into the console screen before we want to draw the green pipe for example we also want to have a little offset of 10 and this makes sure that the rectangle doesn't fill the whole section and then we want to offset the whole thing by the current level position and this will give the impression that the level is scrolling smoothly past the bird the height is simply the height of the console minus the value that were storing for the obstacle in the list the bottom right coordinate is much the same except this time we just go to the screen height we're going all the way to the bottom and I'm using solid characters that are green and to create the top rectangle in exactly the same way except this time I'm drawing from the very top of the screen and I'm drawing to our stored value minus 15 and that means that all of the portals all of the gaps in between the obstacles will be 15 characters hi there's a lot of constants in my code here which could be variables and they could change over time to change the challenge for the player but if you implement this I'll let you play with those let's see how this works so our bird is falling and here comes our first obstacle now there's no collision detection at the moment so the bird can simply fly through everything and we can see there's an empty space there which was nice and this time we've got a run of three obstacles four obstacles and there's a gap in between each one I mentioned earlier that we could change the density of the challenge by changing the number of elements in this starting list so here if I increased it from four to six and when we run it now we can see that the obstacles are much closer together increasing the challenge considerably for the player I'm going to leave that back at four because I think that's a reasonable challenge right thankfully we're almost done now all we need to add is collision detection and game scoring love you I'm going to cheat with the collision detection I could try and mathematically work out where the rectangles are and see if they intersect but instead what I'm going to do is take the four corners of the bird and check them against the screen before that we've already drawn two and see if there are any obstacles there so it becomes important where we do this collision detection whether the result is valid or not and we don't want to do any collision detection after we've drawn the bird so the collision detection is going to be a one-liner but I've broken it off here so it's easier to see what's going on we have a boolean value B has collided and there are going to be four cases in which this is going to be true either the bird has gone off the top of the screen almost because I don't want it to crash into the score which will draw up there all the board has fallen off the bottom of the screen or the corner of the bird has intersected with something other than a blank space in the character array representing the output displayed to the console and unusually for one of my videos we're accessing the screen buffer directly in this case or I'm taking the y-coordinate of the bird times the screen width plus X something we've done in pretty much every one lone coda video ever and I'm just checking what is the character at that location and the next two have a plus six on them because these are for the front of the bird so any of these conditions are true the bird has collided with something the game has ended we need to update the scores but let's add in some missing variables firstly we're going to need the house collided flag this is a boolean I'm also going to add in some scoring variables going to record the number of attempts that the player has had since starting the program and I'm going to score by counting the number of it's not necessarily the obstacles past or the distance traveled I want to be a bit different and I'm going to record the maximum flat count since the program has started so the player knows if they're beating the previous score or not when there is a collision I don't want the game to just immediately restart the level the player is going to need an opportunity to take a break and to think about what they just did wrong have a think about why they're even playing this rubbish and then start the game at their own pace and since this means the whole game has to pause I'll have to put the whole game so far into the result of an if condition based on the has collided variable so if the player has collided it does something else it runs the whole game that's why I've zoomed out so we can see all of that change together and this means when a collision has occurred everything that was drawn to the screen will just remain drawn to the screen because the on user update function doesn't do anything else it can't clear the screen it just goes static and so when we're in collision mode like this we're just going to wait until the player has released the space case so they have to press it again to start but this means we then need to reset the game so I'm going to create another flag called reset game and this reset game flag will be tested on each loop and it'll be the first thing that is tested and its purpose is just to reset absolutely everything to an own starting point so we're going to clear the collided flag and we're going to clear the reset game flag because we don't want it to keep calling this and we'll set the bird to some default positions and we'll clear out all of the sections so far I'm also going to start adding in some scoring so I'm going to set the current flap count to zero and the number of attempts count I'm going to increase because every reset we can assume is another attempt it's quite nice having this reset flag here because it means I can also just call it in on user create I can said it's a true and I know that the game will start up in an own State since we're scoring the number of flaps being counted I'm going to add to the when the user presses the space key for flapping I'm going to increase the n flap count variable and I'm going to check it against a maximum and if we're greater than the maximum then the maximum becomes the current count so the high score is always updated and just so the player is aware of how much of their life they're wasting I'm going to display the results on the screen from coordinate 1:1 so not quite in the top-left I'm going to display the number of attempts the current score and the high score let's have a look you can see the number of attempts there isn't decreasing but the number of flaps and the maximum score is and if I crash yep there we go it's paused the game and it won't do anything until I press the spacebar at which point it restarts and so that's that should you wish to subject yourself to such a miserable form of entertainment this source is available on github if you've enjoyed this video please give me a thumbs up think about subscribing and I'll see you next time take care so just go through the damn obstacle just just one more go one more go damn it