Basic Enemy - 2D Platformer - Part 11 [Unity 2019.2.0f1]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up guys my name is Heinrich and welcome to Barden today we're gonna take a look at creating super basic enemies that can detect ledges as you can see on the left and detect walls like this one on the right we'll also make it so that we can hit them and then when they die they will burst into a couple of chunks and some blood splatter that will eventually disappear okay so let's start off by importing the sprites that we're gonna use so let's go to the sprites folder and let's just do some organization so we'll create a new folder I'm gonna call it player and I'm just gonna drag all the player related sprites into this folder like that and then I'm gonna create another folder I'm gonna call this one enemies and we'll drag the dummy sprite sheet into there and I'm gonna create another folder that I'm gonna call hmm I'm gonna call it map maps I'm trying to drag the décor items and the tile set into that and then finally I'm gonna create one last folder that I'm gonna call particles I'll just drag the particles into there okay let's go into the enemies folder and let's import our new webs import our new enemy spreadsheet and we'll start off by just changing the settings like we always do so the pixels per unit is 16 the sprite mode is multiple the filter mode is point no filter and I'll set compression to none and then hit apply we can then click on sprite editor and hit slice grid by cell size and the pixel size is 64 by 64 and then hit slice and then we can hit apply now we have all of the sprites for our enemy we can now create our enemy game object so we'll create a new empty game object and I'm just gonna call this enemy 1 and now very important is reset your transform we can then come to our enemy one game object and create a new child game object that will call alive this will be the game object that all the different components are attached to and our script will be attached to enemy one so on the alive game object let's click Add component and let's start by adding a sprite renderer and into the sprite renderer we can drag the first sprite just so we can see where the player is or the enemy is and then we can come to the sorting layer and change that to enemy and we'll just leave it on 0 by default next we can add a rigidbody 2d component and in this component we need to set the gravity scale to 8 or to whatever you set everything else to or whatever works best for you and we'll change the collision detection mode to continuous and then we're gonna freeze the z-rotation next we're going to add an animator component and we'll just leave that as it is for now and then finally we're going to add a box Collider 2d component we can open that up and just hit edit Collider and let's go ahead and change it so it fits around the enemy a bit better just like that okay I'm also just going to click on the enemy 1 game object and then drag him up here where it makes a bit more sense to have him just like that now we're just need to make sure we click on the alive game object again and set the tag to enemy and the layer to damageable now we can start to make the animations so let's go to the animations folder and in the animation controllers folder let's right click and create a new animator controller and I'm just going to call it basic enemy AC I'll then click on the alive game object and drag this new controller into the animator we can then go to our animations folder and just create a new folder it'll call enemies we can then drag up our animations window and click on our live game object and then create a new animation navigate to the enemies folder we just created and we'll call the first one enemy one underscore walk we can then change the sample rate to 15 and then go to our sprites folder and drag in the first 8 sprites so from 0 to 7 into this animation look at him go okay next we can make the hurt animation so we'll say create new clip and then call this one enemy 1 underscore hurt and this one only has one sprite and it is sprite 13 so I'll drag that in there if you play it it doesn't look like much but this adds a lot ok so we can take away the animations window now and then we can just go to our animator and click on our live game object and then we'll create one parameter that we need for now and this will be a boolean and we'll just call it not back like that we then want to make sure that our default animation state is our enemy 1 walk state and then we want to make a transition from any state to our hurt state and when we click on it and make sure has exit time is not ticked and then under settings we want to change the transition duration to 0 well then come down to conditions and add the condition that knock-back is true and then we'll make a transition from our enemy 1 Hertz state to our walk state I'll do the same thing so make sure has like the time is not ticked and the transition duration is 0 and then under conditions knock-back must be false this is all we need for the animations for now later on as we improve the AI of the enemy and add more states this will become a bit more complex but for now all the enemy does is walk and get hurt so let's go into our scene view and then head into our scripts folder in here that's again make a new folder that will call player and then just drag all the player related scripts into that folder and then we'll make another folder called enemies and we'll drag the combat dummy script into that and then we'll make one last folder called particles and we'll drag this particle controller script in there let's head into our enemies script and create a new C sharp script that will just call basic enemy controller let's open that up in Visual Studio and we can just start off by deleting the code that is pre generated for us so the way the enemy behavior is going to work is we're gonna use what is called a state machine meaning we're going to have a bunch of predefined States that we'll use to determine what behaviors the enemy must have and this will make it really easy for us to expand on the enemy later and add more behaviors and more states to it to keep track of the different types of states that we have we're going to use what is called an email so to declare the enum we'll say private enum and we're just gonna call it state we can then open it with a squiggly bracket and then inside the brackets we can name all the different states that we have so our first state will be walking we can then use a comma to separate the different states and the next state is knock-back and then finally we'll have the dead state it's important that the last state does not have a comma after it we also do not need a semicolon after any of the lines next we need to come down and declare a private state called current state this will keep track of what our current state is the same thing can basically be achieved using integers so you can say like walking equals 1 knock-back equals 2 dead equals 3 but the enon basically replaces that in a more readable way we're going to have three functions for each of our state's an enter function an update function and an exit function so let's come down and just make a little comment so we know which state we're working with so we'll say walking state like that and then we'll say private avoid enter walking state and then next we have a private void update walking state and then finally we have a private void exit walking state like that and now we just need to do that two more times for our knock-back state and our dead state so now we're going to do is we're going to come up and create the update function and inside the update function we're going to determine which state is currently active and then based on that call the different update functions for the different states and we'll do this using a switch statement so say switch and inside the brackets we will say current state and then we'll open up some squiggly brackets and basically what this does is it says based on what current state is here are a bunch of different things you can do depending on what it is and the way you do this is you say case and then the condition so state dot walking and then you put a colon and then on the next line you say what needs to happen so if our current state is walking we're going to call update walking state and then we put in a break like that and then our next case is state dot knock-back and if that's the case we're going to update the knock-back state another break and then our final case for now is stay dead and if that's the case we'll update dead state and then put one final break so basically depending on what current state is all the other code for the different states will get ignored except for the state that we're currently in now we need to write a function that will take care of swapping during the different states so let's come down below all the states and let's just make a different section in the code called other functions where we'll write all the other important functions so this function is private void and we'll call it switch state and this function is going to take a parameter and that is the state we want to swap to so it's gonna be a state and we'll just call it state with a lowercase s inside the function we're going to have two more switch case statements and the first one is going to take care of calling the exit function for the current state and the next one is going to take care of calling the enter function for the state we want to go into so we'll say switch and this is based off of current state and our first case is going to be again state dot walking and if that's the case we're going to say exit walking state and then we'll put a break and then our next case is state dot knock-back and if that's the case we will exit the mock back state and then put break finally we have case state dot dead exit dead State and then a break now we can just copy this switch statements we don't have to write it all out again but this time instead of using current state we'll just use state which is the input parameter to this function and instead of calling exit we'll call enter for each of them and you might be wondering why we have an enter and exit state for the dead State the reason we're gonna have that is just if we end up using object pooling or if we have things that respawn the enemies stuff like that well we'll get to that later for now when the enemy dies we're just going to destroy the game object and then we'll work on the respawn system later and now finally for this function we just need to change current state to our state okay so now we're gonna work on the movement of the enemy we're going to get it to turn around when it reaches a ledge by just having a little ground check raycast downwards and then we're gonna get it to turn around at a wall by just having a little wall check raycast like we have lots of experience doing with the player controller already so let's actually go up to the top and declare some variables we firstly need to bully ins so they will be private pool and the first one is going to be ground detected and the second one is going to be wall detected we then also need to transforms where these two Ray casts will be so a cop and we'll say sterilize field and this will be private transform and the first one will be ground check and the second one will be ball check like that we then also need a serialize field and this will be a private layer mask what is ground we also need to declare the distances for these rays still create a another serialize field and this time it will be private float and the first one will be ground check distance and the second one is wall check distance like that we can then come to our update walking function will say ground detected equals physics 2d dot raycast and the position of the raycast is ground check and the direction is vector to dot down because we always want the Ray to shoot down and then our distance will be ground check distance and our layer mask is what is ground like that oops ground check is supposed to be ground check dot position and then we can do the same for the wall check so we'll say wall detected equals physics 2d dark raycast wall check dot position but this time we'll use transform dot right because we always want the raycast to shoot out at the front of the enemy and then next we have wall check distance and then finally what is ground now based on the information from these rays we will say if not ground detected meaning the raycast shooting down is not detecting any ground or wall detected so if ground at exit is false or a wall detected is true then we need to flip the enemy else we need to move the enemy so let's start with the flip function all we need for that is a private int facing direction so we'll say private and facing direction and then we can come down to our other functions section and we can write private void lip like that I don't know why I did this and inside the function we can just say facing Direction x equals negative 1 and then we can say oops okay and then we need to get a reference to our a live game object which is the one that actually holds the sprite and the one that will be moving around so let's come back up to the top and let's declare a private game object I'll call alive and then we just need to come and write ours nope our start function and in this we'll say live equals transform dot fine alive dot game object and then back in our flip function we can say alive dot transform rotate and we'll rotate it zero point zero F 180 point zero 1/2 and zero point zero F like that that's our flip function done so let's come back to our update walking state and just call flip from here now to move the enemy we need to get a reference to its rigidbody component so let's go back up to the top and under this let's declare a private rigidbody 2d called live our V and then in here or in the start function we can say alive our B equals a live dot getcomponent off type rigidbody 2d now that we have this reference we can come back up to our serialize field private floats and declare movement speed and we can also come below our ends and say private vector2 and we'll call this movement what we're going to do is just update the values of movement to apply to the rigid bodies velocity instead of declaring a new vector - every time we update it so let's go back to our walking state and in here we can say movement dot set and now we can just specify an x and y value for it and the X is going to be movement speed x facing direction and then our Y is just going to be alive our V dot velocity got Y like that and then we just need to say alive RB dot velocity equals movement now we just need to remember in start to set our facing direction to 1 by default next we can work on damaging the enemy and then the transition to our knock-back state so let's declare the variables we need for that first we need another float and this one will be max health and then we also need another float that's not sterilized and it'll be called current health we can then also declare some variables for our knock-back state when we'll start off with a private float that will be the start time of the knock-back so I'll say not back start I cannot type lock back start time and then we'll have a serialize filled prime float that will be knocked back duration and then finally we need to make another serialized field this time it'll be private vector - and will be called not back speed this will allow us to specify the X&Y speeds in one variable so let's come down to our other functions section and let's declare the damage function so we'll say private boy damage and this is the same as the damage function we had on the dummy with one small difference and we're gonna make the difference to the dummy and the player code later instead of taking in int or a float damage amount we're going to take a float array called attack details so we'll say float and in square brackets to specify that it's an array and we'll call it attack details the reason we do this is because we use the send message function when we hit something the send message function only allows us to send one parameter in so if you want to send multiple parameters through we have to do it like this and the reason we need multiple parameters is because we're going to be sending through the attack damage but we're also going to send through the X location of the person doing the attack that way we know which side of us the enemy is standing on and which way we need to get knocked back so inside the damage function we can then say current health minus equals attack details zero so we're always going to send the attack damage in the first index of the array and then we're going to send the x position of the player in the second index of the array and I should not think about it we need another variable that is going to be a private int as well and this int is going to be called damaged direction and now back in our damage function we can determine what damage Direction is by saying if attack details one is greater than alive dot transform that position not X then that means that the exposition of our player is greater than the exposition of our enemy meaning the player should be facing the enemy meaning damage Direction should equal negative one and then else you can just set damage direction to one by default like that now in here we can take care of instantiating our hit particle when the enemy gets hit but we'll take care of all the particles later so we'll just say hit particle like that but now we need to make the enemy go into the knock-back state so we'll say if current hull is greater than zero point zero f meaning the enemy is still alive we'll say switch state state dot knock-back and while we're here we might as well say else if current health is less than or equal to zero point zero f then switch state to state dot dead like that so let's go to our knock-back state and in the enter knock-back state here we'll say knock back start time equals time dot time so this will keep track of the exact time when the knock back started then we'll say movement that's set nope that's set and we'll use knock back speed dot X multiplied with damaged direction as the X component and knock back speed dot y as the Y component then we just need to set the velocity so we'll say a live RB dot velocity equals movement here we also need to take care of transitioning in the animator so let's go get a reference to the animator component so we'll come up to the rebels and say private animator and we'll just call it a live Adam will get the component in start so we'll say alive Adam equals alive get component off type animator like that and then in the enter knockbacks taped function will say alive annum dot set bull and the bull resetting is not back and we're setting it to true we then also just want to come to the exit not back state function and say alive annum that's set pool and this time we just want to set knock-back equal to false like that now inside the update not back state function will say if time dot time is greater than or equal to knock back start time plus knock back duration meaning the knock back has gone on for long enough we using to switch States back to moving so say switch state state dot walking I actually don't like the fact that I called it walking so I'm just going to change it to moving over here just like that ok how everything is better and that's it for our knock back state now let's look at our dead state so what we can do is just for now in enter dead here's where we would spawn the chunks and the bloods particle so I should say spawn chunks and blood I'll get to that later and then we can just destroy the game object so we'll say destroy game object like that now before we head back to unity let's just call our on drug gizmos function so that we can see our ground and wall check ray casts so I'll say on draw gizmos like that I will just say gizmos dot draw line and we want to draw the line from ground check dot position to a new vector 2 and the X for this vector 2 is going to be ground check position dot X and the y is going to be ground check dot position dot y minus ground check distance and then our wall check is going to be gizmos dot draw a line from wall check the position to a new vector 2 and we'll use wall check dot position dot X for the X plus wall check distance and then just wall check dot position Y for the Y so we save this I think we're ready to head back into unity so in unity if we now click on our alive game object we can just go ahead and create a new empty game object that we'll call ground check and another one called wall check if we then click on our enemy one game object we can drag on our basic enemy controller script and then we can drag in our ground check position and our wall check position we can set what is ground to ground if I can find it and then we can change our ground check distance to 0.5 and our wall check distance to 0.1 and now we can just move these game objects and position them a little bit better so we'll chain so move the ground check - just in front of the enemy and the wall checked it just in front of the enemy as well like that okay now I can click on enemy one again and we can just set the movement speed to three I'm gonna set max health to thirty and then knock back duration I'm gonna set it to 0.1 knock back speed I'm gonna just set to ten on the X and five on the Y and if you run the game now it should work in C our enemy moves and then flips when he reaches a Ledge we are not yet able to actually damage the enemy because we just need to go make a few changes to our player combat controller but let's really test the enemy on the walls as well so let's just move him down here I'm just go take a look and as you can see he turns around when he touches a wall as well if we try and hit him we're gonna get an error okay so let's go ahead and fix that error what we need to do is go to our player scripts and open up our player combat controller script and then come up to the top and then we're going to declare a new private float but this time it's going to be an array and we'll call it TAC details and then we just need to say equals a new float array of size two that means that our attack details array is going to have two indexes we can then come down to our check attack hitbox function and inside of this will just say attack details 0 equals attack attack 1 damage and attack details 1 equals transform position X and now here we say Collider to transform a parent send message instead of saying attack 1 damage we're just say attack details if we go back to unity now we should be able to damage the enemy as you can see the enemy instantly dies why oh I know why we have to come back to our basic enemy controller and very important in our start function don't forget to set current health equals to max health like that so now if we hit our enemy you can see he gets knocked back and then eventually dies okay now let's make the particles for when we hit the enemy so the first particle when we strike the enemy but he does not die we'll just go to our prefabs folder click on our hit particle and then hit control D we can then rename this to say enemy one hit particle and then I'm just going to mess around with the colors in the sprite renderer and I'm just gonna make it the same color as part of the enemy now it looks a bit more like a blood splatter we can then come back to our basic enemy controller script and declare a variable to hold a reference to our particles so let's say serialize field we're going to have a private game object and we're going to have three of them the first answer is going to be hit particle and the second one is going to be death chunk particle and the last one is going to be the blood particle like that we can then come back down to our damage function and then after we subtract the health we can instantiate the particle so I'll say instantiate and we want to instantiate the hit particle and we want to instantiate it on a live dot transform dot position and we want to instantiate it at a random rotation so we'll say return Ian dot Euler and the Euler is going to be zero point zero F for the X zero point zero for the Y and then for the Zed we're going to say random dot range we're going to take this between 0 and 360 so if we save this and head back into unity we can then click on enemy 1 and then drag this hit particle into the reference slot let's just move our enemy back up closer to us so we don't have to run down every time and then if we run this we should be able to damage the enemy with a lovely little blood splatter okay now let's make the chunks and blood that happened when we killed the enemy so let's head to our sprites folder and in the particles folder let's drag in our pieces sprite sheet we can then click on it and just do what we usually do pixels per unit is 16 sprite mode is multiple filter mode is point no filter compression is and then hit apply we can then click on the sprite editor and just choose whichever chunk you like best I like this one so I'm gonna click in the one corner and drag a little green box around it we now we have now cut this sprite out from the rest of them we can then hit apply let's come to our hierarchy and then right click go to effects and say particle system whoo zoom in on the particle system and start off by coming to the renderer tab and just setting the sorting layer to enemy I'm gonna set the order in layer two to so it appears above the enemy sprite okay we can then close the renderer tab and now let's make it use the chunk as the texture so come to texture sheet animation click the whole circle to activate it and then change the mode from grid to sprites drag the piece of sprite into the little block right below it we can then open up our emissions tab and then change the rate over time from ten to zero because we want to use bursts instead so click the little plus symbol in the first section I will just change the count to a random number so clicking the little arrow and say random between two constants I will just say between 50 and 70 let me expand this so you can see that if we restart this you can see it full bursts of particles it doesn't look like much yet but you'll see we'll get there we can then come to our shape tab we'll change this from a cone to a circle as you can see it looks more like a line and not much like a circle just come up to the top at the transform and change the rotation from negative 90 to zero now the circle faces us perfect we also want to just reset the transform so everything else is zero okay now let's make it look a little bit better we'll start off by setting a start delay we'll change it to random between two constants and we'll have a start to lay up between zero and zero point one that spreads them out a little bit we then also change our start lifetime change it to a random between two constants and we'll just have the lifetime be between two and five seconds let's also change the starts speed to ran in between two constants and the speed is going to be between ten and fifteen now we get a much better explosion effect perfect now let's change the start size again I ran the between two constants and the start size will be between zero point one and zero point five using to play with these numbers to make the chunks look a reasonable size for your character now let's mess with the start rotation so I'll say random between two constants and we'll just have rotation of between zero and 360 degrees that looks a lot better so far we can then come down to our stop action and just set that to destroy that means when this particle system is done playing the game object will destroy itself so also just make sure to unpick looping at the top now let's make it so the particles are affected by gravity so come down to the gravity modifier and just change that to eight we play this now you can see the particles pop up and fall down you can mess with this to make it feel a bit more floaty I'm actually gonna take mine down to five to restart this now explodes a bit nicer you can also just drag the particle system above the enemy so we can take a better look also you can notice these whole screen tearing lines gonna fix that just mess with the size of the window and it'll eventually go away just like that so that looks quite good now let's make the particles interact with the environment so scroll down and come to the collisions window or the collisions tab hit the little circle to turn it on and change the type from plains to world we then it change it from collides with everything to nothing and then change that back to ground we also need to change the mode from 3d to 2d it's almost perfect we can then just change dampen to one and balance to zero that means when the particles hit the surface they stick to it and they lose their momentum we can then also just come back to our shape and just change the size of the circle to make it fit in the enemy a bit better like that I like it the last thing we need to do now is just rename it so we'll call this death chunk particle and then just reset its transform one last time before making a prefab just click on it and hit control D we'll rename this duplicate that we just made death blood particle and then just drag the death chunk particle into the prefabs folder and the death blood particle into the prefabs folder as well we can go ahead and delete the death chunk particle game object from the hierarchy and let's work with the blood particle let's go back to our sprites folder and in our particles folder let's click on the pieces sprite sheet again and hit the sprite editor and for the blood I'm actually just going to use a single pixel so I'm just going to drag around a single pixel and then hit apply we can then come to our death blood particles again and under texture sheet animation change the two sprites around so we play this now you can see that pieces are a bit big so let's come up to our start size and let's change that from 0.1 to 0.05 to 0.1 as you can see that looks a lot better now we need to come to emissions and change the count between 250 and 500 so there's a lot more blood to go around 500 might be a bit much I'm gonna take this down to 400 perfect we can then also come to our start color and then hit random between two colors and we can just mess up the color a little bit I'm gonna make the blood a little bit brighter red and between a little bit of a darker red so to play this now that looks good okay let's make sure we save the changes we just made to the prefab by coming up here hitting overrides and saying apply all we can now delete the death blood particle from the hierarchy and then head to our script and in our entered death state function we can instantiate these particles so we'll say instantiate we're going to start with the death chunks particle and we're just going to do it on a live dot transform top position and the rotation is going to be death chunk particle dot transform dot rotation and then we can do the same of the blood so that blood particle alive dot transform position that blood particle but transform dot rotation just like that and now we need to make sure on enemy one that we drag in these prefabs into the game object slots so death blood particle into death blood particle and death chunk particle into death chunk particle so now if we kill the enemy beautiful if you want the chunks G spawn faster you just need to mess around with the start lifetime variable over here and that's gonna do it for now next we're gonna take a look at making the enemy damage the player when the player touches it before I go I just want to fix a mistake I made with the dash ability so if we play the game and we - as you can see we can see the dash perfectly fine I built the game and I played it and I realized I could not see the - and I was like why is this happening and I realized it's because when you build the game the framerate is a lot higher and I did not think of this when I wrote the code but if we head to our player after image sprites script our alpha is getting multiplied by something every single update meaning this this alpha is not going to decay at the same rate every time it's very dependent on framerate so let's fix this let's quickly put a serialize field for our alpha multiplier and that's actually change it from alpha multiplayer to alpha decay and then in our update instead of saying x equal we'll say - equals alpha decay times time Delta time so now when we play the game we need to come to our after image prefab and the alpha decay needs to be set to something higher I found that 10 works good for me now the the after image will decay at the same rate every time I hope you guys found that video helpful if you have any questions feel free to leave it in the comment section or you guys can come join the discord and talk to me directly and a big thanks to all the supporters and wonderful people on patreon and absolutely big thanks to the absolute mad lad Mason Crowe for his support I hope you guys all have a wonderful day
Info
Channel: Bardent
Views: 34,677
Rating: undefined out of 5
Keywords: Unity., tutorial, player, 2D, platformer, walljumping, wall sliding, jumping, Unity, Animation, ground, check, physics2d, castcirlce, variable, jump, height, Wall, Jumping, Hell, Yeah, Movement, improvement, user, friendly, code, 2019, 2019.2.0f1, Ledge, climb, dead, cells, system, easy, beginner, animation, Dash, Ghosting, After, Image, After Image, Basic 2D Combat, Unity combat, Comabt, Combat, Melee, Melee Combat, Basic, Enen, Enemy, Patrol, State, Machine
Id: K2SbThbGw6w
Channel Id: undefined
Length: 46min 43sec (2803 seconds)
Published: Sun Feb 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.