How to make Centipede 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 create the classic arcade game centipede in unity centipede is a 1981 fixed shooter arcade game developed and published by atari the primary objective is to shoot all the segments of a centipede that winds down the playing field we will learn about shooting mechanics player movement object generation and a lot more 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 would mean a lot to me and it really helps drive the growth of my channel 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 project button from here we can choose the template we want to start with in our case we're going to choose the 2d template since this is going to be a 2d game we can also choose which version of unity we want to use so i'm going to use unity 20 20.3 this is the current long-time long-term support version for this tutorial though it doesn't really matter we won't really be utilizing anything that's specific to one version or another so feel free to use whichever version name your project whatever you like i'm going to just call it centipede and choose wherever you would like to save your project and go ahead and create the project from here it might take a couple minutes to initialize so we'll pick it back up as soon as it finishes before we do anything let's go ahead and import some sprites that we're going to use throughout the project i'm going to actually create a new folder here by right clicking in the project panel create folder let's create a folder here for sprites so we can keep everything organized if you want to use the exact same sprites i'll be using you can download them from the github project there will be a link in the description of the video it'll take you to the repository here and click this download link and then you can extract this folder here to find the entire project and within the project there will be a assets and then spreads folder i'm just going to use these same sprites since this is already an existing project it includes these meta files for now you can ignore those the meta files are generated by unity automatically once they've been imported into a project i'm just going to take all these png files i'm going to drag them into our project panel down here let's go ahead and move these into the sprites folder and there's just a few settings we want to change on on these sprites here so if you click on one you can change the import settings you can actually click on all of them at once so i can change all of them they're all going to have the same settings first i'm gonna change the pixels per unit to eight all of these images are sort of eight by eight images and so this means once it when the image your sprite is being displayed in our scene one unit in our scene will be equal to 8 pixels so it'll just kind of help keep everything normalized um let's see what else we also want to change the filter mode here to points for pixel graphics you usually want to use points otherwise it can apply some filtering that's going to sort of change the style of the graphics a little bit so it's not going to have that pixelated look to it so we usually want point and in our case you know that's really all that matters but since these are all small images i can set the max size to maybe 32 the compression maybe to none since these are all really tiny images anyways just really maximize the image quality and that should be good for now all right let's just do a little bit of simple scene setup before we begin writing our scripts for our game so in the left here is our hierarchy where we can see all the game objects that exist in our scene and on the right is our inspector so when i select a game object i can inspect all of the components and properties of that game object before we do anything i'm actually going to go to our scene file here i'm going to rename this to the centipede you can of course have multiple scenes you know for some games you might have a scene for your main menu for level one level two etc you can have all kinds of scenes for this game i'm just gonna kind of keep everything in one scene but potentially if you build this game out more and more you might want to have multiple scenes in which case you can switch between them so here in our hierarchy let's choose our camera you can see the preview of our camera in the corner here we can also switch to our game view where where we can see the full thing i'm also previewing the game at a one to one aspect ratio you can always customize that you can change the aspect ratio you want to preview your game at you can add new ones if you want to for our camera first i want to change the background color to black it's a pretty simple change feel free to obviously customize this to your preference the other thing i want to do is change the size here so what this is going to do is essentially change how much area the camera can see so for example if i increase this or decrease it this white outline is representing what the camera can see so if i increase this i'm essentially giving myself more space to work with the camera is able to see more um within our scene and so for this game we're basically going to be following kind of a grid system all of our objects will be displayed on a grid and so i'm going to use it like a size of around 20 should give us plenty of space to work with we'll be able to have plenty of rows and columns to be able to put all of our objects the only slight caveat here is i actually want to increase this by half a unit whatever whatever size you end up doing i would then add 0.5 to it the reason for this is because here let me demonstrate it let me just drag a sprite into our scene so i can show you so everything in our scene is going to be on a grid right so let's say this object is right against the border right against the edge of our camera there so negative 20 right so everything's gonna be perfectly aligned to whole numbers 20 19 18 etc you can see here it perfectly lines up with the edge of our camera which is what we want let's say the size were just 20 well now when our objects at this whole number it's actually halfway clipping outside of the bounds of the camera which we don't want and so we'd have to decrease this to like not say 19. but now there's some extra space here and so to make sure the objects perfectly kind of aligned to the edge of the screen or the edge of our camera we can increase that by half a unit [Music] all right so that's good for now i'm not going to really do much else in our scene but as we continue to build out the game we'll add more let's go ahead and add our blaster sprite to our scene so we can then write our first script for player movement if i just take this sprite here and drag it into our hierarchy it'll create a new game object with the sprite render component and assign that sprite to it there's a couple other components i want to add as well i want to add a rigid body 2d of course the 2d version since this is a 2d game a rigidbody turns this into a physics object that means the physics of this object will be simulated via the physics engine there's a few properties i want to change on here so i can get rid of drag i can just set this to zero the angular drag has to do with rotation but our object's not going to rotate it at all in fact i can even freeze the rotation just to make sure it doesn't doesn't rotate accidentally and freeze that there and i also want to turn off gravity because in our game we can kind of freely move up down left right there's not really a sense of gravity for this particular game so we can set that to zero as well next i want to add a box glider 2d component the clyde or any kind of clutter there's different shapes box glider circle collider so on these will define the collision area of our object which is represented by this green outline now i'd actually don't need to do anything else on this all those settings are completely fine as their defaults and so that's it in terms of actual objects let's go ahead and create a new folder now to contain all of our scripts just to keep everything organized you can create a folder that are called scripts then we can right click create c-sharp script and i can create one called blaster once that script has been created you can actually add it to your objects if we re-select our object we can drag this into the empty area at the bottom you can also add it via this add component menu and then we can start writing our script let's open up our blaster script i'm going to be using vs code throughout this tutorial feel free to use any editor you want it doesn't really matter it's just preference if you are curious on how to set up vs code for unity i do have another youtube video for that you can check that out by default unity creates us a class that inherits from mono behavior and then there's a couple functions here that are very commonly used i actually like to kind of sort of delete everything and just start fresh i still like to remove these two imports that aren't being used that's just my preference you don't necessarily have to do that but like having a clean slate to work from so to move our plaster object here we need to get a reference to that rigid body component so we can add forces to it to handle movement let's go ahead and create a new variable private rigidbody2d i'm just going to call this rigidbody and there's actually a really old sort of deprecated obsolete property with this exact same name as part of one of the one of these base classes so we get a little warning here because that property is kind of obsolete and deprecated we can sort of ignore that or if we want to suppress that warning we can just add the new keyword here and to assign this value i'm going to add our awake function this function is called automatically by unity the first i guess essentially when your your object is first created or initialized within your scene make sure you use capital letters here for the always for the first um for the first letter of the functions for any of the built-in unity functions it has to be exactly this case sensitive otherwise it won't get called so in here we can say rigidbody equals git component and get a reference to our component this is another function unity provides that it's going to look it's going to look on the same object that our script is on so our script is running on this object and when we say git component it's going to look on the same object for that component that we specify so in our case rigidbody2d if it can't find that component it'll just get set to null which will probably cause errors all right next let's go ahead and add our update function so this function is called also automatically by unity every single frame that this script is enabled and this behavior is enabled and this is usually where you're going to handle like user input or player input and so we're going to assign we actually need to create a new variable to store our direction the direction the the blaster is moving this will be a vector 2. just call it direction and in here we can assign um our direction based on the user input you can say direction.x equals input.getaxis and then we can say horizontal and then direction.y equals input getaxis vertical let me explain what these get access is doing so this is actually using unity's older input system there is a newer input system but by default the old input system is it's still the default when you create a project so if you go to your project settings edit project settings there's an input manager here with these different axes so there's all these different buttons that are just by default included so we can see there's horizontal and vertical these are mapped to wasd as well as the arrow keys and i think it even has like controller stuff built in or actually i think there's more yeah there's another set of horizontal and vertical which are mapped to your joystick so like if you have a controller so we can just kind of reuse these default settings that already are set up which is really convenient um if you're using you can obviously you can use the new input system too and that's that's fine as well the only thing i really want to change on these is the some of these the gravity and sensitivity so this is going to change like how quickly the value goes up and down when when you press it and we want the game like we want the player to sort of move instantly if i press that like if i press left i want it to instantly move left i don't want it to be this slow gradual process and so with these default settings it doesn't feel very good in my opinion i'm just going to bump these up to like a thousand just so basically it instantly starts and stops the input rather than like slowly accelerating and deceleration decelerating obviously feel free to adjust these to your preference just based on how you want the game to feel [Music] but i'm going to do this both for horizontal and vertical we should be good there all right let's go back to our script here that's update that's setting our direction vector based on your inputs we also need to now actually apply a force to our rigid body based on this direction so this will do in another function called fixed update the difference between these is update runs every single frame your game is running but the frame rate of your game might vary okay fixed update runs at a fixed time interval doesn't necessarily matter what the frame rate is this is usually important when you're doing physics because you want the physics to be consistent if it's the physics changes based on the frame rate of your game you're going to get really inconsistent results so we usually do physics related things inside fixed update so here we can sort of calculate um a new position for our object and this is one thing so although we are using ridge bodies normally speaking you would add a force so normally you would say rigid body add force and that's going to move the object in different ways and it's going to handle collision and stuff like that or for this game we're not actually going to use normal forces we're going to use something else um so let me show you how this works but we need to sort of calculate the new position ourselves so i'm going to get whatever the current position is we can say rigidbody.position this is whatever the current position of our object is and now we can change that so i can say position plus equals direction i actually want to normalize our direction what that's going to do it's going to make sure our vector always has a unit length of 1. the reason this is important is because let's say you're moving at a diagonal the x let's say is 1 and the y is one which makes you move at a diagonal but the unit length the vector length is actually bigger than one so you would move faster on a diagonal than if you were just to move up or down or left or right so we don't want the inconsistency consistency so we can normalize our vector to make sure it always has a magnitude of one it's usually pretty common when you're doing like you know motion vectors and or kind of direction vectors and stuff we can times this by some scalar like a speed variable which we don't have yet so let's go ahead and create that this one we actually want to make public that way we can customize the speed of our object in the editor maybe just by default i'll set it to around like 20. but we can change that that variable will show up on our script and we can just set to whatever anything we want we can multiply this direction by our speed and then finally we also want to multiply this by time dot fixed delta time this will make sure that the amount that we are moving is sort of spread out over time and we want to use fixed delta time here since we're in fixed update if you're with if you're using the time in normal update you would just use delta time in our case fixed delta time so that's our new position of our blaster and then we can say rigidbody.move position so we're gonna move to this position and this will still handle collision and things like that that's good there that's it for now let's go ahead and actually test this out go to our blaster object here and you can see in our inspector you can see that speed variable so we can always customize that if we want to go ahead and run this and now i can move up and down left and right perfect feels great inputs are very responsive they happen instantly because of those changes we made in our input manager and that looks great there is one problem here where i can move out of bounds so that's going to be the next problem we we tackle so to prevent our blaster from moving out of bounds we just simply need to add some barriers so it some invisible barrier barrier so it can't pass beyond that we can do that by right-clicking our hierarchy we can create an empty object here let's reset the transform here just so it defaults everything back to the normal values of zero and let's add a box collider 2d here and let's go ahead and switch to our scene view so we can see this object so if i move this object we can see the green outline of our collider we essentially want to move this all the way to the edge of our border and then change the size on our box collider just to make sure it fits the entire screen here so i'm going to do let's see like 40 and we can do 50 and just make sure it covers the entire area area and we also want to make sure this is perfectly lined up with the edge so let's do 21 a nice whole value there do the exact same thing on the other side and actually let me name this i'm going to call this barrier i can just duplicate this by right clicking and choosing duplicate or pressing ctrl d or command d if you're on a mac and we can move this to the opposite side a whole value of 21 same size so we have our two barriers there that looks good go ahead and also create one at the very top and the very bottom let's duplicate this again let's move it back to the middle let's actually flip the size here we need to change the size in the x-axis now let's do 50 and one let's move this up we do 21 there let's duplicate this one more time do negative 21. we have four barriers kind of surrounding our scene there which looks great and let me just name all these barrier and let's go ahead and test this out oh yep now i hit the edge and i can't move beyond it so that looks perfect and once again i perfectly kind of line up with the edge of the screen based on the camera settings we used before of using the 0.5 there now the only thing i don't really like is when i'm sort of scraping up against the edge my like movement kind of slows down a little bit it doesn't feel super good so something we can do to help that a little bit is to add a physics material to our blaster which is going to change uh how friction is applied when we collide with something i'm actually going to create a new folder for this let's create a folder called let's call this physics and i'm going to right click in here create 2d physics material 2d i'm going to call this no friction and you can see there's two properties friction and bounciness if i set the friction to zero that'll allow us to kind of move up against that edge without it being so without the friction kind of slowing us down so we apply this material to our rigid body on our blaster it should help a little bit to smooth that out yeah that feels a lot better now i don't i don't like slow down when i'm sort of it's so it does still slow down a little bit because my vect the vectors like i'm moving on a diagonal right now so the vector changes but it it's not nearly as bad as it was so if it has a lot smoother and this will work too once there's mushrooms and other objects in our scene you're not going to kind of get stuck up against them as much you'll be able to sort of smoothly kind of collide with them and continue moving on and it just helps a little bit we also need to add a barrier towards the bottom middleish area because the the player here the blaster shouldn't be able to freely move everywhere they should sort of be restricted to an area towards the bottom let's go ahead and actually duplicate one of these barriers one more time let's take one of these horizontal ones and let's move this up to around let's say negative 10. that'll give the player basically all of this area down here to to move around in they shouldn't be able to really go anywhere they'll sort of sit within this i think they refer to this as like the home area and change the name here barrier um and let's move our blaster into that area let's move our blaster down in there let's spawn them at around i don't know negative 18 it should work pretty well and there it goes we spawn towards the bottom if we replay i can yeah i hit that barrier there and i can't move anywhere beyond it so this is good but this is plenty of area for me to navigate around in and once the centipede is within this area the centipede will stay within this area so it'll hit the bottom and it'll start go back up once it hits this period or start to go back down it stays within this area which adds like an extra challenge to the game okay let's focus on our dart next the dart that you can shoot out of blaster let's go ahead and just create that game object go to sprites and let's drag this into our scene just like we did for the blaster now for the dart we actually want to parent this game object to our blaster that way when the blaster moves around the dart wheel as well at least before you when it you haven't shot the dart it will sort of be sticking out of your i guess mouth and then once you shoot it it'll detach itself and be able to you know move freely but we can drag this object onto blaster here and so it'll kind of create this nesting here this indicates the dart is a child of this object if i move our blaster it moves both of them together now of course we want to reposition this so we want to move this let's say um oh yeah so now if i set z a a value of zero that's going to indicate it's the same position as the parent the parent's at negative 18 but zero is the same i want to just bring this up like 0.5 that way it kind of looks like it's sticking out of its mouth you also might have saw that it sort of is on top of the blaster it should probably be underneath we can go to our settings additional settings here for our spark render and we can change the order in the layer i want to probably just set this to maybe negative one that way it sits behind it and that that works a little bit better really i should probably do that for our blaster as a whole as well where the blaster itself should always be the kind of on top of everything that way at some point if there's like a mushroom or something in case it clips over it a little bit or whatever just to make sure our blaster is kind of always the most foreground element so just increase that to one so it's always on top of everything that all looks good now we still need to add a couple more components to our dart before we can begin writing our script so very similar to our blaster we need a rigid body 2d component and we can kind of do some of the same settings as we did before we can turn off angular drag because there's not going to be any rotation we don't need gravity we can set that to zero we can freeze the rotation i think we can even oh now let's just say i was thinking we could freeze the x axis because it only moves up and down but when the blaster is moving and it's technically moving left and right as well so that should be good and let's also add a box glider 2d to our object here and let's go to our scene view so we can visualize that yeah so here the the size of the clatter it doesn't quite line up with the actual visual of the of the uh dart so i might want to adjust this a little bit so it lines up a little bit better so let's say like 0.125 i think 0.75 is the correct size and we just need to realign it there i think this technically mathematically this should be negative 0.0625 so that's like perfectly lines up the um the collider with the actual kind of pixels of the dart that's good there that'll just make the collision feel a little bit more accurate all right that's it for now in terms of the setup of our dart then we can actually create our script as well so let's go ahead and do that right click in our scripts folder create c-sharp script we'll call this dart and we will attach the script to our game object just like we did for the blasters let's go ahead and drag this into the empty space now we've got our script down there all right let's open up our script and start editing this i'm going to delete these just like i usually do start with a clean slate here for our dart we once again need a reference to our rigid body components we can actually you know apply some forces to it let's create a new variable for rigidbody 2d exact same as our exact same as our blaster i'm going to get that same warning so i can suppress that with the new keyword there we also need a reference to our collider as well so same thing here collider 2d i could be more specific if i needed to i could say box splatter 2d but just generic lighter 2d it works for us this also the same um this property also is one of those obsolete or deprecated ones from from an old version of unity so i can suppress that as well with new keyword and the the reason we need a reference to our collider is because we need to actually turn on and off the collider when you you know when the when the dart has not been shot yet we need to disable the clutter that way it doesn't like collide with the player or other things i mean only once you shoot it will it actually turn on the collider um and then we also need a reference to the parent um well so well let me explain that a little bit more but let's create a variable that's of type transform now let's call this parent let's go ahead and assign these different vari values in our awake function once again this function is called automatically by unity when the object is first initialized where the script is we can rigidbody equals git component rigidbody2d we can also set our collider here getcomponent collider2d and our parent here we actually can reference or access the parent via transform that parent and so i want to assign that parent equals transform that parent the reason we need this is because when we shoot a dart we're going to detach the dart from the parent and then later on we need to reattach it and so we need to sort of save which object this is parented to that way later we can detach it because once we detach it well then this won't this will just be null we won't know who it was previously attached to and so this will allow us to kind of save that so we can reattach it later now initially when the dart sort of spawns it's sitting in the players or the blaster's mouth so we want to turn off the collider you say cloud or dot enabled equals false and we also want to turn off the physics simulation on our rigid body we don't want to simulate any physics or anything so to do that we can say rigidbody.bodytype equals rigidbodybodytype2d.kinematic this is going to essentially turn off the physics simulation we probably should even do that in this scene just in case so initially this will be set to kinematic here and then our collider will be disabled oh it just doesn't cause any problems initially all right let's go back to our dart script go ahead and add our update function so we can handle input to determine when the dart actually gets fired so somewhat similar to what we did in our blaster but a little bit different we'll say if inputs dot get button and we can say fire one this is another input that is included by default in the input manager so we go back to our project settings input manager there's actually fire one two three so by default this control is mapped to left control or mouse zero so i can click my mouse button to to fire maybe i want to change this to like space i think that would be more appropriate um and yeah we're good there everything else looks looks fine yeah there's even one for once again the joystick so we're good there feel free to obviously change these you can add new ones if you want to you know just kind of then change the string here so when we fire we need to um depart the dart from the blaster we can say transform set parent to null so this will detach it so it can kind of move freely we need to re-enable the rigid body simulation so we can say route by body type equals rigid body body type 2d dynamic and then we want to re-enable our collider that way collision can actually happen between the dart and other objects the only thing that's missing here is we only want to be able to fire the dart if it isn't currently fired so the only for for my implementation of the game and i think this is true for the original there's only one active dart at a time you cannot like it's not spawning new darts every single time you you click or fire so it's one dart if it's already active then you can't fire it again and so to prevent the way we can do that is we can say if rigid body is kinematic that sort of implies you know when when the dart is not active it's kinematic right so while it's essentially not active then we will check for input and if you press the input we will fire it this way once it has been fired it's no longer um this will be false and so you wouldn't be able to like re-fire it a second time until later on it gets reset that's checking for input actually firing it the movement itself will be handled in fixed update just like we did for our blaster so here we can calculate our new position let's get the current position from our rigid body we can then update this position and i can just say it's always going to move up and so vector 2 dot up times some speed variable once again so let's add a speed variable public float speed what should this be default to let's default this to around 50 maybe you can obviously customize that and by making it public it'll show up in the editor so you can freely change that value and then just like our blaster we need to multiply this by time dot fixed delta time that way this movement happens it gets spread out over time and then we can move our position on our rigid body rigid body move position we'll pass in that new position the only thing missing now is we should only be moving the dart if it's been fired and so kind of we need the opposite of this if it's not kinematic that means it's been fired and so that's when we want to do this code so we can say if if it's not rigidbody is command the exclamation mark means not we'll move this code inside there right so if it's not kinematic which essentially implies it has been fired we will move it otherwise if it's kinematic which means it's kind of not been fired we won't run this code and finally we need to reset or reattach the dart to the blaster whenever it collides with something the way we can handle collision or check for collision is via a function called on collision enter 2d and then this has a parameter called collision2d we'll just call this collision once again make sure for these functions they're typed exactly like this case sensitive otherwise they won't be they won't get called because these are called automatically by unity so whenever we collide with anything we need to essentially do the opposite of this we need to reattach it so we need to reset the parent to its initial parent which we saved when the object was initialized we need to reset the position to be you know wherever the blaster is this is where we can say local position instead of just normal position the position here is world space whereas local position is local space this can be relative to the parent and so this is where for us it's really just zero zero zero um or we'll really if the y we we want to offset it a little bit so if you remember correct if we remember on our dart we said 0 0.50 this is local space since it's attached or parented to the blaster it's relative to the blaster we can say 0.5 there so that'll kind of reposition it in the mouth of the blaster and let's set our rigid body to be kinematic again that way it's not moving and let's turn off our clutter that way you don't it doesn't collide with things even though it's not active and that looks good let's go ahead and test all of this out so let's run our game i can shoot here so the problem you can actually see in the hierarchy it is detaching so it's it's working it's getting detached and firing but it's not moving and that's because as soon as it detaches it instantly collides with our player and so then it gets reattached we need to turn off collision between these two objects one of the ways we can do that is via physics layers so if we click on our let's say let's start with our blaster on this object there's this layer property up here we can we can add different layers or assign them to different layers and then in our project settings we can say which layers can collide with with others so let's go ahead and add a new layer let's add one for player and let's add one for dart so i'm just going to add just whatever available user layers there are player and dart let's go to our blaster let's assign this to player no we don't want to change the children and then let's assign our dart to dark now in our project settings edit project settings you can go to physics 2d and at the bottom here will be this collision matrix which allow you to turn on and off collision between different layers so we want to disable collision between the player and the dart so if we uncheck that now those two won't collide with one another let's rerun this and try it again there we go so now i can click and so it's hitting this invisible barrier here and so it's getting reset that's no good we want our dart to be able to go through that invisible barrier so we might need to do something very similar where we um sort of set that on its own layer that way we can ignore the collision between it let's go ahead and find that barrier there i guess it'll probably be on all of our barriers let's go to let's find that one at least okay so let's go here let's go to our layer again add layer add one called barrier let's go ahead and assign this there and actually we should really assign that to all of them we can select all and set them all to be barrier and let's go ahead and try that out so if we go to our project settings now we can disable collision between the dart and the barrier uh let's see so barrier and dart yeah there we go so we can turn that off and now we can rerun again it should be able to travel through there it does the only issue now is that because it doesn't collide with the barrier at the top it keeps going on forever and there's nothing to like essentially reset it so just for this very top barrier we actually don't want to set the layer we can just set it back to the default that way it'll make sure that when the bullet or the the dart hits this top barrier it'll always collide with it and which will make it reset there we go so now as soon as it hits the top it gets reset i can shoot again but it traverses through this invisible one in the middle i guess the sides and bottom don't really matter since you can't actually hit those but this looks good next we can start to handle our mushrooms or we can really spawn all of our mushrooms we need to create a prefab for it though let's go ahead and go to our sprites folder let's find just the first mushroom here and let's drag that into our scene let's call this just mushroom and let's add a few components to this let's add a rich or we don't need a rigid body because the mushrooms don't move but we do need a box glider 2d that way collision can be detected between the mushroom and other objects like our dart or centipede don't really need to change any of those it works perfectly our outline there fills the object perfectly so from here to create a prefab we just need to drag this object into our project panel it's going to turn this object essentially into an asset that we can then reuse over and over again um let me actually create a folder for our prefabs just once again keep everything organized let's open this up if we just drag this into our prefabs folder here it turns it into an asset that we can now reuse i can actually delete it from our scene so now i have this as an asset so i can always like respawn these as i want to right i can always just have a bunch of them now and so now really what we're going to do is we're going to write a script to spawn them dynamically in our scene so let's go ahead and create a new script called um well we're gonna need two scripts so we're gonna need a script for the mushroom itself so let's go ahead and just create that and we're also gonna need a script for our mushroom field so the mushroom strip will handle like the health and like the the states and health for that for each individual mushroom it'll have its own script on it the mushroom field will handle like spawning all the mushrooms as a whole so let's actually go to our prefab for our mushroom and let's make sure we add the mushroom script to it that way every every instance of our prefab here has that same script for our field one thing we want to do is indicate the area that the mushrooms can spawn within and i can do this via a box collider actually let's create an empty object in our scene let's reset the transform sets normalized to zero i'm just going to call this maybe field or i could call it mushroom field and let's add a box glider 2d here and we can just adjust the size here to kind of indicate this is the area area i want the mushrooms to spawn within so let's say 40 for example that'll be good it can spawn all the way up against this edge and once again if if i'm spawning this right at 40 it's gonna at well i guess it's 20 because it's 20 in each direction would be 40 but if i'm right at 20 it's going to perfectly align against the edge so for the size here i want it to be half a unit away from that edge there and the y the y it can be the y can vary a little bit you know maybe 30 um 32 we do like 33 i think um actually works well because if once again if these are on a grid let's say this is like negative 16 or let's say negative 17 yeah so like that works perfectly because our you can see our blaster and the mushroom are perfectly on two separate rows um so at 33 here so actually we could maybe even go a little bit more i think though if this is an even number yeah this is the problem where oh no that actually should be fine because then this can spawn if it spawns right on the edge there yeah that should be good so 34. let's try that we can always adjust it if we need to um so 40 34 feel free to adjust that doesn't really matter i guess and let's go ahead and the important thing here is we mark this as a trigger we don't actually want anything to collide with this this is just sort of we're just going to use to indicate the bounds of the area we can spawn mushrooms in we don't want anything to collide with it i'm marking this as a trigger it allows objects to go through each other and you can you can still check to see if some object has collided with this but it won't actually like cause the object to stop its movement so trigger there that's really important and this object here we can bring our mushroom field onto all right let's go ahead and open up our mushroom field script let's start with this one i'm just gonna delete these like i usually do start with a clean slate here for our field we need a reference to that glider component that we added so we can check what the bounds of it is so let's go ahead and add a variable for box collider 2d i'm going to call this one let's call it maybe area we also want a variable for our prefab that way we can reinstantiate that prefab over and over again this one i want to make public so i can assign a reference to the prefab in the editor and it's going to be of type mushroom this means whatever object i assign as the prefab has to have the script the mushroom script on it if i try to assign any other game object as the prefab it won't work unless it has that mushroom script on it and maybe we add a variable to indicate how many mushrooms you want to spawn this can just be an integer maybe i say amount and maybe this defaults to 50 so we can spawn 50 mushrooms initially and you know maybe as you as you continue playing the game it spawns more and more and more let's go ahead and add our awake function so we can get our reference to our area here we have via git component box glider 2d and let's create a function called maybe generate so we can say private void generate here and we can get um well so we should call this function and start so starts another built-in unity function this function is going to get called automatically the very first frame that this script is run the script runs and so in here we can say generate [Music] in our generate function we can get the bounds of our collider we say bounds equals area dot balance so area is that box collider then we can loop over however amount however many mushrooms we want to spawn so we can create a kind of standard for loop here for into i equals zero i is less than uh amount i plus plus [Music] and then we just need to sort of pick a random position within these bounds and then instantiate our prefab so let's say position here i guess just initially it'll be zero and then we'll assign the x and y independently uh so we can say random.range and we can give a min and a max and so the min and max is just going to come from our bounds so we say balance.min.x bounds.max.x and same thing for our y here random.range bounds.min.y bounds.max.y now the only important thing here is we need to round these values to the nearest whole value that way everything stays kind of aligned perfectly to a grid we can say math app.round kind of wrap that whole thing in a round function math f dot round [Music] and there we go so we're taking this whole thing and putting it inside round and now we can instantiate a new object a new uh clone of our mushroom here so there's a function called instantiate we pass in the object we want to clone or copy this is our prefab we can then pass in the position we want to spawn it so that's that position we just calculated and then quaternion is their rotation we don't need rotation we can just say identity and then we can parent it if we want to so we can actually parent it to our field our mushroom field we don't need to do that but it might help to just keep things organized so this will just be transform and transform is referring to the mushroom fields transform the only other thing we might want to do now might as well do this now is if you regenerate um you know actually no we'll do it later when we get to our game manager i was going to say we should add a function to clear the field of mushrooms but worry about that a little bit later let's go ahead and test this out let's go to our field we do need to assign our prefab here so let's go to our prefabs let's drag that into our field there let's go ahead and play see what happens there we go got a bunch of mushrooms everywhere looks good let's check their positions they're all lined up when i'm trying to get some yeah so perfect this one's right on the edge it looks it looks perfect i think we're all good to go the important thing too is none of the mushrooms will spawn on top of the blaster right so the edge of our the edge of our field is right on top or right below before our blaster so they're not gonna accidentally spawn on top of the blaster um now obviously i can move around i can collide with these so everything looks good there perfect this looks great all right next let's handle the mushroom states themselves so this will be sort of like the mushroom's health where when you shoot them they have like you know a few different states that'll cycle between and then the mushroom will disappear let's go ahead and go to our mushroom script that we had created i'm going to start with a clean slate like i usually do and for here we need to add a variable to indicate the different sprites that we'll use for each of the states of the mushroom so there's four of them or you know you can obviously have more than four but for our case um i have four i guess we don't have to specify anything in the code here but we need to create an array of sprites so this is creating it declaring an array of sprite i'm just going to call this states i'm making this public so i can actually assign those in the editor we also need a reference to the sprite renderer on the mushroom so we can change the sprite any time the state changes let's get sprite renderer here and then we just need a variable for the mushrooms current health we can say private in health here go ahead and add our awake function let's assign our sprite render the git component and health is gonna initially get set to however many sprites you have right so if there's four sprites then the health is four we can say health equals states dot length now from here we need to determine when the dart collides with our mushroom we need to reduce the health and then swap out the sprite or change the sprite on our renderer here so to check for collision we did this before on collision enter 2d this takes a collision 2d parameter here let's call this collision now the difference between this one and our dart is we need to check what is colliding with the mushroom the health is only going to change the feed if a dart collides with it so the way we can do that is saying if collisions we're going to access some of the data in that collision object here if collision.gameobject.layer equals layer mask name to layer start then we know we collide with our dart so earlier we assigned the dart game object to its own layer we can look at that here if we choose select our dark our dart it is on its own layer also called dart um and so this is a way we're just comparing the layer of the object we collided with to see if it is that same layer and if it is then we know we climbed with a dart make sure this string here is exactly the same spelling and casing as the layer you assigned now what happens when we collide with the dart well we need to damage the mushroom let's go ahead and create a new function for that let's say damage here and maybe we can say damage by some amount and so here we can say damage one we're going to apply one damage to a mushroom any time the dart hits it when in our damage function we want to first reduce the health so health minus equals the amount and then we need to check well is that is there still health remaining on our mushroom or is there not so we can say if health is greater than zero then we need to reassign the sprite else we need to delete this mushroom so deleting is easy we just say destroy game object this is going to destroy this game object from our scene if the mushroom still has health remaining we just simply need to change the sprite on our sprite render sprite render dot sprite equals states you're going to access our array here the index is going to be essentially health but it needs to be the inverse of health but it needs to actually be states dot length minus health so it's the inverse because if state you know the first sprite in here is going to be when you're full health second sprite you know so it sort of needs to be the inverse of our health we just subtract by the length there and we're good to go i think that should be good go ahead and make sure we update that so let's go to our prefab mushroom our pre our mushroom prefab we have our states array here let's go ahead and assign our sprites to this so i have four sprites for my game so i'm gonna set the array to four i'm gonna then drag each of these in mushroom one two three and four and let's go ahead and test this out if i shoot one that's how it goes to the next stage every time i shoot it it goes to the next date [Music] and this looks great [Music] perfect so this works awesome and once it fully um and once once it has no more health it just gets completely destroyed and removed from the scene awesome [Music] now let's focus on the most complicated aspect of this game which is the centipede itself we're going to kind of break it down in a few different steps but let's start by just creating a prefab for one segment of the centipede so let's go ahead and take our let's say centipede body and let's drag this into the scene i'm going to rename this to centipede segment there's a few you know components we need to add on this just like we've done for all of the islanders so we've got our sprite renderer that's good we need a box glider 2d we can uh handle a collision and this is a very minor thing but it's somewhat important we want to change the size here we just want to reduce this ever so slightly like for for example just like 0.99 the reason for this is because you're gonna have a bunch of these segments kind of lined up one after another right and the the centipede can technically collide with itself so if you at some point the centipede will break apart and there'll be multiple of them kind of moving around if they cloudy with people with one another it'll cause them to move to the next row and inverse their direction and so on and so we don't want these segments to trigger the collision um and so if they're both at one they're technically you know let's assume once again these are all on a grid these technically will be touching each other right they're technically touching each other which might trigger that collision code let's just set these to 0.99 just to guarantee they're not truly touching one another it's also not um like we could make this even lower if we wanted to but we don't want to make it too low otherwise the bullet itself will be able to fit in between the segments so we don't want that so maybe you know 975 or something it doesn't really matter just so long as they're not actually touching one another all right so we have our segment here box glider we do need a script as well let's go ahead and just create a script for centipede segment and let's go ahead and attach that script to our game object here and i think that's it for now we can just drag this into our scene to or not interesting from our scene into our prefabs folder to create a new prefab so we're good to go there now we can delete it from our scene now that we have this asset we can always re re-add those all right so next we want to actually let's just focus on spawning the centipede and then we can do the movement after let's create a new script for the centipede as a whole but kind of similar to the mushrooms we have a script for each individual segment and then we're gonna have another script to kind of manage it as a whole and let's go ahead and open up the script so here let's start with a clean slate here delete all that and the first thing we want to do is add various properties or variables here we want one for our prefab so just like we did for the mushroom field let's add our centipede segment i'm just going to call this prefab or maybe i'll call it segment prefab a little bit more specific um what else we need to have a list we need to create a list so we can store all of the segments in the list to create a list we need to import using system.collections.generic then we can declare a list here so list we have to specialize or specify what type of list it is it's gonna be a list of centipede segments i'll just call the segments we can actually initialize it right here too so new list same type empty parentheses [Music] what else do we need we need probably a reference to our two sprites our body sprite and our head sprite that way we can assign reassign the sprite accordingly based on where in the centipede the segment is let's create some variables for our head sprite and our body sprite um what else for spawning purposes maybe that's it for now i think all the other things will be for movement so i think this is good for now let's go ahead and add a start function and inside of our start function we can call let's say a respawn function so let's add another function called respawn and here we'll call that later on we will call this in other places as well but initially when the script starts we'll respawn our centipede when we respawn the centipede one thing we want to do is we want to clear out our list and destroy all the existing segments so we're starting fresh so for a list we can say for each centipede segment segment in segments so in our list so for each segment in our list we will destroy the object segment dot game object make sure you say dot game object because if you just say segment it's just destroying the script it's not destroying the game object as a whole dot game object and then we can clear our list segments dot clear that way we're starting fresh and now we can instantiate our new segments so this is where it's similar to our mushroom field we can loop oh that's one property we are missing we should specify like what is the size of our centipede so we can add a public integer maybe call the size i'm gonna maybe default it to 12. feel free to customize that to your preference so here we can say for n i equals zero i is less than the size i plus plus and for each for each um loop here each iteration of our loop we want to instantiate a new segment add it to our list and position it accordingly so let's first just get it instantiated because the positioning is a little bit more complicated so segment here is going to equal the output of our instantiate function in our mushroom field we didn't need to actually this you know this function actually returns the object you're instantiating we didn't need to do anything in our mushroom field because we're not really tracking them in a list or anything but in here we are so we need to actually assign the result of this to some variable instantiate our segment prefab and then we can add that to our list so we can say segments dot add segment and that's good for now we just need to pass in the other parameters here for position and rotation so let's calculate our position it's going to be a vector 2. and there's a little bit of math we need to do here so really we should spawn this wherever the parent [Music] kind of uh wherever the parent's centipede is like it's going to spawn in that position so just wherever this object is it's going to start here then we need to offset it to the left or right each segment will be offset to the left right by essentially whatever the index is for example we can say vector2 vector2 dot left times i and we should put this in parentheses here for order of operations i guess that we don't technically need it but um so what this is doing essentially is saying if i zero then zero times well left is you know negative one in the x so it's not it's gonna offset it by zero when i is one that's gonna offset it by negative one when i is two it's gonna offset it by negative two three negative three etcetera so it's going to offset each segment kind of one after another initially wherever our position is here now this is yelling at me because i'm trying to add a vector 3 and a vector 2 together which it doesn't like there's actually one more thing i want to do this anyways this position here just to be safe i want to make sure that this position is aligned to the grid so i can i'm going to write just a little utility function that's going to round this position to the nearest whole values that way it's always kind of um it's always properly aligned on our grid let's create a little util function we're gonna return a vector to i'm gonna call our function here grid position it's going to take in a position and it's going to return it so we're going to take in a vector 2 and it's going to return a new vector too so all i'm going to do is i'm going to round this to the nearest whole value position.x same thing for y math.round alright so i'm taking the this position i'm rounding it to the nearest whole value and then i can just return it back again so now here i can say grid position transformed up there's just a little utility function to just guarantee that this position is aligned to a grid and then it also just happens to get rid of that error because i'm returning a vector 2 so i'm adding a vector 2 plus another vector 2 and there's no error there so finally we can pass this position into our instantiate function rotation we don't care about so we need to set that to identity and we're good to go there so let's test this out i know that was kind of a lot um once again this centipede is going to be the most complicated part of our project here we actually need to add our centipede to our scene here so let's create an empty object let's reset the transform i'm going to call this centipede i'm going to add our main centipede script to this and now i need to assign all these various properties let's assign our segment to there let's assign our sprites so head sprite body sprite and size initially is 12 so that's all good um i want to spawn the centipede towards the top so let's just say at a position of 20. that actually sort of wants to be right on the we're on the edge there so 20 and we should be good let's run it and see what happens perfect so it spawns right at the top and once again each segment is offset one by one by one by one the only thing missing here is our very first segment in here needs to change its sprite to be able to set the sprite on each segment we need to start to build out our centipede segment script a little bit more so let's go ahead and open this up start with a clean slate here and i need to get a reference to the sprite render on this segment that way i can update the sprite accordingly let's go ahead and add this and actually i'm going to make this it's going to be a little bit different than any of the other variables we add i'm going to make it public i'm going to say it get private set so what this is doing is it's creating a property that has a public getter and a private setter so that means i'll be able to access this variable from other scripts but i won't be able to assign this variable from another script and we can assign this in our awake function just like we've been doing for everything else sprite render equals git component sprite renderer and so now i can actually assign i can access this from our other script here so when we create our segment i can say segment dot sprite render dot sprite equals and i can either choose header body the head will always be the first one so if i equals if i equals zero we're going to use our head spray otherwise we'll use the body spray this syntax here is called a ternary statement it's kind of like writing an if statement where you have a condition here that you're evaluating to true or false if this evaluates to true it uses this value if this evaluates to false it uses this value this is uh called the ternary statement i equals zero we use head otherwise we use body let's test that out and we should already have our script on our prefab yeah so we have our segment script on our prefab make sure that that's there there we go so now we've got the head and then all the body follow that's good we need to put a little bit more structure in place before we can start to handle the centipedes movement let's go to our centipede segment script and one of the things we need to do is for each segment to track which segment is ahead of it and which segment is behind it this is essentially like a doubly linked list for any of you programmers out there who are familiar with that data structure this is sort of like a doubly linked list it's we're not actually going to use a linked list here but we're going to kind of follow that same general pattern where we have different nodes in each of our segments and each segment contracts what's ahead of it what's behind it that way we can always traverse through the entire centipede if we need to as well as handle other things so let's go ahead and create some new variables in here and we actually want to make these we're going to do something very similar to this so we're going to make these public i'm going to call these centipedes segment let's name this one ahead and this will be a get set so it's a fully public property public editor public setter i don't want to just do this though because then this will show up in the editor because you're not we're not actually assigning this in the editor i just want to be able to get it and set it from our other script here so there's better encapsulation practices you could follow here but there's no real benefit in our case so get set same thing so head in behind g segment it's going to track which one's ahead of it which one's behind it and one way we can know if this segment is the head is if the one ahead of it is null if there is nothing ahead of it well that must mean that this is the head segment we might want to have a little property there to determine that so we can have a public bool is head i'm going to use write a little arrow here so equal sign with the right kind of carrot and this would say ahead equals no equals equals null so now i can always check you know if is head i can execute some logic the the way the segments will they'll be different logic whether it's a head or not a head so we kind of want this little utility property in here and finally i probably also want one more one more uh property to track the centipede itself that way i can communicate back to the centipede as a whole to say oh hey like this segment was destroyed um you know this seg this segment was destroyed and then the centipede since it's tracking the full list of segments it can update them and do things as needed a bunch of properties in here we need to assign all these programmatically so for a centipede that one's easy because we can just assign it whenever our segment is instantiated so we can say segment dot centipede equals this because this is i'm inside the centipede script right now so this is referring to to that same type or the ahead and behind after we've instantiated everything we actually want to loop through everything one more time that way we can we can assign all those values so let's loop through everything one more time for inch i equals zero i is less than let's say segments dot length segments uh or accounts i'm sorry segments that count i plus plus here let's get a reference to these segments at that index segments i and now we can assign the heading behind um let's create a little utility function for this so let's say this function is going to return a segment and we say get segment at some index here and this is going to first let's check that the index is not out of bounds if the index is or we should check if it is in bounds so if it's greater than or equal to zero and it is less than segments.count we know that this index is within the within bounds so we can access our list and return the segment at that index if this index is out of bounds well then we need to return null so it doesn't cause an error if we try to access an index that's out of bounds we'll get a exception that's going to cause an error now finally here we can say segment dot ahead equals get segment at index i minus one and [Music] segment dot behind equals get segment at i plus one perfect right so behind is or a head is actually the one that's in front of like in the list it's the one in front of you and then behind is the one that's the next in the in our list so there we go so now we're assigning all of these different properties here and this will be needed as we start to build out the movement of our script a little bit more all right let's actually start to work on our centipede movement now which is going to be the the hardest part of this so at any point any segment could be a head segment or a body segment because as you shoot a dart at the centipede it's gonna break into two and then you could break it into three and then you can break it into four so there could be four in there can be x amount of independently moving centipedes and so that's where it gets a little bit tricky for movement purposes i found the best way to do this is for each segment to sort of calculate a target position and then we just simply need to always move towards that target position and that target position will be calculated differently whether you're a head segment or a body segment for body it's pretty easy basically the target position is just this position of the segment in front of you the headache it's a little bit more complicated but we'll break it down into sort of those two different steps so let's add some variables here let's have one for our um our target position that i mentioned this will be a vector 2. we also need a variable to track our direction the direction that this segment is moving and initially let's say it's going to be moving to the right and it's going to be moving down so we're not going to just say like position plus equals direction this is more so like just keeping track of i i wanna kind of independently am i moving left or right and then for the other axis am i moving up or down the way we actually move the segment itself will be a little bit different but we still need to keep track of the general direction it's moving so direction target position now as soon as the segment sort of spawns i guess we want to assign our target position just to be its current position so we can say target position equals transform that position [Music] all right now let's add our update function so our update function is going to get called automatically by unity every single frame and this is where we'll actually do the movement and so let's actually just write the movement cut itself because that's pretty straightforward the hard part is going to be how we actually calculate this value here let's assume that this value is assigned and let's just update the position of our segment so let's start with our current position let me transform that position then let's go ahead and we can say uh transform that position equals vector 2 dot move towards and then we can say current position right so we need to pass in the current and move towards a target so obviously our target position that we have and then the max distance delta is essentially like sort of like a speed you can it's essentially like your speed um like it can only move this amount per frame that's basically speed we actually haven't created any speed variables yet so we can go ahead and do that and i'm actually going to create that speed variable in our main centipede script because i want the entire centipede to move at the same speed you i guess you could if you really wanted you could have each segment move at different speeds but that would it would then the 7p wouldn't really stay together as a whole i'm gonna kind of create a new variable here for speed this will be a float let's say maybe initially the speed is just one and we can update that in the in the editor as we need to now for speed here we want to say centipede dot speed times time dot delta time we want this to happen over time um just because this whole line of code is pretty long i'm just going to put this into its own variable just to improve the readability a little bit here let's do this just to shorten this line of code a little bit it's still fairly long but so we're going to update our position to move towards the target position at some speed speed it will be defined in our centipede and we are moving towards that position over time so time to delta time all right next we also want to set the rotation of our segments based on the direction we're moving so there's just a little bit of math here we can say um the well let's take a look at what's the direction from our current position to the target position we can get a vector to indicate the direction there this is like the overall direction that the segment is moving but from you know its current position to the very next target position whatever that next grid position is what's the vector there and so to do that let's just call this like movement direction we just subtract target position minus current position and then we do want to normalize this let's wrap that in parentheses and then say normalized that way it always has a magnitude of one from here from this vector we can actually calculate an angle so this is a pretty neat function this is i believe this is trigonometry if i'm not mistaken mathf.a tan 2 we got to pass in a y and an x here and so this is just our vector so movement direction y movement direction x is going to calculate the angle of this vector and then we can essentially set our rotation of our segment based on that angle now rotations are are defined as quaternions which is a kind of a more complex math math concept that i'm not going to get into but there is a function on quaternion that angle axis so it's up this creates a quaternion given an angle in a given axis angle axis the angle of course is that angle that we just calculated and the axis is the um well also this angle though we need to convert to degrees uh this a tan returns it in radians and this function takes degrees angle axis takes degrees so we need to convert that that's pretty simple we just say math f that red two degrees radians two degrees our axis here is just basically the axis we want to rotate on and we want to rotate on the z-axis so the z-axis can simply be written as vector three dot forward zero x zero y one into z so that will rotate on our z-axis so that's gonna make sure that the segment is always rotated to the direction you're moving this is a pretty minor thing overall you might not even notice it if it wasn't here but it is pretty nice so that's the actual like movements and rotation of our segment but what's missing is we still haven't calculated what this actual target position is so that's next so to calculate our target position we need different logic based on the head if it's the head piece or the body piece let's go ahead and create two separate functions for each of those let's call one maybe update head segment and let's call one update body segment and for our head segment here anytime our anytime we reach our target position we're gonna re-update it recalculate the new target position right and so the one way we can do this is to check the distance between our current position and our target position and if that is you know close enough well then we know we've basically reached our target position and we should then calculate the next one and we're only going to do that for the head piece because the headpiece will then inform the body pieces to update their positions as well so at the very top of our update function we want to do it before we actually apply movement because ultimately we want to calculate the target position first we once again we only want to do this if it's the head piece we're going to say if is head from this property we created earlier and if the distance vector2.distance between a and b so a is going to be our current position b is going to be our current target position if let's say that's like less than 0.1 so if you're basically you're very close to reaching we don't want to say zero because it you it not it might not always be exactly zero so just to be safe we'll give a little bit of a buffer there but if you're basically very close to the target position we're gonna then calculate the next target position so this is where we'll call update head segment now within these functions um we're going to handle the logic to actually calculate that um to calculate that target position but before we do that i want to finish getting the structure in place after calculating that new target position we want to update the the next segment in our centipede so i can say if behind does not equal null then we can update that one and we know this we know the one behind it is always going to be a body piece if this is the head one so i can say update body segment then same thing here once that segment gets updated it needs to tell the next segments behind it to also update so it's going to kind of traverse through the whole thing the reason we check for null is because once you're at the tail there won't be any more segment behind it and so it'll stop at that point this looks good that's the structure now we actually just need to calculate the target positions let's start with the body one because it's a lot simpler really all we need to do is say target position equals the same we want to move to wherever the piece ahead of it is is where each body piece sort of follows the one ahead of it so we're just going to say a head dot transform a position the only thing we need to do is we do always want to make sure our target positions are aligned to the grid right so the transform position will not always be perfect whole values these need to be our target position needs to be nice whole values so we just need to round all of this to do it to the grid which we already have a function for that in our other centipede script and go ahead and maybe just copy this over and then we can call this here so so we're just rounding it all to a line to the grid and we're good there the only other thing we want to do is we want to make sure our direction is is is being updated as well to whatever the one ahead of it is that way eventually if the segment you know the centipede splits out into two different ones um the direction's not going to be completely invalid because it was never being updated we're just going to say direction equals ahead that direction just directly copy that over that's it that's all we need to do for our body one that one's pretty straightforward the head one will be a little bit more complicated so initially for the head segment we need to see where it's at on the grid currently so let's have a vector 2 called grid position let's call this grid we're going to call our utility function here and we're going to pass in our current position we're going to round our current position to the grid and our target position is always going to be our current grid position but then we're going to update it in the x-axis whichever direction we're moving right so target position.x plus equals direction.x so we take our current grid position if we're moving to the right well then the target position is one to the right and so on or to the left right obviously there's going to be more we need to do here but let's initially test this out oh and also i noticed our speed here is only set to one um we probably should have maybe set this to let's say 20 i could i can also change the default here i guess i don't need to change the default because that's the whole point of making it public so you can just change it in the editor but i'm going to default that to 20 make sure it's set there let's test this out perfect so everything's moving in uniform with one another obviously it doesn't recognize the barriers or anything like that but at least we have some some movement in place we can continue to build off of this now we need to handle the collision on our centipede let's go back to our centipede segment script we need to add a little bit more logic our update head segment here so after we calculate this target position we need to check if that's a valid position we need to check if there is a mushroom at that position or if there's a barrier there and if there is we need to reverse the direction and then start to advance to the next row we can do this by saying if physics 2d dot overlapped box this is going to let us know if there is a collider at some point we can say our position here we want to check at the target position if it's if there's a clutter there some you know mushroom or barrier or something the size here doesn't actually matter we can just say zero because we just care about that point in space when we're not trying to really you know actually like a box per se angle can be zero we don't need it to be rotated we do need a layer mask here this is how you can specify which layers are we checking for so in other words what are the layers that the centipede can collide with let's go ahead and add this layer mask to our centipede script i can add a new variable here called layer mask i'm going to call this collision mask once again this is going to indicate which layers the centipede can collide with we can pass that in here centipede collision mask so if there is something where you can collide with at this target position well that's it's not a valid position and so we need to change it um first though we need to reverse the direction we can say direction.x equals negative direction.x so once it advances to the next row it'll start to move in the opposite direction we need to reassign our target position now it's just going to be our current grid position dot x and then the y is going to be the row you know the next row so target position.y equals grid position.y plus direction.y so whichever vertical direction we're moving in we will advance to that new row and there will be some logic to check if we're within the home area or not but for now this is good go ahead and try this out we do need to assign our collision mask though so let's go ahead and update this the cenobe should be able to collide with barriers should be able to collide with mushrooms and also with other centipedes as well but we don't have those other layers so let's go ahead and add those let's go to our mushroom prefab let's add a new layer here i'm gonna create a layer for mushroom as well as for centipede let's assign these so mushroom we're assigned to mushroom centipede segment we're going to assign to centipede and let's go back to our collision mask and assign all of these that looks good barrier mushroom and centipede those are the only things the centipede is looking for in order for it to change its movement direction let's go ahead and test this out now it hits the barrier and it moves to the next row it's going to hit a mushroom it moves to the next row so all that looks perfect but i'll just continue to traverse all the way down let's speed up its speed or change its speed so we can see if it gets all the way to the bottom perfect now once it gets to the bottom it continues going because we haven't written the code yet to handle it's reversing the vertical direction [Music] to do this we should start by creating a new invisible collider to represent the area of the home the home area so very similar to kind of how we created some of these other barriers but or to our field i should say we kind of have this box collider that just represents the bounds of the mushroom field we can do the same thing for our home area i'm gonna create an empty game object in our scene let's call this home reset the transform i'm going to add a box collider 2d we're going to mark it as a trigger because we don't actually want anything to physically collide with this and now we can adjust the position here so size 50 um and the x just to make sure it covers the whole area maybe the foam um maybe or vertically it's maybe y and then we can reposition this as needed so make sure this is aligned properly to the grid area so maybe negative 14 we don't actually necessarily need it to go all the way to the very bottom of the of the board that way the player does still have somewhat of a safe area i guess it's up to you you can customize that how you want let's see how it lines up with our other um with our other barriers we had this barrier here so these two yeah so these two should kind of line up a little bit better i think this is too big let's maybe reduce this to eight yeah there we go so that actually works we want we want the home one to be like halfway inside there um like it doesn't have to be but that should that should work pretty well cool yeah then now there's the space at the bottom where the player can still can still be safe so that should be good but obviously feel free to adjust that to your preference all right so let's go back to our centipede script and let's add a um let's add a variable so we can keep track of that uh keep track of that so this would be a box collider 2d we're going to call this the home area and let's rearrange those or organize those and let's go ahead and assign that now centipede yes let's drag in our home area there cool now we can go back to our centipede segment script and we can finish the remainder of our logic here so after we set our new target position we need to verify that that new target position is not outside of the bounds of our uh home well depending on the direction we're moving so first let's get the bounds of our home um homebounds equals centipede.home area.bounds and so if we're moving down and we're moving down if y is one then we need to check have we moved past is this target position below the maximum so if the target position is below this area then we are it needs to start going up we need to reverse the y direction start moving up again this bottom part is max the top is min so here we can say direction is one so that means we're moving down and the target position dot y is greater than homebounds dot max dot y that means we're gonna reverse direction so direction is going to be negative or direction.y is negative direction not y so same as this really but just for direction now and our target position dot y needs to get reassigned to grid position dot y plus directional y so same thing as this just in the in the y axis right it is the exact same thing we're just reassigning that now that the direction is changing now we also need to do the same same thing if we are moving up and we are outside of the min um so which would be above it so we can say or we can wrap this entire thing in parentheses that's like one thing and or we can kind of do the same thing here so another set of parentheses direction dot y equals negative one so it means we're moving up and the target position dot y is less than homebounds.min.y so if we're gone past it or we've gone you know above it then we will reverse the direction so this will guarantee we stay within the home bounds upon reaching it i think that's it i think that's all that remains for our um centipede movement so let's go ahead and test this out we already assigned our home area so we should be good let's just go ahead and test it and i'm gonna increase the speed so to save some time here and i'll slow it down once it gets further okay so great we've hit the bottom yep and now it's going up again and then and we can see so boom it moves here let me move my blaster out of the way yeah perfect so as soon as we hit to that last one then it try it it can't go any further so it goes back up and in this case it's actually really interesting because it sort of gets stuck here where you know just the layout the particular layout of these mushrooms makes it so it needs to actually just go back back down again so that all looks great so movement is all good next we need to handle splitting the centipede into multiple centipedes whenever it collides with a dart let's go ahead and go to our centipede segment script and let's add a function to check for collision so this will look just the same as the other ones we've done on collision enter 2d fix in a collision 2d object make sure not to confuse this with collider 2d hp collision 2d here we can check if we specifically have collided with the dart by looking at the layer just like we did for one of our other scripts so if collision.gameobject.layer equals layer mask name to layer dart well now we know we've collided with the dart and we should remove this segment from our centipede so we need to do a number of things in this script so let's go ahead and add a new function here i'm going to make this public because i need to be able to x to be able to call it from an external class from a different class i'm going to call this maybe remove pass in the segment where we want to remove and then we can call that here so we can say um entropy.remove this so we're removing this segment from the centipede in here there's a few things we want to do um so first we actually want to instantiate a mushroom um at the same position of our segment so this basically the segment sort of gets replaced with a mushroom so we need a reference to our mushroom prefabs let's go ahead and add that mushroom mushroom prefab here and we can instantiate this so we say mushroom prefab we need a position here um maybe we say mushroom position or disposition i guess [Music] this will be the same position of our segment although we want to make sure it's aligned to the grid so let's wrap this in grid position here so it rounds everything pass that in rotation we don't care about so we can just say i quality identity that's good we're instantiating a new mushroom at that same position of our segment then we need to remove our segment from the list so segments dot remove segment and then we can destroy this segment itself destroy segment dot game object make sure you say game object not just the script and there's actually a couple more things we want to do so we want to re-link these other segments so let's say for example let's say these circles here are different segments maybe you're destroying this middle one here this one is going to get destroyed well when this gets destroyed you know it's going to change like let's say this is moving to the right as well so this will get replaced with a mushroom this one now becomes the new head and then there's nothing ahead of it anymore because the one that was ahead is now destroyed and then same thing for the one here the one that was behind it well it's destroyed it's no longer no longer exists so we need to null these out for the respective ones so we can say if the segment ahead of the one being destroyed is not null well then we can reassign the one behind so the one ahead the one behind of the one ahead is the one being destroyed we null it out and then same thing in the opposite direction if the one behind is not null then the one behind the one that's ahead of the one behind is the one being destroyed so we know that out sorry if that's confusing um but yeah we just need to reassign those that way because remember we have this little property here that says this is considered the head segment if there's nothing ahead of it and so by nulling this out it's now going to consider that one to be another head right because now this these become like two independent these will become two independent cent beads it splits it now they're two completely independent centipedes and instead there's a mushroom here now now the other thing is because there's a mushroom here it should hit it and then you know reverse direction so these these two will kind of split apart and move at their own in their own direction do we really we should just call recall or update head segment so it resets the target position it it'll indicate oh there's a there's a mushroom there you know then it'll reverse it and everything so we just need to call that function segment that behind segment.behind.updatehead segment um i get an error here because this is private so i need to make this public now and that should handle making sure that it it goes in a new direction once it kind of splits apart so a lot of times it will do that anyways but just in case um we'll do that i think that's all we need um i think that's it let's go ahead and test this out oh you know what yeah well let's test it out first um we do need to make sure we assign our mushroom prefab now that we added that let's drag that in and then let's run this shoot one of these there it goes it splits out a mushroom spawned it split and the two the two splits kind of went in their own direction now we got three of them moving all at the same time now here's a there's a couple problems i see um one is the new segments the head the head sprites aren't being assigned so that's a problem and so let's go ahead and um go to our centipede script and we need to reassign this one because this one's now ahead so we can say behind dot sprite render sprite equals head sprite and becomes the new heads we assign the sprite there that looks good and let's see so that's one problem fixed the other problem it's a subtle one it's not even necessarily a problem but let's say you had two segments here obviously right next to each other of course um i'm just illustrating this one it's not gonna be perfect but let's say your dart hits these for right in the middle where technically it's colliding with both it would actually destroy both which maybe is fine but it happens kind of a lot and i don't really like it feels like you're able to destroy the centipede way too quickly because it's essentially destroying multiple at the same time so there's a little a little bit of a hack we can do to fix this let's go to our centipede segment script here when we check for collision we can sort of check to see we can do some stuff in here to make sure that this logic of removing the segment will only happen for one if it does indeed collide with multiple um so what we can do is we can disable the collider on our dart immediately so collision dot collider is referring to the darts glider in this case we can disable this immediately as soon as it collides with one of the segments and then we can add another condition to our if statement here to say we're only going to run this if the collider is enabled all right so if collision.clatter.enabled and it's the dart then we'll remove it so essentially if this were to be called multiple times within the same frame for the first one it's going to be enabled and so it'll it'll go through it'll remove that segment but then the dart gets disabled and so then when this code gets executed for the second one it collided with well now it's considered disabled and so it won't remove the second one so it's just sort of a forcing it to make sure it only removes one at a time just in a scenario where it technically collides with multiple in the exact same at the exact same time a little bit of a hack it's not even necessarily a problem but personally i feel like that improves the gameplay a little bit so um and the thing is the the dark collider is going to get disabled anyways so um because that just with the script or the code we wrote earlier for the dart it gets disabled anyways when it collides with something so this doesn't really cause any issues all right let's just do one final test but i think we're i think we're already good here let's make sure the sprites are being updated yeah so i already saw so there now we've got the head spread is being reassigned and yep now and now in this case it's just a head completely by itself that's totally fine so this all looks great so we've got multiple segments that all can kind of move independently of one another and perfect everything's good there all right at this point we basically have a working game and centipede we just sort of need to tie everything together with some scoring some lives some ui things like that let's start by creating a game manager that can manage all of those things a new c sharp script here called game manager i'm going to create an empty object in our scene call this game manager i'm going to drag this on there let's reset the transformer that doesn't really matter move this to the top here let's edit the script let's clear everything refresh here so we're going to somewhat implement a singleton design pattern here which will allow us to access our game manager from any other class and with a singleton it also implies there is only a single instance of our game manager that we can then access anywhere so to do that we need to declare a static variable our game manager here is going to manage it's like it's going to keep a reference to itself statically and we'll call this instance and this will be a better with a private setter [Music] so because this is static we can access it from any we can access it from any class without needing a specific instance we can we can just access this from the class itself and so here when our game manager is initialized we need to assign this here but we only want to assign it if it's null if an instance doesn't already exist well then this becomes the instance our souls in a single instance if an instance already does exist well we shouldn't be creating another one so we can just destroy the game object that is being the the second instance that's being created that won't actually happen but once again for a proper singleton you would want to make sure you can't ever instantiate more than one um and then whenever an instance of the game manager is destroyed or any game object is destroyed unity calls on destroy for for that object and so here we can say if the instance is this well then we should clear it out we should know it so that way the next time another one gets initialized we can reassign it again so this is a very simple version of a singleton there's normally more you need to do so for for some games this isn't enough and there could potentially be problems you run into but for our purposes here this is plenty fine so let's finish creating the rest of the structure of our game manager um so the other thing we want to do is just keep a reference keep track of a number of references to some of our important game objects like our blaster for example we want a reference to that we want a reference to our centipede we need a reference to our mushroom field um we'll call this um mushroom mushroom field um we also need like score and lives as well at least for now this should be good and then let's create all the various functions we will need but we'll implement them individually so first let's add our start function so this is going to be called by unity the very first frame our game manager runs when we start we should start well we should assign all those references so we can find them in our scene we can't use git component here because these these references aren't components of our game manager they're just other objects in our scenes we can say find objective type same thing for the others find object of type centipede mushroom field an object of type mushroom field mushroom field and then let's create the various functions that we'll need to manage the state of our game so there'll be a new game function and we'll we'll come back to implementing this there'll be a game over function there will be a reset round function so when you die we should reset the rounds and then there should be a next level function i guess we can call it those are kind of some of the main functions that'll that'll happen or different events that'll happen when the game changes states so [Music] the only thing i think we can do now is we can say new game here so we can call new game when it first starts but the rest of this will start to implement these one by one all right let's start with our new game function here whenever a new game starts there's a number of things we need to do we should reset our score to zero we should reset our lives to whatever you want the initial amount of lives to be let's say three we should respawn our other objects our blaster centipede we should regenerate our mushroom field for the centipede we already have a respawn function just make sure it's public so you can access it from our game manager well that is already in place which is good our blaster we don't have a respawn function so let's add one to this add a public respawn function here really we just need to reassign the transform position um but we need to know what the initial spawn position is so let's create a variable for that called spawn position we will assign this initially when the blaster is initialized to whatever its current position is and then here we'll do the opposite of that where we'll reset the transform position to the spawn position the other the only other thing we probably want to do is make sure our object is active so set active to true um i can't type set active to true this will make sure our blaster is activated again because when we lose we'll probably deactivate it so that's all we need for that so let's respawn our blaster and then we need to clear and regenerate our mushroom field as well so for this we should probably keep track of a list of our mushrooms we can destroy them but why don't we add a list of mushrooms here let's import systemcollections.generic so we can declare a list here maybe a list of mushroom we'll just simply call this mushrooms um i can initialize this in our awake function to a new list new empty list when we generate a mushroom we need to add it to that list so here we need to actually get a reference to the object being instantiated and add it to our list and then we should probably add a new function for clearing our mushroom field in which case we will loop through each of the mushrooms in our in our list and we will destroy all of these game objects make sure you say game object otherwise you would just be destroying the script itself which is not enough i'm gonna destroy the full game object and then we can clear our list off mushrooms so it's empty again so these two functions now we can call from our game manager make sure they're both public we can call them from our game manager so here we can say mushroom field clear mushroom field generates i think we're good there cool oh and also now that we're doing all this from the game manager we don't need our start function in here because the game manager is going to handle doing all this so we can actually get rid of start same thing in our so our blaster is good the same thing in our centipede though we don't need to call respawn from our centipede script anymore because the game manager is gonna then call this whenever the game starts or whenever a new game happens so let's just verify that that works we run our game and yep centipede respawns everything responds so we're good there all right let's handle the next function which will be game over so this is sort of the opposite here really all we need to do when you get a game over is disable the blaster so the player can't move around or anything so we can just say blaster game object set active defaults and then we'll probably do some ui stuff later but we'll treat the ui as its own section um so we'll come back to this but we need the ability to reset the game when you do have a game over and so maybe for example you get a game over it displays stream ui which we'll get to and then you can press any key to reset the game to play again so we can check for input um so to do that we need our update function we can check for input here we only want to check for this input if um if you're out alive so if you have a game over if our lives is less than or equal to zero and they let's say we can actually do any key down so if they press literally any key we can call new game again that one's pretty straightforward game over we disable the blaster we will then check for input to see if we should start a new game in which case the blaster and everything gets respawned remember the blaster is going to set this to be active again and that's really it that's all we need for that all right let's do our reset round function next so here when we you reset round this will be handled when the player loses a life so when the centipede collides with our um collides with the player then we will reset the round so actually let's go ahead and check for that collision first so let's go to our centipede segment we already have our on collision enter function here let's just check for collision between the centipede and the player so instead of we can just use the same code here instead of checking for dart though we will check for player instead if we collide with the player then we will call that reset round function on our game manager so this is where i can access the instance of our game manager from anywhere and i can say reset round here now this function is private so it's giving me an error so i need to make sure this is public so i can access it from from here and then we're we're good to go and just in case so it doesn't execute any other logic beyond this i will return okay so in reset round we want to decrement the number of lives so that will get decreased by one if the lives is z less than or equal to zero that means you've gotten a game over and then we can return because we don't want to execute any other logic in this function if you haven't run out of lives well we need to respawn the centipede we need to respawn the blaster and then we should we could regenerate the mushroom field but we don't it actually in the real game i believe it just heals all the mushrooms instead of regenerating them that way it feels like the same round because if you regenerate them it's going to feel like an entirely like like new level almost if we just heal them they maintain their same positions and everything and they'll feel like you're just resetting that same exact round we need the ability to heal our mushrooms why don't we go to our mushroom field actually let's first go to our mushroom script itself we should probably have a function on here to heal a mushroom this will be a public function called heal we're going to reset the health back to the max so remember if you have let's say four sprites that that four different states for your mushroom well then the max health you can have is four so we just reset that and then we just need to update the sprite sprite again and this one's easy because it'll always be the first sprite so index zero is always the first one in the array there that's good now we need to be able to loop through all of the mushrooms and call this function so we can go to our mushroom field script we can add another function here called heal and instead of we can loop through everything but instead of destroying them we will just call heal that looks good and then let's go back to our game manager so here we can say mushroom field.heal now we'll loop through everything it'll heal them all and i think we're good there but let's test this out let's test this out [Music] let's run this i'm going to speed up my um i'm gonna speed up my centipede here to make this go a little bit quicker [Music] let me get hit by this there we go so i should have lost the life if we go to our game manager we can switch to the debug mode where we can see some of those private variables so we have lives is out too that looks good let's test out that we get a game over [Music] there we go i got hit again so i have one life left yeah what lies is one perfect let's get one more time here um let's speed this up [Music] perfect there we go so the blaster completely disappeared now because it's got disabled we can see that in our scene here it's completely disabled this thing or the centipede still moves which is totally fine um that was intentional i wanted it to do that and yeah this is obviously we would display some game over ui and stuff but we'll get to that oh yeah and then i just clicked so i just pressed an input and it restarted i respond centipede respond i should have three lives again yeah so the whole game the game started over again that's all working correctly i just noticed a problem as soon as i finished recording that last segment so let's go ahead and fix something real quick let me show you what happens when we if we destroy some of the mushrooms and then we the round is reset we're going to get an error i didn't catch it the first time because i hadn't destroyed any of the mushrooms when i reset the round so let's get one of these centipedes to hit me and we're gonna get an error [Music] hit me please so yeah so we get a null reference or a missing reference exception um the object of type sprite render has been destroyed but you're still trying to access it it's trying to access the sprite render on one of the mushrooms but it's been destroyed because we killed the mushroom you can actually see the full stack trace here it happens when we try to heal everything right so we collide with the segment it resets the round that tells all of the mushrooms to heal and then when we call the heel function on our mushroom it's it's not able to access that right render because well it's been destroyed that's a problem and that's because in our mushroom script we destroy some of these but after destroying them we never go and update our list here we don't ever update our list and so our list is keeping track of some destroyed objects and then we're still trying to heal them so that's that's not no good so to simplify this what we can do let's actually get rid of the list we don't need it there'll be an easier way to handle this get rid of the list i'm just deleting we don't need that import we don't need the list we don't need to initialize it we don't need to add it here we can just simply instantiate this is kind of going back to how we originally had it all we need to do instead now is get a reference to all the active mushrooms in the scene via find objects of type so this is going to look in our scene for all the objects that for all of our mushrooms the ones that are destroyed well they're destroyed they don't exist anymore so it's not going to find those and so now when we loop through everything we're just looping through only the ones that are actually that actually exist we don't need this line of code anymore same thing here we can copy this same line of code here we're gonna find all the alive mushrooms in our scene we'll loop through those and we'll heal those any ones that have been destroyed we don't care about anymore so that should fix our problem let's go ahead and test it out real quick let's destroy some of these mushrooms let's keep a couple of them at lower health as well so we test that there are getting healed um i need to let the centipede actually hit me so let's increase the speed here [Music] and there we go so yep no error those other ones got healed everything responds we're good now we fixed that problem next let's handle advancing to the next level whenever the player kills all of the segments in the centipede now this is not a fully complete version of centipede so our next level here is going to be somewhat simple but i can at least show you how to get this in place and then i would challenge you to see how you can add more to the game to really make each level feel unique so let's go to our centipedes or just our centipede script here and in the remove segment function we should check after we've removed and destroyed that segment are there any remaining in our list if the count is zero well that means you've killed them all and so we should we should uh call our next level function on our game manager so you can say gamemanager.instance.nextlevel here and make sure this is public that way you can access it from from this other script and so when we advance to the next level really all i care to do for now once again from this is a simplified version of the game i'm going to increase the speed of the centipede that way it gets progressively harder and harder as you continue to play i can say centipede speed maybe times equal maybe 1.1 which is 10 so it's gonna get 10 faster each time [Music] you can obviously change that or do whatever you want but and then of course i need to respawn the centipede since you killed it we could respawn the blaster but i don't think we necessarily need to we could also re re-generate the mushroom field but in the original game they don't do that they the mushrooms kind of stay how they are um there are other objects in the scene like there's a spider and other things that generate new mushrooms [Music] and so just naturally over time more and more more and more mushrooms get spawned so even if you start to destroy them there's usually always mushrooms because of those other objects now we're not going to go that far with our game for this tutorial so maybe i should regenerate the mushroom field but it's up to you if you want to you can you can essentially call some of these same functions [Music] do whatever you want to obviously in the original game as well the whole color scheme of everything changes but for our purposes here this should should suffice so [Music] that's something that i really would challenge you to see how can you implement some of those other features of the game let me just test this real quick so i'm gonna increase the speed real quick oh no i want to actually kill the snake so i can um see that the speed changes let's set this back to the default of 20. it's actually trying to destroy it all [Music] a couple more segments here that one let's get that one it's hard because if you miss you sort of get penalized because then you have to wait for your bullet to or your dart to respawn um okay there we go so it respawned yeah the speed is now 22 so it's 10 faster and so as i continue to play it's gonna get harder and harder and harder mushrooms and everything stay exactly how they were which is which is once again what i intended it to do but feel free to customize that to your preference all right the only other thing we need to do is scoring so let's go ahead and do that let's add we have our score variable in our game manager we need to add some variables to our centipede and our mushroom to indicate how many points this is worth so we'll only start with our mushroom here we can add a variable for let's just say points and i think mushrooms are only worth one point since there's a bunch of them they're easy to destroy for our centipede i believe if it's a head it's worth 50 so let's say points head it's gonna be 50 points or 100 points i don't remember exactly what it is but feel free to customize doesn't really matter if it's a body piece i think it's worth 10 points and so we need to [Music] add a function to our game manager to increase the score so let's add another public function here called increase increase score by some amount and we'll update our score here so score plus equals amount and now we can se call that function so whenever you remove a segment same thing here where maybe this is the very first thing we do if the segment is the head well then we will say or i guess we're going to call that no matter what so we can use a ternary so we say game manager instance increase score and then if it's a head we will increase by the points of the head otherwise by the points of the body here so so once i'm using a ternary statement it's going to evaluate this to true or false if it's true it uses this value that's false it uses this value and you can customize the points in the editor to your preference you can also hard code them if you really want to it doesn't really matter too much that looks good now pretty much same thing for our mushroom whenever you damage the mushroom or whenever the mushroom gets fully destroyed we will um call to our i think it's when it gets destroyed maybe you could it it's up to you if you want to give the player one point every time they damage it you can just do it here instead but i'm gonna do it when it gets destroyed we will increase the score by however many points the mushroom is worth which i set it to one but you can customize this in the editor so cool this looks good um let's test that this works [Music] let's switch to debug mode so i can see my score since that's a private variable and let's destroy a mushroom here so yeah oh i must have accidentally destroyed yeah destroyed ahead so i got 100 points destroyed a few things on accident but yeah obviously my score is is changing so getting points for killing mushrooms for killing centipedes or yeah the second head segment so everything is working there in terms of score this looks great all right at this point all we have left to do is the ui for our game let's go ahead and throw that together real quick just to show you i'm not going to make it super pretty but i just want to show you how you can hook up ui for your game switch back to the normal mode here let's right-click in our hierarchy and go to ui and let's create a text component here it's going to create a canvas it's going to put that text as part of our canvas it also creates an event system which is used to handle like clicking buttons and things like that so for our text here you can see it's showing up there um let's start with our score text let's call a score i'm going to anchor it to the top of the screen so i'm going to go to this diagram here i'm going to anchor to the top and i'm going to set the y position to zero although i need to change the pivot as well set the pivot to one and then set the y to zero and now it is going to show at the very top of the screen let's center align it change the color to white let's um just initially set this to zero and i'll make it a little bit bigger as well that looks good that'll be our score let's duplicate this and add one for lives now this one i'm going to anchor to the right of the screen and this one i also want to set the pivot on the x to one and then set that this to zero we want it to be right aligned and i might want to offset this just a little bit from the edge of the screen so maybe like negative six or so maybe this one's slightly smaller in size oh we keep it it doesn't matter um and we might also want to display a little like blaster icon so we understand what this value is for [Music] so i can right click our canvas go to ui image and now i can assign the blaster to that i obviously definitely want to make this smaller so let's maybe say 16 by 16. we're gonna anchor this to the top right corner set the pivot to one and that's zeroed out let's now adjust it a little bit maybe this is negative 20. um maybe a little bit more 24 bring it down a little bit negative six now it looks pretty good see i'm not trying to make this look super pretty i'm just trying to show you how to do this let's go to ui um so we want to do our game over now but there's going to be two separate text elements so i'm going to first just create an empty object sort of just be the parent so i'll call this game over now on that i'm going to right click that i'm going to create a text component this one the center line we're going to make it white we're gonna make it a lot bigger let's do say 32 now making it that much bigger it now clips outside the bounds of our thing so i could tell it to just overflow and this will be game over so it looks fine let's duplicate this and offset the position below it say negative 40 or so i'll make this one a little bit smaller i'm gonna say this one press any key to play again and yeah that looks good that looks fine um so we're good there now we just need to hook it up with our game manager let's edit this game manager we need to add a few references to those different ui objects so ours first we need to import using unity engine.ui and now we can get a reference to let's say our score text our lives text and then to that parent game object for game over because we want to enable and disable that as a whole so all both of them together so we'll just get a reference to the parent game object we'll just call maybe call this game over and then in our code when we start a new game we should hide the game over game over set active to false when we get a game over we want to set it game over to the active so that displays and then anytime we change like score or lives we need to update this text so i find the best way to do this is to have a helper function for this so we say set score and this can be you know some value and so we'll say score equals value and then we'll update this text as well and this will be you know score two string anytime the score changes we're also going to update the text and now basically the exact same thing for lives i'll just change this to lives set lives lives equals value lives text equals lives to string and now anywhere we update the score or lives we want to call these functions instead so here we'll say set score to score plus amounts here we'll say set lives to lives minus one and then here we'll say set score to zero set lives to three this way anytime you change these values it's always going to update the text as well so it's always up to dates in the ui that should be good let's test this out uh we need to assign these different things here though so let's assign score let's assign lives and let's assign game over and let's test it out so this should disappear right away because the new game starts good as i play the game my score increases bottle looks good we're all good there and let's go ahead and let one of the centipedes kill me so we can test that test that out there we go our lives got updated too so there we go and let's um let's test real quick that uh we get the game over whenever you whenever you fully die [Music] here so i have one life left let's get one more and speed this up okay and game over perfect blaster disappears snake early centipede continues on but 34 points zero lies game over i can click click to play again and continue on everything resets great that's really it now for centipede at least as far as this tutorial i definitely would encourage you to add more to the game there's obviously more to centipede than what we did here there's spiders there's some other i think scorpions there's a number of other enemies that you can implement so i would love to see what you can come up with how you can extend upon this tutorial with new features new functionality new enemies levels etc 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: 18,908
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: QvdEBjqw0a8
Channel Id: undefined
Length: 140min 22sec (8422 seconds)
Published: Tue Mar 22 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.