How to make Flappy Bird in Unity (Complete Tutorial) πŸ€πŸ’¨

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello my name is adam in this video we are going to learn how to make flappy bird in unity flappy bird is an infinite side scroller where the player controls a bird attempting to fly between columns of green pipes without hitting them if you need help at any point in the tutorial feel free to join our discord community where we can offer direct help there's a link in the description of the video please consider subscribing to the channel to support the amount of effort it takes to create a video like this one it is completely free but it helps me a ton thank you enjoy the video let's begin by creating a new project using the unity hub in the top right corner we can click the new button to create a new project we can also click the drop down next to it to select the specific version immunity we want to use for this tutorial i will be using unity 2019.4 it won't really matter though which version you use we won't be using any special features that are available in one particular version of unity so really feel free to use whatever version but i will be using 2019.4 we're going to select that here we want to choose the 2d template since this will be a 2d game this is going to install various 2d packages that will help us in our development go ahead and name your project whatever you would like i'm gonna call mine flappy bird and choose wherever you would like to save your project and go ahead and click the create button from here it might take a couple of minutes to initialize so we'll pick it up as soon as it's finished once your project finishes initializing you should see something like this by default unity provides us a sample scene that we can use to get started i'm just going to simply rename this to flappy bird and from here we need to import some custom sprites that we'll use throughout our game if you want to use the exact sprites i'll be using you can download them from github there will be a link in the description of the video that link will take you to the repo here look for this download link and that will download the entire project within that project will be the assets folder and then the sprites folder and this will contain all the exact same sprites i'll be using i definitely encourage you to use your own sprites though let me go ahead and just drag these files into my project here although first let me create a folder to contain them all this will just keep them nice and organized so i'm just going to call the sprites and let's go ahead and just drag in these files and once these files are in our project we can change various import settings on them so for all of these sprites one thing we want to change is our pixels per unit all of these sprites were designed at 24 pixels per unit so we set that to be 24. this of course might vary based on your sprites if you are using your own custom sprites from here i'm also going to change the format to rgba 32-bit i'm going to change the max size to 256. since none of these images are very large and finally this is pretty important i want to change the filter mode from bilinear to points this is going to really maintain the pixel style graphics that we want so point there let's go ahead and apply all of these changes and we're good to go on our sprites now next let's just do a little bit of scene setup before we begin scripting so in the left here is our hierarchy where we can see all the game objects that exist in our scene right now there's just a camera and on the right is our inspector where we can see the various components that exist on that game object so for our camera component i want to just simply change the background color and actually if we switch to our game view here we can preview what our game looks like let me go ahead and change this background color to match our background sprites so i'm and i just specifically want to match just this blue part of it and i can actually just use the little dropper tool the eyedropper here and then i can hover over that color and then we can set that exactly we're actually going to hold off on adding our background and our ground to our scene because we're gonna set them up a little bit differently to um using a parallax effect so we're gonna focus that focus on that specifically in a little bit but for now let's get our player in there our bird so we can actually just drag this sprite into our hierarchy here and this will add it to our scene we can see our bird show up there and then from here we just need to add a few different components to our bird here to this game object and first i'm going to call this player and i'm going to set the tag to be player this is a this tag already should already exist as part of your project it's one of the default tags unity provides this will allow us in our code later on to you know reference this object by this tag or determine if some other object is in indeed this particular object from here let's add some components we can click add component and we're going to add a rigid body 2d this is a 2d game let's make sure we use the 2d version and then we're going to change the body type to be kinematic what our rigid body does is it turns this object into a physics object so this is going to actually simulate physics on this object however by making it kinematic it's not going to simulate the physics it's not going to change the position or anything however the reason why we still need this component is because without it we can't detect collisions between our object and other objects so we need a rigid body but we're going to be moving the bird manually through its transform so we're going to set it to kinematic and then from here i want to also add a collider specifically i'm going to use a circle glider although it doesn't really matter but i find this circle clutter kind of works best and if we go to our scene view here is scroll in you can see the green outline here is the actual area of the collider and our collider what that does is it defines the collision area of this object so one thing i kind of want to do is make it a little bit smaller um so am i actually going to just change the radius here to maybe 0.25 and yeah that looks that works actually pretty perfectly um so that's it really for our bird and that's all the scene setup we're gonna do for now like i said we're gonna focus on some all the some of the other elements later but let's go ahead and start scripting our bird all right let's create our first script although let me create a folder that will contain all of our scripts just to once again keep everything organized within this folder i'm going to right click create c sharp script and i'm just going to call this player once that script has been created we can drag it onto our player game object so we can drag it here put it into the empty space at the bottom and this will now execute the script as part of this game object go ahead and edit this so by default unity creates a class and here is from mono behavior personally i like to delete these functions they provide by default and some of these imports that aren't used just my preference there [Music] so for our player we need to declare a couple variables that we'll use throughout the class here one is going to be our direction so let's make this oh we can make this private actually not public so private vector three direction here and then let's also create a public float and we'll call this gravity so this will allow us to customize how much gravity we want to apply on the bird which you might use to change how difficult the game is and i can default this to maybe 9.8 or negative nine points since that's what real life is if you notice here with that being public if we go to our script in the editor we will see that one show up [Music] only the public variables though which is really convenient and this allows us to customize that value in our editor so from here let's add our update function update is a function that uni calls automatically every single frame this script is running and usually this is where we handle things like input so in update let's go ahead and handle input what we can do is add an if statement that says if input dot get key down and we can look for a specific key in our keyboard so for example i could do spacebar every time you press spacebar we will like flap or kind of fly upwards or i could say if input get mouse button down and then you have to provide an index here zero would be your left click so in this case i'm saying you can either press spacebar or you can press the left mouse click and this will kind of flap the bird and so when we do this we want to set our direction to be up vector3.up and we actually might want to multiply that by some strength and once again that could be another variable we use to kind of dictate how difficult the game is let's go ahead and add that i have another public float here i'm going to call it strength and maybe i'll default it to five so here we can say vector3 dot up time strength and we're good there now considering this is a mobile game or the original game is a mobile game you might want to test for touch input and so let me show you how to do that although i won't be able to actually fully test it out because i don't have my all my mobile setup but if we want to handle touch inputs we can say if input that touch count is greater than zero so this is letting you know how many you know fingers essentially are touching the screen and if it's more than one we can go ahead and get a reference to that particular touch object um so we can say touch equals input dot get touch and then we provide the index here we're just gonna only get the first one we don't really care about the others although maybe for your game you do with this touch here we can check if it just began if it just ended if it's currently active things like that so for example i want i might want to say if touch dot phase equals touch phase dot began so this is essentially saying i just touched the screen i just began touching the screen with some finger and then from here would probably do the exact same thing we're doing above so essentially it's like you tapping potentially this might vary based on your implementation maybe you want to do it when it ends instead of began it can all vary but play around that's kind of the just the very very basic way you can do some touch input and then from here our input is good now but we always need to make sure we're actually applying gravity to the direction so this direction only gets set to up when we actually activate our input but every every other frame you're not actually activating the input we always want to be applying gravity or every frame no matter what we always want to apply gravity so we can say direction um specifically just the y-axis we only care about gravity along the y-axis we say direction.y plus equals gravity and then times time that delta time let me explain what this is going to do but let me write one more line of code first now that we have our direction we just need to update the position of our bird and to do that we're going to access the transform of this object and we can say position and then plus equals direction so we're updating the position of our transform based on their direction and we also want to apply that times this by delta time this is going to make it frame rate independent no matter what the frame rate of your game is whether you're running at 60 frames a second or 1 million frames a second it's going to be consistent now you might be wondering why are we also why are we timesing by delta time twice well that's because gravity is an acceleration it's meters per second squared and so we specifically for gravity we actually want to multiply it both times so that's really it for our player let's go ahead and test this out we can see our variables there those are good let's go ahead and just run our game so by default i fall down because of gravity and if i click or press space bar i flap back up perfect so this is working great and once again you can customize these values to potentially change the difficulty of the game let's actually animate our bird now when it moves when it flaps let's go ahead and go back to our player script here animate it we just need to change the sprite that is currently being displayed and just kind of cycle between um a few different sprites so to change the sprite we're going to need an access to the sprite renderer component because the sprite renderer component defines the actual sprites as we can see here in the editor let's go ahead and declare a variable for that we can just call this and we'll make this private we're going to call it spriterender spriterenderer we can assign this this value in our awake function here wake is called automatically by unity the very first frame this object um essentially when this object is initialized and it will only get called once per the whole life cycle of this this script so here we can say sprite render equals git component and we specify the type of component we want to get which is sprite render what this is going to do is it's going to search for that component on the same object that this script is running on right so our player here our player game object has our player script and so when you get component it's going to look for these other components and see if it matches the one you specified and then from there we need to define an array of sprites that we can actually cycle between so this will make public because we'll define what those sprites are in our editor and we're going to make this an array using our square brackets there i'm just going to call this sprites and lastly we need one more variable to keep track of the current index in this array so this will be an integer and we just call this sprite index all right so from here when our script first starts we need to start kind of the animation so unity has another function that's called automatically called start this will get called the very first frame that this object is enabled and when we start here we can use invoke repeating invoke is a way of calling another function and in this case repeating so it's going to repeatedly call that function over and over again although we need the func we need to define what that function is first so let me actually create a function here i'm just going to call this animate sprite let's go back up here we need to pass in the name of the function so i can use the name of keyword then i can say animate sprite and then we need to provide the time like how often do we want this to repeat or this is the initial one and then the repeat rate but i'm just going to use the same for both of these and let's say it cycles every you know 1.5 seconds or something and you can obviously adjust that to your liking so this is going to call our function down here every 0.15 seconds so within here we can increase the index and then reassign the sprites on our sprite render based on whatever index in our array so that's what i'm gonna do i'm gonna say sprite index plus plus that's just gonna increment it by one and then we need to make sure it loops back to the beginning if we get to the very end of the array so we can say if sprite index is greater than or greater than or equal to sprites.length [Music] um then we can set it back to zero to start over and then finally we just need to update our spread so we use this right render dot sprite equals and we're gonna access our ray here we're gonna use the subscript operator to then get the sprite at this index and that's really it we just need to now assign those sprites in our editors let's click our player game object we can see our sprites here if we go to our sprites folder there in my case i have three sprites so i'm going to set our size to be three and i'm just going to drag in each of these one two and three let's go ahead and run this and see what happens here we go so now we kind of are flapping and it looks it makes a lot more sense it looks like we're actually moving properly this time [Music] next let's add our background elements and this is going to really make everything come together and and especially make the player feel like they're moving now remember in a side scroller the player's transform left and right isn't actually changing the background is moving and that's giving the illusion that the player is moving forward so go ahead and add our background elements now however we're not going to just drag in our background to our scene because this is going to create a sprite renderer we're going to actually do this a little bit differently in order to create a parallax effect and to give there'll be an easier way we can get the background to move kind of infinitely using a different approach rather than a sprite render so i'm actually going to right-click in our hierarchy i'm going to go to 3d object and that's okay even though this is a 2d game we can still create 3d objects and i'm going to create a quad now crowd a quad really is more of a 2d object but they're used commonly in 3d games i'm going to reset the transform here to its defaults we can use a little three dot menu there and a quad will allow us to to render a texture on this you know on this quad here um but to do that we need to create a material so if we go well let me first create a folder for our materials as well as folder materials once again just keeping everything organized let's open that up and let's right click create material i'm going to call this background and from here any material you can specify the shader that is used to render this material in our case we just want to render a texture so we can go to unlit texture and this is going to change the properties that are available for us mostly we just want this texture here so we can go to our sprites we can drag in our background and boom now we have a material with our background on it and we can preview that down here we can go back to our quad object and we can drag our material onto it you can actually just drag it to this empty space or into the materials slot here now we can see our background obviously it's really small because it's not sized correctly but we'll get there one thing we should do is remove this mesh collider our background does not need a collider we don't need our bird colliding with the background element there so let's get rid of that let's go ahead and size this properly so for your game i don't know if you're developing it for mobile for tablets for desktop it doesn't really matter but you can preview your game um using whatever particular aspect ratio you want to so right now i'm using 16 by nine which is more of a desktop um asp ratio maybe you want to do more like an a phone or a tablet whatever you want to do it doesn't matter we just want to make sure that our background can cover the entire space so i'm going to set my scale to be 24 and that'll just make sure it's big enough to really cover the space here so we can see the white outline is our camera and very much it covers it it goes past it and that's perfectly fine then i want to set our y scale to be 10.666 repeating um and that's because that's just going to maintain a specific aspect ratio to this particular image so it's just going to maintain it exactly it doesn't really matter if it were to stretch a little bit and obviously it could vary if you're using your own sprites but just once again make it large enough that it fits and fills up the entire space now obviously it actually is stretching right now and that's because we need to actually tile this and this material lets us change the tiling properties on it so i can say tile it by four and this will basically display the one image four times now it still looks really messed up and that's because we need to change a particular import setting on our um on this file here we select our background sprite let's change the wrap mode to repeat we apply that now you can see our image repeats and we should do the same exact thing for our ground here because we're going to be repeating this process for that object too let's change our ground so this looks perfect it fills the entire space it repeats four times everything's good and then we can write a little script that will simply cycle the offset here see if i change this manually i can just change this forever i can it'll just go on forever because it repeats and it loops back and so what we can do is write a script that changes this and this is going to make it seem as though we're moving so for now let me set that back to zero and oh let me rename this object to be background quad just make it a little bit more meaningful let's go ahead and write that script go to our scripts folder i'm going to right click create c-sharp scripts i'm going to call this parallax let's go ahead and add this script to our background so we'll drag that on let's go ahead and edit this and for our script here we just need to essentially get a reference to the mesh renderer so the mesh renderer on kind of like we did for our player we got a reference to sprite render because we changed the sprite property in our case we need to change the material and you access the material through this mesh renderer component so we need to get a reference to that so very similar to what we did on our player we can declare a variable here from mesh renderer call this mesh renderer in our awake function we can get component of that particular type and then in our update function we can change the offset on the material repeatedly so update we can say meshrender.material.main texture offset plus equals and then some new th this is a vector two so we're gonna form a new vector two and we just need to set this to be you know whatever we want we should probably declare a variable that'll allow us to customize the speed that it moves we can have a public float here call this maybe animation speed just going to default it to one and so here we can say animation speed once again we're in times by delta time because we want it to be frame rate independent and then we'll set this to zero for the y we don't care about the y we're not we're not moving it and the y we're only moving it in in the x and that's actually all we need let's go ahead and test this out let's play this um obviously my character fall fill it's obviously a little bit too fast let me go ahead and change it we can go to our background i'm just going to make this way smaller let's do 0.05 and let's play it again that's a lot better now this is a background element it's really really far away from the player and so it should be moving much slower but now let's go ahead and add our ground and our ground you'll notice will be a lot faster because it's closer to the camera and this is going to create the parallax effect the the difference in speed between the background element and the foreground element creates this parallaxing effect so let's sort of repeat the same process let's go to right click on our hierarchy 3d object quad let's call this ground i'm going to reset the transform i'm going to remove the mesh collider and let's create a new material oops not a lens flare that's not what i want create material call this ground we're going to change the shader to omelette texture we can go ahead and select our ground texture there there's our material we're seeing the preview of we can tile this one by four as well it'll be the same amount and let's go ahead and add this material to our um to our ground mesh right over here and let's see what else we need to change the scale of our object so i'm going to do 24 to match the background and this one only needs to be scaled 2 in the y and you can see you can see this orange outline but it's actually behind the backgrounds when it needs to be in front of it so what we can do is actually change the z position this is going to change the draw order that they get rendered in so we're going to make that negative one the the lower the number the the you know it gets drawn first or i guess last but yeah so negative one there now it's in front which is what we want and let's go ahead and position this towards the bottom let's say negative 4.5 that looks perfect let's see what it looks like from our camera's perspective yeah that looks great and we can just add that exact same sprite that we already added or not spread the script the script so parallax script and like i said the the speed will be bigger will be much larger in this case since it's closer we'll just keep it at one see what it feels like yeah that actually feels honestly feels great it actually feels like i'm moving and flying now with the ground moving the background moves too but it's much slower because there's a lot farther away and that is a really nice parallax effect okay let's start focusing on our pipes now the first thing you want to do is create a prefab for our pipes because we're going to be repeatedly spawning new pipes and so we need some prefab that we can use to kind of clone that object over and over again let's go ahead and create a folder for our prefabs as we've done for all of our asset types and let's just start creating our pipes in the scene and then we can drag that into our folder here and that will turn it into a prefab so for our pipes it's actually going to be a um a collection of two pipes they're going to be the top pipe and the bottom type and that's going to be treated as one kind of game object so we can just create an empty game object in our hierarchy i'm going to reset the transform here let me switch to our scene view and from here we can create children objects which in objects um let's find our pipe sprite and let's drag that in and we're gonna drag it over our game object here and this now you can see it's parented to that i should probably call this too i should probably call those pipes we've got one pipe which is great and let's duplicate this i can press ctrl d or command d or you can also right click and do duplicate so we've got two pipes right now they're sitting on top of each other we just need to position them kind of respectively so let's put one maybe 4.5 and the other will be the exact opposite so negative 4.5 and this creates a little gap between them the one at the top needs to get flipped around so let's go to that one you can just simply rotate it on the x-axis to flip it around that looks great now this gap in between is going to really play a pretty big a pretty big factor in how difficult your game is so feel free to adjust this distance to your preference i'm going to rename these boats to be pipe or i can say you know top and bottom just so it's a little bit clearer what's what now one thing we need to do is we need to add a box collider to each of the pipes the collider will allow us to detect when our bird actually runs into the pipe and that will cause the game over let's add a box glider to this 2d and we're going to mark it as a trigger we don't actually really need to simulate the real physics of it we just need to know hey the bird has entered into this area so that's what a trigger will allow us to do same thing on the bottom add component box collider 2d and you'll notice that it changes the size automatically based on the sprite which is really convenient and then finally we actually want one more little trigger zone right in between because that's gonna tell us hey we should increase the score they kind of flew through it successfully boom give them um another point so we can create an empty game object as another child of this i'm just gonna call this like scoring or something i'm not really sure what to call it we'll just call it scoring and it's just going to have a box collider on there 2d of course we'll mark it as a trigger we don't actually want the bird to fly into it we just want to know when they've entered this zone so we can give them a point and we'll make it a little bit bigger so we can change the size of our box clutter we'll make it fit within that gap and i might make the axe a little bit smaller just so you know they have to kind of cross at least sort of halfway between before they actually earn their points that looks pretty good um you know i'll make the y just a little bit bigger okay so it doesn't matter if it overlaps because they will run into the pipe before they run into the little scoring zone here so that's it for our prefab let's actually turn it into a prefab now we just take this game object and we drag it into our scene here or not into our scene sorry into our project panel and now it's an actual prefab now that we've done that we don't actually need to have this object in the scene we can delete it now we have the asset and we'll use this to then spawn it repeatedly in code okay let's create our spawner script that we can use to repeatedly spawn pipes that the player will have to obviously avoid go to our scripts folder right click create c-sharp script i'm just going to call this spawner let's open this up just like i usually do i'm going to delete all these things and let's think about how we want to spawn this so what are some of the variables we're going to need one we're going to need a reference to the prefab so we can spawn that object over and over again we also might want to define some variables for how often the pipes spawn and we might want some variables to change the position of the pipes and maybe like a range between some min and max so it'll kind of randomize where within there it will spawn so let's create a variable for our prefab we're just going to reference this as a game object we'll call that prefab let's create a variable for our spawn ray and this will be a float because it's going to be the amount of seconds and let's just default this to 1. let's create two more variables now to kind of define a range that will position the pipes either up or down so we can maybe call this min height and then maybe that's negative one and then we can do max heights and this can maybe be positive one okay and then from here very similar to what we did in our player we're going to do this invoke repeating so although we're not going to do it on start we're going to do it on enable and that's because at some point we're going to disable the spawner you know for example if the player loses we want to disable the spawner kind of stop everything and so we want to only start repeating like do the spawning repeatedly when this spawner script is actually enabled so here we can do invoke repeating we need to provide the method which we don't have yet let's go ahead and create that i'm just gonna call this spawn and then we can pass the name of that function to our invoke repeating we have to give it our time here our time is our spawn rate that we declared same thing here we'll just pass that twice and then let's do on disable we need to cancel this so it stops spawning so on disable we can say cancel invoke and then name of spawn and by the way both on enable and on disable are unity events that are called automatically whenever the script is enabled or disabled you can enable or disable a script via this check box here so when you you know or that's how you would do it in the editor you can obviously also do it programmatically which we will be at some point but that little check box is setting it to be enabled or disabled so in our actual spawn function we need to clone our prefab we can say game object we can say pipes and we can say instantiate this allows us to create a new object and it's going to clone an existing one so we're cloning our prefab and we're getting a new set of pipes here so we can say prefab and give it an initial position and rotation so the position should just be wherever the spawner is positioned you can move the spawner anywhere in the scene and that's where they will spawn it so we can just say transform that position just referencing the spawner's position and then same thing here we can pass in the rotation they don't need to be rotated at all so we can just say quaternion.identity is essentially no rotation and then finally we want to adjust the position of the pipes either up or down based on a random variable between these so we can say pipes.transform.position plus equals up times then a random value within a range we can use a rank unity's random class and we can provide a min and a max here so this is our min height and max height and this will now position the objects up or down and since this could be negative if you do up times a negative value that would actually be down so up or down between some random value in our range there and that's really it for our spawner script go ahead and test this out although we need to actually create our spawner game object in our scene so let's go ahead and right click create an empty object here i'm going to call the spawner and we just need to position this um for now i'm going to reset the transform and let's just position this off to the side here so let's maybe set the x to be 12. actually i actually would perfectly if you remember our background and everything was set to 24 so we're kind of doing it halfway it's right on the edge of our map there and let's add our script to it we need to make sure we're assigning our prefabs we can go to our prefabs assets here and drag that in and we're good there and let's go ahead and run this and see what happens okay so you can see on the left we have our pipes spawning but of course they're not moving because we haven't written the code to do that but we at least have them spawning repeatedly so that's a good start all right let's focus on getting our pipes to actually move across the screen let's go ahead and create a new c sharp script i'm gonna right click create c sharp script i'm gonna call this pipes and let me add this to our prefabs go to prefabs let's select our asset there and let's drag our pipe script onto it let's go ahead and start editing this so for our pipes here all we really need is a speed variable and then in our update function we will move the position of our object so we can say public float speed i'm gonna default this to five and we're making this public so we can customize it in the editor once again this is a way you can change the difficulty of your game let's add our update function here and we just gotta say transform that position plus equals vector three dot left times our speed times delta time which will make it frame rate independent so it is consistently moving regardless of the frame rate and then the other thing we want to do is we should destroy the pipes as soon as they're off the screen we no longer need them so we can detect if the position has exceeded some value and then just destroy the pipes now we could easily just hard code some number and that would probably be fine but it's bad practice to do that so let me show you how we can do this better let's create a variable that is going to represent the left edge of our screen [Music] and then here we'll we'll assign this value but here we can say if our transform.position.x is left that less than the left edge then we will destroy our game object destroy our pipes in this case now how do we assign this value so we can calculate that actually pretty easily let's add our start function we don't need to calculate it every single frame we only really need to calculate it once we'll do that in start and we need to convert screen space coordinates to world space coordinates our transform is always in world space or are well not always but specifically here position even says is world space position but we want to say whenever our pipes are past the edge of the screen whatever that is whether you're on mobile tablet desktop we don't care what the screen size is we just need to know that it's past that edge of the screen we will destroy so we need to convert from screen space to world space and you do that by accessing your camera and then there's a function you can call so we can say left edge equals camera dot main camera.mains gonna find the game object or you know the camera that is tagged main camera and then we can say screen to world point so this is converting from screen space to world space so we need to provide a screen space position here so our left edge is just zero actually it's just 0 so it makes it easy so we can just say vector 3.0 and in this case we're getting an entire vector back we only care about the x axis so we can just say dot x now there's one issue with this which is that when we let me show you if we bring our pipes into the scene here our pipe the position of our pipes and most game objects is centered around or it's it's pivoted around the center point here so as soon as our object the center of it hits the edge it will get destroyed but we're we're going to see them kind of vanish before they're actually fully off the screen so we want to just offset that position a little bit more to make sure that our pipes are fully going off the screen before they get destroyed so let's go back to our script real quick and all we simply need to do is just subtract one from this position so we're just making we're just pushing it one unit further and that'll give us enough space to make sure it goes fully off the screen i suppose that depends on how big your pipes are but one unit in most cases should be good but potentially you might need to adjust that and so that's it for our pipes let's go ahead and test this out let's go ahead and we added our script to my things all bugs so let me pause real quick and come back because my interface got all bugged one second okay i've relaunched unity interface is no longer bugged i don't know what happened there let's go ahead and just run our game and see that this works and once again our pipes script is part of our prefab we're good there speed is five i'm just going to watch from the scene perspective so our pirates are moving as soon as they cross that threshold boom they disappear get destroyed from the perspective of the game it looks great so perfect this is working absolutely perfectly all right let's start to tie everything together by adding scoring and of course actually running into the obstacles and getting a game over so first let's create a script that's just gonna kind of manage the overall state of our game i usually like to call this our game manager so let's create a script called game manager and i usually just have this on a standalone object in our scene we can create an empty object you can call this game manager i'm going to reset the transform here although it doesn't really matter we're gonna drag that script onto our object there let's go ahead and edit this so for one we need a score variable and i'm gonna make this private because it isn't something we need to change in the editor and then let's create a couple functions here so for one i want a maybe an increase score function which will simply increase our score by one and later on when we add ui we'll add another line of code here to update our ui but for now that's all we're going to do and let's also add another function called maybe just game over and this will obviously get called when you run into something and when you run into something you know we'll have to you know we'll display a menu and so on to start the game over we're gonna do that separately but let's just get the functions in place and maybe for now we'll just debug you know we'll just we'll just say game over just we just want to know that this is being called we'll worry about everything that happens a little bit so how do we detect these two different things so one we need to know when our bird crosses over the little scoring zone in our pipes here and we also want to know when they hit a pipe itself or the ground if they just fall and hit the ground that also is a game over so what we can do is we can tag some of these game objects and then we can detect or we can know which object the our bird has run into so let's go ahead and open our pipes prefab we can set our tag here right now these are untagged let's add some custom ones let's click that click the plus button let's add one for obstacle and let's add one for scoring and let's go back to our top and bottom pipes will both be obstacles we set those to be obstacles and then our scoring zone will be set to scoring and then we also just want to label our ground as an obstacle i know it's not like really an obstacle but we're just gonna pretend anything that's an obstacle means if you hit it you lose and anything that's marked as scoring means you gain sport so now that those are tagged in our player script we can detect collision between the bird and whatever other object we can do this by using the function on trigger enter 2d if you remember we marked those objects as triggers because we don't actually care about the physics simulation so there's just triggers your 2d the 2d versions of them and then this takes one parameter here which is collider 2d and usually people call this other the other collider you have run into and from here we can check what is the tag of this object and if it's either obstacle or scoring we can call the respective function in our game manager so we can say if other dot gameobject dot tag equals let's say obstacle well then we will call to our game manager now we need to get a reference to our game manager one way we can do this is using find objective type and we can see the game game manager this is going to search our entire scene for that object this is actually not the best function to use um it just depends but this can be a very costly function it's very expensive to use this for our game here since this is just happening in one it's not happening every single frame or anything like that we're fine and our game as a whole is very very simple so we don't really need to get too picky about our performance optimizations here just keep in mind this isn't always the best function to use there are better ways to do this they're just a little bit more advanced and complex and it's just not worth going over right now so find an object of type game manager and we can then call our game over function now we can't because they're private so let's go ahead and go back to these and make both of these public that way we can access them externally so now we can actually call game over and then same thing here but this time instead of the tag being an obstacle the tag will be scoring i believe we called it and if it's scoring then we will say game manager dot increase score okay let's go ahead and test out this code we've added yeah we've added it there let's go ahead and test i'm gonna open our console here so we can see that debug statement so i don't since we don't have any ui yet i don't know if i'm actually getting any points but let me run into a um into a pipe there and so no nothing happened i didn't actually hit the pipe so there is a problem here let's take a look at our pipes and let's make sure we have those um colliders on them we do they are triggers so that's good oh our bottom we forgot to mark the bottom one as a trigger so that was a mistake let's test that again let's run it we should see a debug statement yeah so they're game over when i hit yeah so now if i hit the top i get a game over if i hit the bottom i get a game over and let's see if we hit the ground i should also get a game over which i do now one way we can test if our score is increasing we can go to our game manager we can click this little three dot um menu next to the inspector and go to debug and this will allow us to see some of those private variables yeah we can see our score is six our score is actually increasing as we go through the middle here so that's perfect so everything's working now we just kind of kind of create the ui and everything around it all right let's go ahead and throw together our ui if we go to our sprites here we can see we have a few different ui elements we have a game over image we have a play button and of course we'll have an actual text component for our score let me switch back to our normal inspector here and let's go ahead and right click on our hierarchy and let's go to ui and i'm going to create a text element first this will be for our score and before i do anything i'm going to actually change some of our canvas settings so let's click our canvas game object let's find the canvas scalar component and let's change our scale mode i very rarely use the constant pixel size that's defaulted here i'm going to change it to scale with screen size this is going to be important to make sure our ui actually properly adapts different you know to different screen sizes and this is definitely important for mobile where you know everyone's going to be on a slightly different screen size and so you want to try to set your reference resolution around just generally what the target devices are so if you're developing for mobile a common mobile resolution is 640 by 960. for tablet it might be 768 by 1024 and i'll see if then if it's portrait or landscape you know flip flop those values for me i'm developing my game for desktop here so i'm going to just set mine to 1920 by 1080 and then i'm gonna match it with the height what this does is it's going to compare the resolution of the game where wherever it's being played it's going to compare to our reference one here and it's going to adapt the or scale our canvas accordingly and then in this case i'm going to match it based on the height because our ui is going to really just be vertically kind of up and down so the height is going to have the biggest influence here sometimes you write it want it right in the middle in this case i'm going to have it at 1. so let's go back to our text component here i'm going to call this score [Music] score and let's reposition it to the center it's really tiny right now you can hardly see it let's center align it let's middle align it um let's set it to overflow because i don't really care about the actual width and height the score can if your score ends up being 9999999 i just want to make sure it always displays i'm going to set that to overflow set the color to be white let's position it towards the top i'm going to anchor it to the top of the screen once again this is important that you properly anchor things so when your ui adapts to different screen screen sizes it will still be positioned properly so i'm going to anchor to the top now if i have the position at zero you can see it's it's you know it's really small as you might barely be able to see it but it'll be at the very top middle there that's where we anchored it to so i'm going to bring it down of course and say negative 100 let's maybe set the default text like zero and obviously let's make this way bigger now one thing people often do is unity's you default like text component isn't the best and sometimes you'll notice that the font is very blurry um which doesn't look very good so sometimes people will make this font size really large but then they'll scale it back from the actual transform here and this still makes the the font rendering really crisp but still being sized appropriately so i'm gonna set a font size of 300 and i'm gonna make this you know a tenth of that or you know i'm going to scale it back down 10 times so that looks pretty good another thing i want to do is add a custom font let's go ahead and bring that into our project it'll be available on github just like the sprites were link in the description of the video this time assets fonts and this is just a free font that i found online that very well matches the style of the rest of our graphics we go ahead and create a new folder for fonts let's go ahead and drag that in and now we can assign this to our text component there and that looks a lot better um let's see what else one thing we might want to do is change or not change but add a little outline just to match kind of you know for example our little floppy birthday little outline so let's add an outline component we can click the add component button here search for outline and let's change the distance because you can hardly see it when we do the 12 um if you remember our sprites were designed at 24. so i'm going to do half of that 12 and negative 12 that looks good we're going to change the color bump the alpha all the way up and let's set the color to be the exact same color as our flappy bird's outline here we use a little color dropper to change that and that looks a lot better looks pretty good yep great there's our text component for our score let's go ahead and add our game over next um sprites now we don't want to just drag this in here because it's going to create a sprite renderer which is not what we want we want an actual ui element right click our canvas ui image and then we can assign these sprite here in the image component now obviously it's all stretched weird so we can click the set native size which is gonna change our size to match the actual image and let's position this we're going to anchor this to the top as well and i'm just going to change the y to be maybe like negative 225. now that works pretty well let's call this game over okay and let's add our play button now this one's an actual button that you can click so let's go to ui button let's drag in our sprite to the image component click the set native size and set native size and you might be able to see if there's a little text on it that says button we don't actually want the text so we can just go to that child game object and delete it and let's go ahead and position this at the bottom this time we're going to anchor to the bottom middle and let's set the y to be um i don't know 200 let me see what i set it on my other one 275 okay 275. once again you might need to position these and scale these differently based on you know if you're developing for mobile or whatever all right that looks good let's call this play button and i think that's it actually that is our entire um ui elements we just gotta hook them up to the rest of our game now okay so let's hook up our ui to our actual scripts now let's go to our game manager let's open this up and we need to get a reference to all these various ui elements we can do do different things with them so let's create a public a public variable here for our text for our school we need to import using uni engine.ui and then we can declare a text component here text and that's called a score text let's get a reference to our play button and i'm just gonna i could reference it as button but you remember this object actually has multiple components there's a button an image so i'm actually going to reference just reference it just as a game object so i get the thing as a whole so we're just going to say play button and same thing for our game over although that one is just an image maybe yours is different maybe there's multiple different components i'm just gonna say game over um yeah just game over is fine and then we also will need a reference to the player themselves so we'll just get a reference to the player there all right so we need to hook all this up we need like a proper like you know game flow like play game you know increase score game over replay etc so when our game first starts we actually want it to be paused because we want them to hit the play button so we're going to add our awake function here and we'll we'll come back to that but let's add some various functions let's just add the functions we're going to need we're going to need play [Music] um we're gonna need pause and then we have game over and we have increased score i think that's actually it so when our game first starts i'm going to pause it because we want to actually hit the play button first um and also as a side note i'm going to set our target frame rate to 60. um i don't need the game to run any faster than 60 frames a second so this isn't required but i'm just going to make sure the game doesn't exceed that frame rate okay so we hit pause as soon as the game starts and in pause what do we need to do well we need to make sure our you know our bird isn't moving our pipes aren't moving or anything and there's various scripts that are all doing different things and one of the easiest ways we can do that in this game is just simply setting our time scale to zero it's essentially pausing the game it's freezing the game time is not going to update and if time's not updating that means our update functions aren't going to do anything you know because everything's multiplied by delta time and so this is a very easy way in our case to just pause our game now something else we do want to do is still we still should disable the player because they check for input and do a number of things so we should still disable the player so we can just say player dot enabled equals false and that's really it for our pause for our game over what do we need to do well we need to display our game over menu or those ui elements so there's really two which is of course the game over um the game over one we're going to set active to true and then there's also the play button we of course want to display the play button so we're going to set that active to true and then when you get get a game over we also want to pause the game so we'll just call pause all right what else our increased score here our score is changing but our text component isn't so now we can actually access score text dot text equals score oops score to string oops two string there we go so this is converting our integer into a string which will get displaying uh displayed on that component and finally we just have our play function here so what happens when you play the game well we should reset our score to zero and since we're changing our score we need to update our text so we can once just same exact line of code we should hide the play button so we can set active false and hide the game over the little game over uh image we'll set that to false we need to set our time scale back to one just so if things start actually moving and happening and we need to re-enable the player so we're doing just the exact opposite of what we did in pause so we're um we're setting our player to be enabled okay and then finally what else one thing we might want to do is just make sure all the pipes get destroyed because there will still be pipes on the screen that um that will just be sitting there and when we play the game we want to reset everything so we'll just destroy all of them one way we can do this is to declare an array of pipes here and we can say find objects of type pipe or yeah the script is called pipes oh that was confusing so oh yeah no that's all right so find objects of type pipes and then we can loop through that array and just destroy all those game objects that it finds in our scene so standard for loop here i equals zero eyes with some pipes at length i plus plus very standard and then we can say destroy pipes i now i've seen this mistake um people have made it from some of my other videos we don't just say destroy pipes eye because this is we're getting a reference to the component pipes it's not the entire game object it's just that one component we want to make sure we're actually destroying the entire game objects we're going to say dot game object it's very important otherwise you'll just be removing that one component and i think that's it honestly we just need to call these function well we're already calling game over we're already calling increase score pause happens respectively from the various functions the only one that's missing now is play and play should get called when we click our button so let's show you how to do that if you go to our play button object find the button component there's this on click handler here we can click the plus button and then we can get a reference to a game object and it allows us to call a function on that now this is another mistake i've seen people make you do not want to drag in the script itself here if you drag in the script itself there won't be anything to call we want to drag in a reference to the game object in our scenes drag that object in here and there will be a lot more options we can call functions on the game object on the transform and on our game manager so game manager play and so now our this play function that we created will get called whenever you click the button let's go ahead and test this out see if everything's working so game starts oh i got an error oh so i forgot to actually assign these references i declared them but i need to make sure i'm assigning all these let's drag our player in drag our score text in let's drag our play button in and our game over image in and we're good there let's try again play game is frozen initially can't do i can't move i'm pressing thing nothing's happening we click play the things go away i start moving my score is increasing i hit the top of the thing so i lost i can play again and there we go so now we actually have a fully working game of um fully working game of flappy bird awesome all right so after a little bit of extra testing i noticed two problems that we need to fix potentially three one is that we're not actually losing when we hit the ground nothing's actually happening and that's just simply because we never added a box glider or any kind of collider to our grounds we can go to our ground game object box collider 2d mark it as a trigger it's already set as an obstacle so i think that's all we need to do let's play the game and there we go now when we hit the ground we actually lose so that's good that's one problem fixed the other problem is flappy bird does not reset its position upon playing again so in our player script we can add an on enable to reset the position if you remember in our game manager when the game starts the player is enabled when the game ends the player is disabled so when we when on enable is called in our player script we can just reset the position we just need to reset the y just the y value so let's get whatever the current position is transform that position and let's set the y back to zero and then just reassign you know reassign this back to our transform um and then i guess we should also reset our direction to our direction just you know initially should be zero so our direction can be vector three dot zero and as once update starts getting called it'll obviously kick back in that should be another problem solved let's play it one more time so i die i press play and it resets now if i go way up here and hit the pipe up there reset it starts back in the middle every time so that's all good the only other thing i sort of noticed it's not a problem per se but i noticed that the pipes tend to go more towards the bottom rather than the top and potentially we want to just adjust the you know spawn position here so maybe i want my spawner position to be you know maybe more one way than the other but just just the way they're spawned you know kind of the way they're positioned this might you might want to vary this so potentially we want you know it's b2 and negative one it it's really up to you it doesn't matter necessarily but with the value of two it'll allow it to go a little bit higher up because it's already reaching the bottom you know we have our ground element here so it doesn't need to go as much down as it needs to go up because there's a lot more empty space at the top so we want to set our max height to be two to allow it to go up even more now once again that's all just preference and something you can play around with to change the difficulty of the game but that is it i really appreciate you watching this tutorial and i hope you learned a thing or two along the way give the video a thumbs up or down to let me know how i did subscribe to the channel for more videos just like this one and leave a comment recommending what you would like to see next if you want to support my work even more you can become a patreon member to receive exclusive benefits including access to the unique assets that i develop link in the description of the video thank you for watching see you in the next one [Music] you
Info
Channel: Zigurous
Views: 3,680
Rating: undefined out of 5
Keywords: unity tutorial, unity, how to use unity for beginners, how to make a game, unity 2d tutorial, game development, how to make a game in unity, unity 3d, unity 2d, game dev
Id: ihvBiJ1oC9U
Channel Id: undefined
Length: 66min 46sec (4006 seconds)
Published: Wed Nov 10 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.