How to make Dino Game 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 the Google Chrome dinosaur game where the player guides a pixelated T-Rex across a side-scrolling landscape avoiding obstacles to achieve a higher score this tutorial will teach you how to implement side scrolling infinite generation and high scores overall it is a fairly beginner level tutorial if you need help at any point 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 if you like my videos it really helps Drive the growth of my channel we're getting really close to 10 000 subscribers thank you enjoy the video let's start by creating a new project using the unity Hub in the top right corner we can click new project let's choose the 2D template since this will pretty much be a 2d game at the very top you can also choose which version of unity you want to use depending on which versions you have installed so for this tutorial I'll be using 2021.3 which is the current long term long term support version doesn't really matter too much which version you use we won't really be using any special components or anything so feel free to use whatever of course you can name your project all I'm going to call this dino game and choose wherever you'd like to save your project and go ahead and click create project from here it might take a couple minutes to initialize so we'll pick it up as soon as it finishes all right let's start by importing some Sprites that we're going to use throughout our project if you want to use the same spreads that I'll be using you can download them from the GitHub project there's a link in the description of the video upon opening that link you should see something like this and you can download the entire projects from this code button here and then you can download the zip of course you can use git commands to clone the repo as well if you're familiar with that [Music] let's go ahead and unzip this project here and then we can pull out the assets that we want so in here you'll find assets and then Sprites and we can grab these let's just sort by pngs here and I'm just going to take all these pngs and I'm going to drag them into our project panel at the bottom here in unity and let's go ahead and create a new folder to organize all of these assets so I'm going to create a folder called Sprites and we're going to bring those all in there now before I move on you can also get these Sprites themselves from chrome since this is the kind of Chrome browser game if you go to Chrome if you open up the game here in Chrome and if we go to the dev tools so we can go to this more tools and developer tools if we switch over to network and let's actually refresh the page it's going to download the assets that are used by the game itself so for example if we click on one of these here's the actual Sprite sheet that's being used by Chrome so you could actually take this and save this entire image but you'll probably need to use some kind of photo editing tool to pull out the individual Sprites so but this is a more comprehensive spreadsheet oh I'm not using everything on here in my version of the game but if you needed the full Sprite sheet this is how you could get that all right so back to Unity one thing we need to do is update some of the import settings on all of these Sprites so I'm going to select all of these and here on the right in our inspector we can change the settings for these Sprites so for one I'm going to change the pixels per unit to 96. what that means is for every 96 pixels it's going to be one unit in our world space in our game and so all of the the size of most of these images are for example 96 by 96 pixels so when we place them in our scene they'll take up exactly one unit this doesn't necessarily matter what this value is but it just kind of helps to keep things more normalized or consistent across across all of your assets so let's keep that at 96 for the filter mode I'm going to change this to point usually for Pixel Graphics you want points or no filtering otherwise the pixelated style kind of gets filtered it gets blurred um which we don't want for Pixel graphics and then from here all of these images are really small so we can change the max size to let's say 256. um let's get rid of compression these are all really tiny Sprites so they're not going to really take up much space anyways and that should be good for now the only thing we need to change from here is specifically the ground Sprite this one's a little bit different than the rest so I'm going to change the max size on this to 2048 I believe let me double check that I believe it's 2048 no so it's actually larger than 2048 so let's change this to 4096 and then this one we want to repeat instead of clamp because it's going to sort of cycle this this ground Sprite is going to kind of cycle as it we're going to animate it so it goes left to right and then it'll kind of cycle and continue repeating over and over and over again and change that to repeat and we're good there so that's it for our Sprites okay let's set up our scene with some of our game objects and first actually let's go to our scenes folder I'm just going to rename the scene here from sample scene to dino game feel free to call it whatever you'd like and let's go back to our Sprites and let's maybe start with our ground Sprite so we can just take this and drag it into the hierarchy on the left so create a new game object it adds a Sprite renderer component to that game object and it assigns that ground Sprite to it if we go to our game tab here we can preview what this looks like very hard to see so let's adjust some of our camera settings for uh first let's change the background color so let's set this to D6 d66 obviously feel free to customize this to your preference but that looks pretty good to me and we're also going to raise the camera position which will effectively lower everything else we could change the position of the ground object but I actually want to try to keep the y-axis value here at zero for most of our objects it'll just simplify some of our code so keep that at zero instead we'll change the camera position so I'm going to set this maybe to two and then something else I want to change here is the size if I make this larger it in a way effectively zooms out the camera and if I make it smaller in a in a way it zooms in so I'm just going to change this from the default five to four and I feel like that just looks a little bit better it makes the ground spread a little bit clearer to see but once again feel free to adjust that to your preference so I think that's good for our camera and our ground why don't we go ahead and add our dinosaur next so I'm going to take the idle Sprite I'm going to drag that into a hurricane we'll keep the Y value at zero but we can change the x-axis to position him on the left side of the screen so I'll do negative six that looks good I'm going to rename this to player I'm also going to tag this as player which will be important for some of our code later and I think that's it for now in terms of our scene the rest of these objects like our cactuses and our Birds those are going to be spawned dynamically using a script so we don't actually need to do anything else in our scene yet so this is a good starting point next let's get some of our player controls working so really in this game there's only one control for the player which is to jump so you can avoid the obstacles you don't actually move left or right or anything or I guess that's sort of one of the things with the side scrolling game a side scrolling game it's not the player that's actually moving the player actually stays still and it's the rest of the environment that moves to make it feel like you're scrolling to the side but for our code all we need to do is worry about moving up and down so first before we start writing that script let's go back to our player game object and let's add a character controller this will handle some of the physics and collision of our object we could also use rigid bodies but personally for this game I don't like using a rigid body because I feel like it's easier to achieve the physics I want using just a character controller a rigid body is intended to simulate real physics you know as closely to real life as possible and for a lot of games especially 2D games like this one physics aren't realistic at all and so sometimes it's actually harder to achieve the desired feel you want using something like a rigid body which is intended to stimulate realistic physics so I'm going to use a character controller which will still give us collisions and stuff and allow us to move the character um but it'll just be a little bit easier to to get the fuel we want so if I go to the scene view here and I turn on my gizmos I can see this green outline is representing the character controller or character controller is really just a custom collider that then has some built-in functions for allowing you to move the object and oh and one of the other reasons we are specifically using a character controller here is because there's a built-in property that allows us to to detect if our character is grounded or not a rigid body does not have that so it actually takes more code to use a rigid body because we have to write we have to do a custom raycasting to check if the character is grounded whereas for this it's just built in so it just simplifies it now we also need to set up our ground with a collider so we actually stand on the ground and don't fall through it let's go ahead and go to our our ground game object here and let's add a box Collider now this is a 2d game but we're actually going to use the 3D um version the the normal box collider which is usually intended for 3D games same thing with our character controllers this is actually generally intended for 3D games but uni doesn't have a built-in 2D character controller so for all of our collisions and things physics and stuff we're actually going to treat this more like a 3D game but it doesn't really change very much so we just got to make sure we're using the non-2d versions box collider here for our ground and let's go back to our scene view so once again this green outline if you have your gizmos turned on will show um the area of that um we do want to mark this no you want to actually keep this don't mark it as a trigger because we need to physically stand on this however we do want to adjust the position here we want to change this to be lowered so for example let's set it to negative one and that kind of matches up where with where the dinosaur is standing in the game the player does not stand on top of it here they actually stands sort of um below it there so we adjust the collider to sort of match we might need to make this a little bit more in fact we probably will because the player the character controller has this like skin with property which will kind of offset the Collision a little bit let's keep it at negative one for now and we'll just adjust it once we test it um another really minor thing that's sort of a tangent um I probably should have did this before but for these two objects we want to make sure the player is always rendered on top of everything else like our ground so if we go to our Sprite renderer we can change the order of here on the player to one so you can notice like here the ground is actually being rendered on top so you're seeing that line go through him so we just change the order of our player to one which will cause our player to always be rendered on top so yeah now it looks like he's sort of standing on the ground plane here even though it's just a 2d object all right so this looks good let's actually start writing a script for this and we can tweak things as we need to so I'm going to create a folder for scripts just to keep my project organized I'm going to right click create sharp script I'm going to call this player and we can click our player game object and we can drag this script onto it in the empty space at the bottom here let's go ahead and edit this [Music] all right [Music] so I usually like to get rid of the kind of boilerplate code that you need provides just to kind of start fresh here now to move our player we need to get a reference to that character controller component because that's what we use to actually move move the character so let's declare a variable of character controller and I'm just going to call this let's say a character and then in the awake function we can assign that reference awake is a function at Unity calls automatically when the script is initialized make sure you're capitalizing the a here all of these are case sensitive otherwise um D will not call this function for you we can assign this value by saying git component and then specifying the type of component we want to get which is character controller so this is going to search the same game objects that the script is on so our script is on this game object we're going to try to find a reference to another component on the same object which in this case is the character controller which we specified by the type here right from here um let's add a variable for our Direction so the direction that the player is moving this will be a vector three and we'll just call this direction [Music] let's add a function on enable so this is another built-in function Unity provides it will get called anytime this script is enabled so at some point we will disable the script when you get a game over to prevent you from being able to move or jump or anything and whenever we re-enable the player we want to reset the direction to zero so we'll say Direction equals Vector 3.0 now from here let's add our update function this is a function Unity calls every single frame your game is running this is typically where you will check for input now we always before we even check for input the input we will check for is whether you jump or not but no matter what whether you're jumping or not we need to apply gravity to the player so let's actually add a custom variable for gravity we could use unity's that there is a built-in gravity variable we could use um but in this case I actually want to just declare my own um because one the built-in variable is a vector three and we only really care about gravity in the y-axis and it's just cool it just makes it a little bit easier to customize this in theory if your game had you know multiple different things that are affected by gravity having a variable would allow you to customize the gravity for each individual object maybe you want that maybe you don't but in this case I'm just going to declare my own gravity variable I'll set it to be 9.81 which is kind of the gravity of real life well actually so this is another reason why I don't want to use origin body is because once again rigid bodies are going to try to simulate realistic physics as much as possible I actually want to increase the gravity a lot more to to get our to just get get it to fuel the right way the value this gravity value here I just feel like the the dinosaur is up in the air too long and almost feels like they are floating too much so I'm actually going to double this I'm just going to times this by two and this by the way is just a default value this will show up in the editor and we can customize this however we want so this is just serving as a default but if you were to change it in the editor that what the value that shows up in the editor is the actual value it'll take all right so in our direction we're going to say plus equal factor three dot down we want to apply gravity going downwards times our gravity scalar here and then gravity needs to be gravity needs to be applied over time so we're going to say time dot Delta time that's how much time has elapsed since the last frame now let's check if the character is grounded and only if they are grounded will we check um for uh their jump input so this is where this is really easy to do because our character controller has a is grounded property just built into it which is really convenient so if the character is grounded if the character is grounded we actually don't need to apply the gravity so we can set the direction to just be down um well so we we still want to apply a force that pushes the player down but the problem with this line of code is this gravity builds up over time it keeps building up and building up and building up and building up which we don't want when the player is actually on the ground we can just apply a constant force of down but we don't want that value to continue to build up over time so we'll kind of reset it to just be down and then now finally we can check for input so we can say if input dot get button down or actually maybe just get button the difference here is get button we'll check every single frame that you're holding down the button whereas get button down will only check for the single frame it was first pressed it down so if we use get button down you're gonna have to re-press let's say space bar every time you know you have to press space over and over again whereas with get button you can hold it down which from my testing feels a little bit better it doesn't really matter but I kind of preferred it allowing the user to hold it down if they want to so if input your button jump and so this is where Unity has built-in inputs so if we go to our project settings if you go to edit I already have it on my um on my menu bar but if you go to edit uh project settings there is built-in inputs already so if you go to the input manager Unity has a number of inputs already set up for you including one called jump which is mapped to the space bar so you can of course remap those and change these settings um but whatever you specify should be here you could also check for individual keys like you could say get key down and then you can specify like you know spacebar or something like that um but in this case I'll just use the axis value here jump and if we do jump then I'm going to set our direction to be up times some jump Force so let's add a variable for jump Force and from some of the values I've tested I found a value of 8 works pretty well but once again you can tweak this this is just a default so in the editor you'll be able to customize this to your preference count four so Vector 3.0 times our jump Force and finally we just need to actually apply this direction to the character so we're going to say character dot move we're going to move them in that direction and we also want to move the character over time so once the direction times time that Delta time and that is it for our player script that's our entire player script let's go ahead and test this you can see once again our player script we have those two variables showing up so we can tweak these if we want if we don't like these values we can at least customize them let's go ahead and run our game and see how this feels so I can press spacebar and I can jump here we go I can hold it down to keep jumping if I want but this looks and feels good now the contact point on the ground I feel like needs to be a little bit lower so I am actually am going to decrease this even further so I'm going to say negative 1.1 Maybe let's Replay that yeah that feels a little bit better it's positioned more where I want so there you go that looks good so next I want to start animating some of our objects including our grounds so it actually looks like we're moving and we get that side scrolling effect but also I want the speed of the game to increase over time as you get further and further it's going to get faster and faster so we need some kind of variable that we can use to change our animation speeds um dynamically and so I'm going to create a game manager script that will manage some of our game State including sort of our Global game speed which we're going to then use across several different objects in our game to make them all animate faster and faster as the game gets faster and faster let's go ahead and create a new script for game manager and let's also create a new object in our hierarchy so we can right click and let's just create an empty object I'm going to reset the position although it doesn't really matter I'm going to call this game manager I'm going to drag this to the top once again it doesn't really matter but just just kind of like it being at the top there and I'm going to add our script to this let's go ahead and edit this so our game manager here will manage some of our kind of over overall game State you know what's your score you know what's the game speed it'll do some of our UI and things like that once we get to that um so this is a script that we need to access some of that game States through a lot of our other code so we're gonna turn this into a very very simplified Singleton which is a design pattern commonly used in games especially for something like a game manager a lot of developers might overuse Singletons and use them in places where they really shouldn't but this is such a simple game that I think turning this into a very basic Singleton will will be will suffice and just simplify a number of things so um now this won't be like a true Singleton but just kind of show you how we can do a very very basic version of it so the idea of a Singleton is that you can access it from anywhere and there's only a single instance of this class which makes sense there doesn't need to ever be more than one game manager so we need to declare a static variable of the same type of our class here and I'm going to call this instance and this is going to have a public getter but a private setter so it's a public variable with a getter but then it has a private Setter so only this class can manage the single instance but anyone can access this from elsewhere in the awake function we can assign this instance but we only want to assign the instance if it doesn't already exist so if we check if instance equals null then we'll go ahead and assign this instance to be this this just referring to this instance of the game manager Elsa if there already is an instance and for whatever reason another one is being created we're gonna destroy that one immediately destroy immediate game object so this is where that single instance comes in we don't ever want there to be more than one so if for whatever reason a second one is being created we will destroy it immediately and then on Destroy is another built-in Unity function we're going to check if this Global instance is this then we'll unassign it instance equals null so this is a very very simplified version of a Singleton but for our purposes this totally suffices this will allow us to access this from anywhere else so for example just pick some random code here I could say game manager dot instance and then access you know anything I need to all right so for now I just want to focus on um creating the properties we need to be able to animate our objects so I'm going to create a variable for our game speed and I'm gonna also make this a have a public getter with a private setter and I'm also going to declare a separate variable called initial game speed and maybe this defaults to five so this will be the game speed when the game first starts but this value here will be the actual current game speed which will increase over time and along those lines we can also specify how fast the game speed increases so we can have a variable for let's say game speed increase and maybe this increases by 0.1 um per second all right so from here let's get just a little bit of structure for kind of starting a new game and then we'll revisit our game manager um further in the tutorial once we start doing the rest of our game State and game over and things like that but let's implement the start function which Unity is a built-in Unity function it will get called the very first frame this script is running and from here we can um actually at First let's create a new function called new game and in our start function we'll say new game all right so in new game we can set our game speed to be equal to the initial game speed and then in our update function we will increase the game speed say plus equals that game speed increase times Delta time so that's all we'll do for now there's definitely going to be a lot more we're going to do in this in this script but for now we're setting our game speed to be some initial value and then that game speed will increase over time by however much we specify in this variable so just to show you that real quick let's play our game and I'm going to switch to Let's unmaximize this I'm going to switch to the debug mode here and you can see our current game speed so it's increasing as the game continues on and so five six is still going to be quite slow but then you know if you if it's if you haven't died and it's been a minute it's going to be a lot faster so it's gonna get harder and harder and harder which I think makes the gameplay more interesting okay so now that we have our game speed set up we can start animating some of our objects so let's start with our ground because that's going to create that side scrolling effect that's really important let's go ahead and create a new script for our ground I want to call this ground and just like everything else I will assign uh this script to our object let me switch back to the non-debug mode to sign our ground script there now let's go ahead and open this up now to animate our ground what we need to do is essentially we don't actually want to change the position because at some point it ends so what we want to do is that we actually want to change the tiling on the texture on the sort of sprite texture because if you remember earlier we changed our ground Sprite to be repeatable so if we sort of tile it it'll tile infinitely without us even having to change the position so that's what I changed the wrong thing let's set this back to zero now the problem is the Sprite render does not allow us to change the texture tiling values um like on the material here you'll see these tiling values but we can't actually change these unfortunately so we don't want to use a Sprite renderer for this object instead we're going to change this to use a mesh renderer which is once again technically a more of a 3D object but we can totally use it for this just the same so I'm actually going to remove the Sprite render instead I'm going to add a mesh renderer actually we need first let's add a mesh filter and then a mesh renderer I'm going to bring these both to the top although it doesn't matter the order here but just like them to be there the mesh filter defines the mesh that's being rendered so the it's sort of the raw data the raw geometry that is being rendered we're just gonna render a quad so there's you know 3D objects like a cube sphere but we just want a quad which is just you know like 2D you know just a 2d thing so here we get this little square uh that magenta color because there's no material sign that's just kind of the default like Shader color I suppose um all right so that looks good we do need to create a new material to assign to this so let's go ahead and create a folder for materials and inside this folder we can create a material so let's do material I'm going to call this our ground and we're going to change the Shader to a on lit transparent our ground spread is actually transparent so that's why we're using transparent otherwise we could just use the um you know unlit texture but in this case it has some transparency to it so we want to make sure we keep that we can drag our ground Sprite into there and let's reassign this to our or now that we have our material we can drag this material just into the empty space here and that will add it or now we can actually see that now of course the scale of this is not right at all so we want to change this we actually want to change the scale to bring it back to the size it should be here so a with my Sprite a scale and the x-axis of 25 is what we want um and I believe the reason for that let me do some calculation here so if our Sprite is 96 pixels per unit times 25 that's 2400 pixels which if we look at the size of our Sprite is 2400 pixels so in other words what I did is I take the width of it 2400 and I divide that by the pixels per unit I set so that's 96 and that gives us our scale of 25. and then in the y-axis it's 96 so that's just one 96 divided by 96 is 1. so if you're using a custom spread that's how you could calculate these values to get the scale back to how it should be now with that change the collider also needs to get reset because you can see it's way bigger than it should be I guess it doesn't really matter but I'm going to reset this as well um I'll just literally reset it and that's going to automatically kind of re-reconform it to the object and I guess this can be one but the Y we can reposition down again this will just be the same negative 1.1 and that looks good all right so we reset up our ground sort of technically as a 3D object set the scale to 25 but now that we have this material we can tile this or really we're going to offset it and you can see as I change the offset it's sort of animating the ground and this goes on infinitely this will never end all right this value can increase forever and our ground will continue to tile so that's why where we went through that entire process so now in our actual ground script all we need to do is add you know five lines of code or so to change that offset property let's get rid of some of the spoilerplate I'm gonna add or get a reference to our mesh renderer which is one of those components we added just like we did in our player script oh I'll assign this using git component in our awake function then in our update function we can update this so mesh renderer.material dot main texture offset and we're going to increase this by some amount so we want to animate it to the right well it actually might seem like it should be animated to the left but if you take a look we look at our ground here if I change this offset to be to the right it actually animates to the left so we actually want to increase this number when I'm um change that number to the right um to animate it as if it's moving to the left so we're going to save vector2. right times some speed variable which we haven't declared yet times time dot Delta time now for the speed variable this is where we will use our game speed here but it's not just directly the game speed we actually want to take that game speed and divide that by the scale of the object dollar 25 here so we can say game speed or game manager.instance Dot Game Speed game speed divided by whatever our scale is in the x-axis so transform.localscale.x cool so that's the speed at which our ground will actually animate let's go ahead and test this out [Music] so there is our ground being animated so now it actually feels like the character is actually moving and once again this is going to animate faster and faster as our game speed increases so why don't I bump up our game speed increase even more let's just keep making this faster yeah so now it's getting faster and faster so that's why we had to go through this entire process to do all this game speed stuff because it allows everything in our game to be animated based on that game speed we didn't have to do that we could just have our entire game be the same speed the entire time but that's kind of boring and I feel like it doesn't make the gameplay very interesting so having the speed get faster and faster just makes it more fun in my opinion so there's a little bit of a process to get that working but now that that's all set up it's easy and for some of our other objects it'll be even easier all right next let's animate our dinosaur this will be animated differently because we really just need to swap out the Sprites over time so we have a few different Sprites here we have the idle one and then the Run we've run one and run two so we just need to cycle between those two run Sprites to get the dinosaur to be animated that's also what we'll do for our bird for example so we can write one script that we can reuse for both our dinosaur and our bird once we eventually set that up so let's create a new C sharp script I'm just going to call this animated Sprite let's open this up I'm going to delete the boilerplate here now we need to provide an array of Sprites that we're going to cycle between so let's declare an array of Sprites brackets here indicate that this should be an array we also need to get a reference to the Sprite render so we can change the current Sprite so let's get Sprite render here I'll just call the Sprite renderer [Music] um and we can assign this in our awake function just like we have for other things spread render equals get component Sprite render now we also need to keep track of what frame or what Sprite we're currently showing which what index in the array so I'm going to call this Frame [Music] it's going to be an integer as the index of the array all right and finally we need to actually uh animate this so when this script is enabled so on enable we're going to invoke a function and this will be a to create a function called animate and we're going to invoke this function now when you invoke you have to invoke by the name of the method so we'll say name of animate and then we need to specify a time here um our time should be well so actually let me revisit that line of code let's start with our animate function then it'll it'll make a little bit more sense whenever we animate ours right we need to increase the current frame we need to check if the current frame is um past our array like if we're beyond the length of array then we need to cycle back to the beginning so we can say if frame is greater than or equal to spreads.length um then we start back again at the first one zero things start at zero not one and then from here as long as our frame is you know so well let's just start by doing this right render dot Sprite equals Sprites and then whatever frame we're on now as a safety check we can make sure that this index here is not is is inbounds to our array this will prevent you from hitting an index out of bounds error that I've had a lot of people on Discord ask about and the only reason that you could possibly get that error error in the scenario is if you forget to add Sprites to your array so this is empty then even with an index of zero it's always going to still be out of bounds so either don't forget to assign Sprites to this or just in case [Music] um honestly just because I get tired of people asking me about it let's add a safety check to make sure that our frame is greater than or equal to zero and less than our squared to that length this will guarantee we will never get an index out of balance error now sometimes getting an error is actually helpful because it lets you know that you made a mistake it will let you know hey you forgot to you know add Sprites to your array therefore it's you know you got an error for that and that's actually sometimes good um as a developer um to be informed of those issues now you don't want those errors to um cause problems for the actual users because that will actually crash their game so um so anyways that's good that's all we do for our animate function so we're just basically cycling this index through our array and updating the Sprite accordingly now this we need to recall this over and over and over again so once anime gets called we're going to invoke animate again every you know let's say every one second but we don't want to do every one second we want to do based on the speed of our game so just like we did for a ground we want to use this game speed variable so we're going to say one second divided by whatever our game speed is so as our game speed increases is going to shorten the amount of time between animation Cycles which was going to make our animation faster it's going to make it look like the dinosaur is moving faster and faster as our game speed increases so if we don't do this if we don't factor in our game speed well then it's just going to make it um it's just going to make it feel weird because the the how quickly the dinosaur is animating is not going to match up with how quickly the ground is moving so we want to factor this variable into everything we use that way it's all synced up and looks you know looks and feels the right way now let's revisit this line of code here so same thing we want to kick off our animation by invoking this but we want this to happen sort of right away um I could just so I could literally just call the function problem with this is have to has to do with unity's life cycle our game speed doesn't get assigned until new game is called which is called and start start will always be called after on enable so that means when we and so this would get called first it'll call animate which will then kick off our animation that's fine but then it's going to tell it to animate again you know as let's say a second from now but our game speed is zero so you're gonna get a divide by zero error which is no good that's going to cause a problem um so we want to actually invoke our animate function after some amount of time that way this can get executed first foreign a value of zero it will get called the next frame [Music] it won't get caught immediately it'll get called the very next frame which gives us enough time to get called and then for our game speed to get set so this is kind of a trick in a way it's almost kind of like a hack but it does the job you could just make this like okay don't start animating it for like a second but that's kind of arbitrary and then your character is just sitting there not moving for a second which we don't want you could also just make this some really small number but yeah a value of zero just make sure it doesn't start until the next frame which is basically what we want we could do this on start as well but the problem is we're going to be enabling and disabling our player um you know when you get a game over and when you restart so start will only ever get called one time for the entire um life cycle of that object so we we need to do this on enable that way research animating whenever whenever the dinosaur is re-enabled after a game over or when you start playing again so so anyways that's that this script will be able to reuse for multiple objects for our birds for dinosaur if you had any other animated objects we can go ahead and drag this onto our player let's make sure we actually assign the Sprites to this [Music] let's add our Dino Run one and Dyno run two and let's play this all right so there we go so now he's you know he's doing his little little run and once again if we increase our game speed um this is going to get faster and faster as well to match how quickly the round is moving so perfect real quick before we move on we do need to do one more thing in our animated spray which is when our Sprite is or when this script is disabled we need to cancel the animation so we can add on disable and all we need to say is cancel invoke so that will make sure that it stops animating when the script is disabled which once again when we in our game manager when you get a game over we're going to disable everything and then it'll get re-enabled once you start playing again so that's an important function otherwise the animation will always continue [Music] so now let's start working on spawning our obstacles our our birds and our cactuses but first we need to create prefabs for all of these so we can we can spawn them dynamically prefab is a pre-fabricated game object it's essentially a game object that you've turned into an asset that you can then reuse throughout your entire project instead of just the single scene that you created it in so let's start with our bird for example let's drag our bird spread into our hierarchy creates a new game object I'm going to rename this to bird oops bird let's reset the transform mine's already reset but make sure you reset these transforms back to their just starting values of zero or scale is one we do want to add a um a box collider to this so we can detect collision between the bird and the dinosaur so just a regular box collider not the 2D one because once again we're technically using sort of 3D components for some of these things so a character controller which is what we need to detect Collision against does not detect Collision against the 2D the 2D um the 2D versions of these because it's a different system entirely so normal box collider we do want to mark it as a trigger we don't actually need to physically cloud with these things we just need to detect when you've touched the object we can also add our animated Sprite script that we just finished making just for our bird here since the bird is animated so we can add in our two Sprites there now in our code later we need to detect Which object or what type of object you've collided with um is the player could collide with other things like the ground we only want to detect when they've collided with an obstacle so what we can do is we can set a tag on these objects to know which kind of object you've collided with let's add a new one call this obstacle or call it whatever you'd like and let's go back to Robert and assign that tag and then for the same reason we did for our player I want to make sure I set the order and layer here to be increased so it draws on top of the ground not being past it which wouldn't make sense so that's it for now for our bird in this case um we can now turn this into a prefab let's create a folder called prefabs and all I need to do is drag this into our folder and so now it's a prefab we can reuse this asset across our entire project and I can actually delete it from our scene although actually I want to update a couple things but let me show you how we could update our prefabs um later so I've deleted it from the scene but I still have the acid here so I'm going to just reopen this up and it'll kind of create um sort of an instant scene that we can edit this in I actually want to adjust the collider here you see there's a lot of empty space at the top and that's because of how it animates I've sort of made the Sprite a little bit bigger than it needs to be that way when you switch between the two Sprites it stays lined up accordingly um and so it's basically a 96 by 96 pixel image which keeps the unit unit exactly at one but our Sprite is a little bit larger than it needs to be so we can potentially adjust that to be a little bit more accurate if we change our Sprite size to be 0.833 repeating and then we also offset that by negative 0.083 repeating it's going to line up the very top of so in our bird too the right top pixels to the top of our collider and for bird one the very bottom of our um of the pixel to the bottom of the clatter so you don't need to do this it's not required by any means but it just makes the collider a little bit more precise based on the Sprites for our bird here all right so that's our bird we basically need to repeat the same process for all of our cactuses as well all right so for our cactuses let's kind of do the same thing um let's start with each of these and let's add our box collider mark it as a trigger I marked our bird as a trigger right yeah our birds are trigger too okay just had to double check in case I forgot it's really important so marked as a trigger let's tag it as an obstacle and we don't need to add any other components to this um because it's not animated or anything let's set the order in layer to one so it goes on top of the ground and that looks good maybe what I should do is um just set our gr oh no we can't because this is a different kind never mind so yeah set the order to one that looks good the collider lines up perfectly in this case we don't need to do anything else so this one I think we can just drag into our prefabs folder and that one's good to go let's do our single Cactus box glider trigger obstacle drag it into our folder good to go all right Cactus large triple oh I forgot to set the um border order one all right this one order one box glider trigger obstacle good to go it lines up drag this into our folder um okay now for these ones these ones you'll see once again that there's a lot empty space at the top that's to the reason for this is so when you drag these into the project they will all be lined up um they'll all be lined up the same at the same spot on the ground regardless of their height but that means when we add our box collider it's gonna you know there's gonna be all this extra space again so we can adjust these as well just like we did for our bird um so let me check what these values should be so in this case 7291667 it doesn't have to be perfect but yeah negative 0.1354167 lines it up perfectly this was based on some math like these aren't just random values there's math I did some math to figure out what the what the exact size of the Box glider should be based on how many pixels this takes up I honestly don't remember how I did that math but once again it doesn't really matter feel free to Just Adjust this until it lines up close enough it doesn't it doesn't really matter okay so we have our box ladder trigger size obstacle order layer one that one's good to go let's drag that in do the single one order layer 1 box collider trigger obstacle now once you've figured out what these values should be they should all be the same for these um these are all the exact same height so there we go Gordon layer 1 box Tire trigger obstacle good drag that in now this is a little bit tedious but sometimes that's just part of game development oops I didn't mean to do that um all right but last one I think this is the last one five Collider trigger order one obstacle and then the colliders what should these values be fats and that there we go lines up good to go let's drag this in all right is that all we have are six different Cactus variants we've got small ones and Tall ones and then we've got single double triple single double triple there we go those are all of our prefabs they're all obstacles they're all order layer one they're all triggers I think our obstacle our prefabs are all set up and good to go now all right now that we have our prefabs created let's start writing our spawner script create a new script called spawner let's go ahead and open this up [Music] delete the boilerplate here so far our spawning script we need to provide which objects we want to spawn so we need to get a reference to those prefabs um now in our case we're going to use the single smarter script to spawn all of our different objects so we're going to provide an array of prefabs that we can spawn but I also want to provide a way to give them a spawn chance so for each one of the different objects we can set how frequently that object will spawn and that's important because we want some of the easier objects to spawn more frequently so for example we'll get like the single trees will spawn more commonly than the double the double will spawn more commonly than the triple that way it kind of balances out the difficulty of the game in some ways and obviously you can tweak those values and determine how much you want them to spawn but in order to do that we need to be able to associate a prefab with a spawn chance as well so let's create a custom data structure so we can kind of identify one of those I'm going to declare a public struct here I want to call this a spawnable object and inside here let's get a reference to a game object which is going to be the prefab that we instantiate and let's also declare a spawn chance um float here now this spawn trench needs to be a value between zero and one and we can actually do that in unity we can add a range attribute to our property or to our variable here and set that between zero and one it's actually going to turn this into a slider in the editor which you'll see in a moment now we can actually declare an array of these spawnable objects now the problem is these aren't going to show up yet and in our editor and I'll explain why although we actually need to create a spawner game object so it's called a spawner I'm going to reset the position let's drag our script onto it and let's position this on the towards the right where it will be off screen let's say it has a position of Aid so it's going to be Beyond the Edge of our camera so the objects will spawn off screen and then they'll get animated to be to move on screen but you see here in our smart script that variable we added isn't showing up and that's because it doesn't know how to serialize this data into something the editor can read and understand all we need to do is add an attribute to our struct system.serializable and now it'll show up in our editor foreign seven or eight different objects um there's seven different ones so for each of these we can assign the prefab so let's start with our Cactus small then we'll do our Cactus well so let's think about uh the order here will actually be important so in our code once we finish writing the rest of our code it's going to Loop through this array so we're gonna we're gonna pick a random number between zero and one it's going to Loop through the array and if that random number is less than the spawn chance it'll spawn that one and if it's not then it's going to move on to the next one and it's going to check that one that'll move on to the next one move on to the next one Etc so the order here is actually important really we just want to order these based on which is most likely to spawn and then at the bottom would be the least least likely to spawn so the actually we want the small Cactus to be kind of the most common one then maybe followed by the large single so small single and large single then we can do doubles we start with a small double then we'll do a large double then we can do the triples the small triple followed by the large triple and then the bird will be last now obviously you can customize this so feel free to to adjust this to your preference but now let's specify these spawn chances ideally you would want these to add up to one it doesn't have to necessarily in fact if it doesn't add up to one then there's a chance that it'll spawn nothing which is actually completely valid um in some ways it's helpful to the player because it will add if it spawns nothing then there's going to be a bigger gap between the different objects which maybe gives the player room to to breathe a little bit so maybe that's maybe we don't perfectly add up all these numbers to one so some of the values I've played around with are just um 0.2 for this that's 20 chance of spawning that and then I just decrease this by two percent every time so 0.18 um 0.16 .14 2012 zone is 10 percent and then this one I'll do five percent so there's only five percent chance that a bird will spawn um I think all these add up to around 95 or something like that somewhere in the 90s um so there's also a small chance that nothing will spawn as well so once again feel free to customize this to your preferences but you know um it's going to pick a random number between zero and one it's that I'm going to Loop through this in order if that random number is less than this then it will spawn it otherwise it will then check the next one and then check the next one and so on and then every time it goes to the next one it's going to decrease that random number so so it'll actually eventually hit the threshold of one of them um all right so back to our spawner script here um let's add some variables to indicate how often we want an object to spawn so we can add maybe and maybe this will be random as well so maybe we can um specify a range Like A Min and a max range so you say maybe the Min spawn rate is one second and then the max spawn rate is two seconds so that means it's going to spawn an object randomly between one and two seconds um and it'll be different every time if you don't want it to be random you just would in the editor just set these to be the same value yeah so if you want it to be a consonant it's always going to spawn a new object every one second then you can just set them really the same all right so from here uh we actually want to start spawning our objects so on enable when our when our script is enabled we will um invoke our spawn function which we don't have yet so let's create that I have a spawn here we will invoke this gotta specify the name there and then we need to provide um the time so this will be a random number between these two values so we can say random oops random dot range between the Min spawn rate and the max spawn right now on disable we want to cancel our invokes so it stops spawning things you can just say cancel invoke and then finally in our actual spawn function here like I said before we're going to pick a random number between 0 and 1. so let's say the spawn chance here is going to be random.value this this is just a built-in property unit provides to get a random float between 0 and 1. and then like I said we're going to Loop through each of our objects so for each um for each of our object and objects or actually we can't use that because it's a keyword so we'll just say obj for each obj and objects if the spawn chance is less than the object spawn chance then we will go ahead and spawn that so to spawn it we will say instantiate obj dot oops instantiate obj dot prefab that creates a copy of the prefab let's store this into um a variable we'll call it obstacle Maybe uh and then we're going to set the position of our obstacle to be offset by wherever the spawner is positioned we're offsetting the position based on the spawner's position so in other words it's essentially going to spawn the objects wherever you position the Spawner in your scene now I don't want to just directly assign the position um to be equal to the uh I don't want to do this I don't I don't want to just say equals transformative position and the reason for that is because then it allows us to maybe customize um these the their initial sort of position um through the prefab specifically for example for our bird if we do spawn a bird the position is zero then it gets offset by wherever our spawner is so it would end up getting offset to there so that's where it's going to spawn maybe for the bird we wanted to be up in the air a little bit right so we we can do is we can change the Y value here to be you know maybe 0.5 maybe 0.25 something like that and now it's going to spawn this in our scene at 0.5 it's going to offset it by our spawn position which is e so now it spawns at eight 0.5 so that just allows us to kind of control um control this better so there you could actually have different duplicates like we could have multiple birds and maybe one bird spawns at one height and another bird spawns at another height you could do that if you wanted to I'm just gonna kind of stick with the simplified approach but if you do do that just make sure you add another object here to your array and maybe tweak some of the spawn chances accordingly all right so back to our spawner script um let's finish this up um once we once it matches the spawn transfer once it succeeds in in spawning that object we don't want to spawn another one so we want to break out of this Loop the break here we'll cancel this Loop or it'll break out of it um if it doesn't meet the small chance then we need to decrease this by however much this is here obj dot small chance minus equals obj dot spawn chance so the reason for that is um let's say we pick a random number and let's say the random number is 0.5 well 0.5 is not less than 0.2 so it will then move on to the next one well 0.5 is still not less than 0.18 so it'll move on the next one 0.5 is still not less than that right so it's never going to be if it's not less than the first one it's not going to be less than than any of the others what we want to do is say okay well first it's 0.5 it didn't hit that threshold so we subtract 0.2 okay does 0.3 hit this threshold nope it doesn't it doesn't hit that threshold so we subtract 0.818 now it's 0.12 okay yeah that does indeed um hit this threshold so this is less than the threshold so it will end up spawning this third one here let's say the random value is one and we go through the same Loop so the first one tries you know it's not less than 0.2 so we subtract that next one nope it's not less than 0.18 so we subtract that the last one it's not less than 0.16 we subtract the swan's not less than 0.14 it's not less than 0.12 it's not less than 0.1 so finally it's 0.1 it's not less than 0.5 either and so that's where at this point it didn't match any of them so it would spawn nothing so yeah based on the math there with these numbers there's a five percent chance it'll spawn nothing which once again is perfectly valid and actually like like the fact that sometimes it doesn't spawn something it kind of breaks up breaks up how much space there is between objects all right so I think there's just one more line of code we need to add to our script here which is once it spawns um once it spawns an object we need to have it spawn another object at another random interval so we're going to invoke our spawn function again this time picking a new random value between our Min and our Max great all right let's go ahead and test this out [Music] now we haven't animated these objects to move so you can see they're spawning they're showing up here in my editor but they're not animated to actually move you know to the side so that's our next step let's go ahead and create our script to animate the actual obstacles from right to left so let's create a C sharp script here called obstacle and we need to add the script to all of those prefabs we had created so I'm going to select all of these I'm going to go to our scripts folder here I'm going to drag that onto it let's go ahead and edit this all right so for our obstacle we just need to um animate it or change its position over time to move to the left and then eventually once it's off the screen once it moves past the screen we can just get rid of it at that point we don't need it anymore so um let's add our update function here and in update we're going to change its position transform that position plus equals vector3. left times our game speed so once again if our game speeds up the ground moves faster we also want these objects objects to move or these obstacles to move faster to match the speed of everything else so we're going to say it's going to move to the left times our game speed or not game object game speed times time dot Delta time because this animation happens over time then we need a check to see if it's past the edge of the screen and if it is then we can just destroy it now the edge of the screen you know might change um based on screen size and things things like that so we don't know like the exact World position of where that will be so something we can do is calculate it let's create a variable to store what that value will be so I'm going to create a variable called Left Edge and in our start function we'll calculate what that should be so left Edge will equal we need to make a conversion from screen space to World space and you do this by accessing your the camera and calling a function on it to access our camera we can say camera dot main this will um this will return a reference to the camera that's tagged main camera so make sure your camera is tagged main camera it should already be tagged up by default but just in case make sure it is tagged up all right so camera dot Main and then there's a function screen uh screen to World point so this is converting screen space to World space now the left edge of our screen in screen space is zero and the right Edge would be you know whatever the resolution of your screen is so maybe the right Edge is let's say 1920 the left Edge is zero um so we can actually just pass Vector 3.0 here that's good to go um so that converts um that is converting our uh our screen space coordinate to World space and we only care about the x-axis so I say dot X and that's really it although we do want to offset this a little bit more because um if I take let me just take one of these objects here so let's say uh you know the left Edge is here well as soon as this crosses boom it's crossed it's going to get destroyed but well it's not technically off the screen yet I need to wait for it to be fully off the screen so what we can do what we can do is just offset that position by one unit so we can just subtract an additional unit on top of that to make sure it gives enough space for the object to fully pass um the screen before it gets destroyed maybe you can even do two units in case some of your objects might be a little bit larger in fact I think yeah like for example this one is larger than one unit so we we need to make sure it's large enough that any object will go fully past the screen before it gets destroyed it's kind of arbitrary now we could do some more math to make that more Dynamic but it's really not necessary so um but now here we can just check if our transform position dot X is less than less than the left Edge then we destroy the game under I'll just get destroyed all right and this is really just so like you know once an object past the edges of the screen like there's no point of it existing anymore it's just gonna continue to consume resources that it doesn't need to so we can just destroy it um if you want you can take a more advanced approach to this which is to use object pooling so instead of destroying and reinstantiating objects you reuse them you recycle them over and over again we in my opinion really don't need to do that this is such a simple game that I'm not at all concerned about performance but maybe if you're building for mobile you know maybe you might want to do something like that in which case I would encourage you to to research that and um uh look up how you can Implement object pooling in your game but anyways I think that's it for our objects let's go ahead and test this out they should be animated now um moving the left and then we should see them disappear when they go off the screen so there's Cactus yeah so this looks great now of course there's no Collision yet on our objects because we've marked these as there are colliders but we've marked them as triggers but doesn't physically stop the dinosaur from um from uh hitting them um but yeah this is working you can see they're kind of getting deleted from the scene to once they pass the screen so once they kind of get far enough past the screen they get destroyed and so this is what a side scroller really is the the dinosaurs technically just staying still and the rest of these objects are what are moving it's the environment that actually moves around you to make it feel like the player is actually moving and our ground in this case is technically stationary as well you can see the Transformer is not changing at all because we use the technique to just um tile it over and over and over again so it makes it feel like it's infinite when it's really not and our game's getting faster and faster now you'll notice here the the obstacles on the ground move that the exact same Pace or rate that the ground is moving just as an example let's say I didn't um I didn't factor in the game time here let's see what this looks like now well one they're gonna be really slow which is fine but you'll notice that the like they just don't it just doesn't line up the ground and these just don't move at the same rate so it just looks really weird [Music] um that's why that's really important that we Factor this game speed into all of our objects okay let's go ahead and detect collision between our obstacles and the player so then we can trigger a game over so let's actually open up our player scripts this is where we're going to actually detect Collision we can add a function called on trigger enter and then this takes in a other collider that we have collided with so once again make sure you have tagged or marked all of your colliders on your obstacles as triggers as triggers should be checked on and make sure they're all tagged as obstacle as well it's going to become both important in this code on trigger enter we need to verify that the other thing we're colliding with is an obstacle so we can say if other dot compare tag to obstacle then we know that it is that type of object this needs to match exactly to what the string is in the tag they need to be you know exactly the same case sensitive make sure there's no Extra Spaces or anything and if this is the case then we can trigger a game over which the game over will handle in our game manager let's go ahead and go to our game manager um let's add a game over function I'm marking this as public because we need to be able to call it from our other script let's say game over now on game over what should we do let's set our game speed to zero let's disable our game manager that way it doesn't increase the game speed when when your script is enabled the update will not get called so we don't want our game speed to start increasing again um what else we need to deactivate our player and our spawner so to do that we need to get references to those two objects so let's go ahead and create some variables for our player and for our spawner and in our start function at the top of our start function we want to say player equals find objective type layer and spawner equals find object of type spawner and then in our game over we can say player.gameobject set active to false and same thing for this spawner spawner.gameobjects that active false we should also um oh yeah no actually that's good uh what else we're gonna do some other stuff like we'll show the UI we'll update high scores but we're gonna handle those separately so for now I think this is good um we should maybe build up the rest of our new game as well so do these two kind of uh are almost opposites of one another so here we reset our game speed we re-enable the script and then instead of setting these to not be active we want to set them to be true active true uh also whenever you start a new game we should clean up all of the objects in the scene all the obstacles need to get removed so you start fresh so to do that we can say obstacle let's declare an array of obstacles here and we say find objects of type plural so make sure this is objects plural not singular [Music] and objects to type for each obstacle in our array we will destroy it destroy obstacle.game object make sure you don't just say destroy obstacle that will only remove the obstacle script from the game object but it won't destroy the rest of the game object we need to destroy the entire thing which includes the Sprite renderer the collider the script so long we need to destroy the entire thing cool so let's go that's uh clearing all the existing obstacles so you start fresh we kind of re-trigger our game state to be at the beginning we reactivate our objects I think that's it for now um now we just need to call this from our playership so if we collide with an obstacle we're going to say game manager instance game over Let's test this out we won't really be able to test the new game yet um until we add some UI but we'll do that next but I should I can jump over these to avoid getting hits but if I don't jump over them then I do get hit and the player goes away everything freezes and stops and we're good and once then we'll display some UI and once you click the restart button it'll restart again okay let's create the UI for our game I do want to import a fonts that we'll use that will kind of match the pixelated style here so um if you downloaded the project earlier to get all the Sprites it'll also have a font you can use you can of course use your own font you can find a font somewhere online use that but there will be a font included specifically you want this ttf file so pix public pixels the name of the font Dot gtf um so I already should have that set up or not set up download it from pre from earlier so let me just drag this in uh publicpixel.tgf I'm gonna put this into a fonts folder move that in there all right so for our UI we need to create a canvas in our hierarchy so right click UI canvas [Music] and then in this we're going to right click our canvas and we're going to create some text elements so I'm going to use text now uh in newer versions of unity we typically use text mesh Pro which is a it's an extra package that is installed in unity if you open the text or open your package menu you should be able to see that here I believe it comes installed by default and newer versions of unity um so that's what I would recommend you can also use the Legacy components too which and actually in every one of my other tutorials that's what I've used but now that I'm using a newer version of unity this is more of the default so anyways here's a text component whichever one if this is the first time using Tech smash Pro it might need you to import some stuff so let's go ahead and do that [Music] yeah this will create a new folder in your project and close this now and we need to turn this font into a text mesh Pro asset as well so I think if you right click your font go to create um and then in here somewhere there's so many options oh yeah Tech smash Pro and then do font asset this will convert it to an asset that we can use on our text component [Music] so on this component let's drag in our asset there that uses the new font I'm going to Center this um I'm going to middle align it I'm going to disable word wrapping um let me check my other project to kind of get some of the settings I want here I'm going to increase the font size and once again none of this is like has to be this way feel free to customize this to your preference um what else I'm gonna make this always capitalized so that there's always cap uppercase everything let's set this to be game over I'm gonna change the color to be sort of a grayer color it's the same color as the dinosaur so you can use the Color Picker and just pick the dinosaurs color or set it to be whatever you want I'm also going to increase the um character spacing here I'm going to make it the same as the font size so this is trying to match the original game as closely as possible it's not exact but that's good enough foreign so this is our game over attack so I'm going to rename this to game over then we also need a button um like a retry button so I'm going to right click our canvas again I'm gonna go to UI button text mesh Pro once again you could use the Legacy ones too for our button here let's go ahead and we actually uh yeah so this has an image um on it which we have a Sprite for so there's a retry Sprite so I'll set that now it doesn't it's all stretched weird so let's click the set native size button and then usually your buttons have a text component as like a child so we don't need that we can actually just delete that and from here it's just really a matter of sort of just kind of uh repositioning these so maybe I might want to move our text up a little bit more set this to like 72 for example maybe our button will get lowered also feel like the buttons maybe a little bit small so I can always scale this maybe I scale it by you know two five or something I might want to lower this as well let's do negative 48. particular that feels pretty good to me um cool what else I think that's really it actually now all we need to do is we need to hook up this button to call our new game um on our game manager so the way we do that is there's an on click here on the button component we can click the plus button we can drag in our game manager here and then we can call any function we want on that script and now the problem is it doesn't show up here because it's not a public function so let's go to our game manager Scripts and let's change this to be public new game [Music] also I'm going to rename this button to uh retry call it whatever you want um so once again we drag our game manager object to here do not drag the script onto there I've had people do this and not understand why they couldn't why nothing showed up drag the object from your hierarchy in there and then now we can click new game sweets now I think the only other thing we need to do is in our game manager we need to get references to these UI components so we can turn them on and off respectively in new game and game over now these ones we can't just assign automatically because there's not a way to distinguish them from one another so we need to make these public references and we have to import if you're using text mesh Pro you have to import TM Pro um if you're using the other kind of Legacy ones you have to I believe import using Unity engine.ui otherwise TM Pro here and for a text mesh Pro this will be um this will be text smash Pro you GUI and we'll call this the game over texts and then for the button oh so actually we still need to import using Unity engine.ui because the button component is still a uni UI class so retry button all right so on new game um we're gonna set those off and on game over we're gonna just turn them on sweets so let's go ahead and test this out so initially when I play the game they should actually disappear because by default the game just starts automatically oh we gotta make sure we assign these so otherwise we'll get errors in fact I'll just show you what will happen we'll get some normal reference exceptions because we haven't assigned those we're trying to access a null object so let's drag these references into their respective slots and try again so they once again they disappear immediately you can see they're turned off here in the editor I die we get a game over and I should be able to click this and there we go it restarts so that's kind of our full game over retry with some UI in there okay to tie everything together and to kind of wrap up let's do scoring which will also include a UI some UI as well so let's go ahead and create a couple more UI components in our canvas let's create some more text we need one for our normal score let's just start with this one first because we can then duplicate it for the others because they're very similar I'm gonna anchor this to the top right corner so I'm going to click this diagram here I'm going to Anchor to the top right now if I set the position to zero zero it gets set to zero zero relative to that corner now I still need to adjust other settings so it's not quite right um so I want to right align it I also want to top oh yeah it's already Top Line by default I'm going to disable word wrapping uh the font size I'll leave when I'm going to change the color will also be the same dinosaur color that grayish color I'm gonna drag in our fonts that we used to there um by default the text will be let's say five zeros now I need to set the pivot point on the X and the y-axis to be one which is going to change my position but now if I set those back to zero there we go so the pivot Points in the top right corner so the top right corner is now at zero zero and then the thing is the hole is anchored to the top right corner of the screen so that's how it gets lined up I still don't want it to maybe be exactly at the corner so maybe I adjust these to be something like that and that looks good okay so from here um that's our score I'm gonna duplicate this I can um right click and duplicate it I'm going to change this one to high score and I'm just going to shift it over some more um let me see what value I use feel free to yeah just kind of adjust it till it's shifted over into 256. um and I also want a little label that just says hi so I'm going to duplicate this as well let's change the text to just be H um to just be h i and I'm going to adjust the position of this as well I'm gonna set the position so there's an exact amount of space between the different labels now this font that I'm using I I chose very specifically because it's actually a mono space font which means that no matter which character you're using they're all exactly the same size and that's really convenient for things like this normally speaking the let's say the character one is really skinny but in this case um it's all the same so here actually I'll do this let's reset the asset back to normal if I change let's say the one to I don't know a six um or a nine oh actually the okay I guess this built-in font that uses um is also monospace so never mind that doesn't even matter but uh certain fonts that aren't mono space will be um it's going to change the the entire size of this based on you know what characters you're using so if the whole thing was let's say ones it'd be really skinny but then it's going to make it so none of the text like lines up it just it won't like line up right just depending on um depending on the sizes or depending on what characters you're using um so the monospace font just makes it so it will always kind of perfectly be aligned and even as these numbers change it won't like change position or change size or anything so it doesn't once again doesn't necessarily matter but the that just kind of helps just make it visually a little bit better all right now one thing we might want to do I probably should have did earlier is change our scalar properties so typically I don't want to set I typically don't want to use constant pixel size what that's going to do is depending on your screen size um or if we change this it'll scale with your screen size that's how you is able to adapt to different like let's say mobile devices landscape versus tablet um if I do scale with screen size and then I can maybe set my reference resolution to like 1920 by 1080. and I like to usually do right around in the middle here so it'll try to match half of the width and half of the height this makes it so depending on what my resolution is it kind of adapts a little bit better on the UI so you can adjust that to your preference maybe in my case I actually want to do like 1280 by 720. and I think that works a little bit better yeah so this is a small detail doesn't necessarily matter but it just helps um okay anyways I'm getting sidetracked a little bit now we have our score let's go back to our game manager let's add some more references to those text components so text Mash Pro you GUI score text and then we also want another one for our high score text and let's add some variables for the score itself um so let's add a float for our score I'm using a float typically I'd use integers for things like this and in the in the UI it's just going to be integers um but I actually want to use a float here because the score is sort of based on time and with time you know you might have milliseconds it's not just perfect one second two second you know it's gonna be you know 2.4 seconds 2.5 seconds 2.6 seconds so it's actually gonna we're gonna be able to calculate our score better using a float um but when it shows up in the UI it'll just be an integer so for our score we're gonna increase our score and update very similar to how we increase our speed in update so here we're gonna increase our score based on the game speed times time dot Delta time so as our game gets faster you're gonna get more score as well so when the game is really slow it's a lot easier so you don't accumulate as score as quickly but once the game starts speeding up and it gets really fast that makes it more difficult which also means you should gain more score it also makes sense too because you're moving faster so you can think about score almost as like how much distance have you traveled and if the game is moving faster well that means you're covering more distance and less time so your score should your score should go up faster as well there's no specific like you can of course customize this if you want it to just be like you know increase by the same amount per second like you could do that um but I I personally like it like this now anytime our score changes we need to update our score text our score text here so we can say score text Dot text equals um score to string but once again this is a float and we need to convert it to an integer so what I want to do here is say math F dot round to int passenger score and then we'll convert it to a string and in my case I actually want to floor this instead of round it rounding will go up or down flooring it will always round down so I feel like that works better it doesn't really matter but yeah I like that better now this we're actually doing one more thing but let's take a look at what this looks like foreign pretty quickly oh well I got a null reference exception because I forgot to assign my references let's drag those in oh uh yeah actually that's good let's test this again all right so notice how I lost all those zeros so I mean this works but it's not quite what I want I actually wanted to say like zero zero zero three seven you know so I wanted to keep all the padding all those leading zeros um so C sharp actually has a very simple way we can do this when you convert a number to a string you can provide a format um so I could say d for decimal um and then I can say 5 to indicate that there should be five digits all right I think these for decimal moves for digit but yeah basically I'm saying I want there to be always be five digits displaying so now it'll automatically add those padding zeros to make sure that it always shows the full thing so there you go that looks great cool so that's our score and once again as our um is our game speed increases so will our scores might be hard for me to do while I'm trying to not get hit but yeah so as our game speed increases our score is going to increase as well and that was obviously you don't want the game to increase that quickly but yeah so there you go that's our basic score and finally let's do high scores so this is actually something I don't think I've ever done in any of my tutorials yet but how can we save what your high score is even if you close the game and come back to it later we want to keep track of those high scores so for one we need to update the high score that shows up both when you start a new game and when you finish a game in case you've beaten the high score we want to update it and also when you start a new game if it's the first time you're playing the game for that session then it needs to update so since we're going to do it in two places why don't we add a function that we can reuse so I'll just say that update high score foreign and I'm going to call this in both new game and in game over so in our high score we can save the player's high score to um using something unique calls player prefs so we can say player prefs based on Uni's description here they say it's a class that stores player preferences between game sessions it can store string floating integer values into the user's platform registry so this that allows us to save some data and even if they close the game and come back to it you know let's say the next day that data will still be there so we can reload that data and display their high score so what we should do is get their current high score and compare that to their current score and if it's if their new score is is greater we need to re-save that high score um and proceed so let's get their current high score we're going to say playerpreps dot get float so we're going to save it as a float because our score is afloat we need to provide a key to indicate you know what we're saving this as it's just like some identifier to know like what what this variable is um in the player pref so I'm just going to call this high score and then we pass in the actual value we want to or no this is so we're getting the score right now but in the case that there is no data saved what should the default value be well the default then should be zero so let's check now if their current score is greater than the high score well then we want to update the high score to be their new score and then we want to re-save this again so we're going to set this float so we're instead of getting we're going to set now we're going to use that same key we want to make sure we save it under the same thing and we're going to pass in the value we want to save high score and then of course we want to update our high score text as well and we're going to use the same kind of code we used here but this time we'll pass in our high score so we're formatting it the same way um and that's it all right so let's play this so it's zero because I've never set a high score yet it's my first time playing um now that we've added that code so let's say I get you know 56 boom so you saw it got updated because it runs that code on game over when I restart now oh so well we found a bug my score didn't reset from um my score did not reset after we got a game over so I'm glad we found that because that was just something we missed from before whenever we start a new game we need to we need to re-assign the score so let's set our score back to zero here in new game so that's pretty important all right let's try that again all right so yeah so look notice how it loaded my high score it shows 56 which is accurate let's try to beat that now well that's not Beat It so it stayed 56 nothing changed because I didn't actually beat it let's actually try to beat that high score now and there we go so we've beaten our high score now it doesn't update until the game ends so we get a game over now it updated to 85 that's our new high score we restart starts at zero again there we go so that's our high score and once again even if I close the game and reopen it that high score will still load so I restart the game still saves that 85. that 85 is saved to my system so I can reload that over and over again 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 the 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] foreign
Info
Channel: Zigurous
Views: 37,716
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: UPvW8kYqxZk
Channel Id: undefined
Length: 103min 25sec (6205 seconds)
Published: Wed Oct 19 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.