Detecting the player - Complex Enemy Behavior - 2D Platformer - Part 14 [unity]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up guys welcome to Barden my name is Heinrich and today we're gonna take a look at how we can make it so that our enemy can detect our player this is what we ended up with in part 13 our enemy is currently patrolling left and right and if he detects a ledge instead of just turning around and moving immediately he will idle for a random amount of time and then turn and then move so let's take a look at this little state machine diagram that I have created here this is for the specific enemy and it just shows all the different states we plan on having by the end of this and then how the different states transition to each other let's just zoom in here so we currently have our moving state and our idle state so as you can see if we detect a ledge or a wall we go to our idle state and then if the idle time is up we go back to our moving state so logically the next state we would want to implement is our player detected state so this is where the enemy has now noticed that the player is in range and needs to go into like an aggro state or something so before we start doing this I just want to list the steps that I follow when I make a new state with the current system that we now have in place and I'll list up here if you guys to reference if you want to make your own states so step one is to create the state class so in this case it'll be the player detected state class that is going to inherit from state in this class where I'm going to do all the things that we need to do to detect the player or look for the player along with this we need to create the state data class for the specific state and then we also need to create the enemy specific state class for player detected state that is responsible for the transitions between the different states and then the last thing we need to do is just declare the state on the enemy class okay so let's jump into unity and get started so let's head to our state's folder and then let's create a new C sharp script and then this is going to be our player detected state like that we can go ahead and open it up so long and then while it does that let us go to our data folder and then let's create the data script so new c-sharp script b underscore player detected and let's go ahead and open that up as well and then next we need to come to our enemies specific folder enemy one and then create a new C sharp script this time it's a one underscore player detected state and then we can just go ahead and open that up as well so now we have all the files we need for this new state we have our player detected state our data class and then our enemy specific class ok so let's start with our player detected state we can go ahead and delete all the pre generated code as we do not need it and then we can make it inherit from state instead of mana behavior and then we can come and generate the constructor with control full-stop generate constructor and now we just need to get the reference to our data class so let's make a pro tected d underscore player detected and we'll just call it state data and then let's add that to our constructor so DePalma the underscore player detected and then again we'll just call it state data then finally this dot state data equals state data like that and then next we need to get the overrides for the functions so we can just click on the class name again control full-stop generate overrides we do not want the equals get hash or two string functions click OK and now we have all of our override functions ok now we need to think about how do we want the player detection to work we're going to keep it simple and just use a single ray cast that is a shot out from the front of the enemy at a certain distance to look for the player but instead of having one ray we're going to use two rays at different distances and say if the player enters the smaller distance then the player is detected and then while the player is in between the smaller and the bigger distance it stays detected and the player is only considered to not be detected once he leaves the longer distance this is also something that is going to stay consistent across most of the enemies so we can write another function in our entity class to handle this for us so let's come back to our entity class and do that we're gonna write two new functions the first one is going to be a public virtual pool again this is basically going to work exactly the same as the check wall or check large functions so we'll call the first one check player in min aggro range so this function is going to take care of doing the shorter distance check and the next one is going to be a public virtual pool check player in max aggro range like that so we need to define what the min and Max aggro distances are for the enemy so let's go to our D underscore entity class and then let's create two new public floats for those distances so we have a public float called max aggro distance like that and by default we'll just set it to 4 why not it doesn't really matter it's just so that we don't have any errors in case we forget and the next one is going to be our public float min I grow distance and we'll just set that to 3 I'm gonna move this up above max and then seeing as we're going to be looking for our player we also need another layer mask that is what is player so public layer mask what is player like that back in our entity class were almost ready to actually fire the Ray now we just need to have a position to fired from so let's do the same as we did for wall check and let's check and let's come up and declare another serialize field private transform and we'll just call it player check and let's come back down to our two functions and now we can say in our check player in min range function will say return physics 2d dot ray cast and we're casting the Ray from our player check dot position and we're firing it in the alive game object thought transform dot right direction and we're using entity data dot and this is our min functions or using our min Agri distance and then finally entity data dot what is player as our layer mask in our check player in max range function we can do the exact same thing we're firing it from the same position same direction except we'll be using max like euro distance instead of min Agra distance now our player detected state isn't responsible for actually detecting the player this is just where we go once we have detected the player so we need to take a look at our state diagram again and see ok we can detect our player from our idle state and our moving state so in these two states something needs to happen to see if we can move to the player detected state so let's start with the move state and let's come up to our variables and we'll start off by declaring a boolean to hold whether or not the player is currently in the min Agra range we do not want to consider the player detected once we enter the Max Agra range once we enter the minimum aggro range so we'll say protected bull and what is call it is player in min aggro range his name might seem a little bit long but it helps in the long run to use descriptive names and then in our enter function we can just say is player in min aggro range equals entity dot check player in managua range easy as that we then just want to make sure we copy this and put this in our physics update function as well and let's go ahead and do exactly the same thing in our idle State so we'll declare another protected pool cold is player in mini aggro range like that and then set it in our enter function so is player in min aggro range equals entity dot check player in min aggro range copy and paste that in our physics update like that so now both our move and our idle state will know if the player is currently in the men Agra range for the enemy will take care of transitioning to the player detected state from our enemy specific state classes so for now let's just set up our player detected state in the player detected state we want to keep track of if the enemy is in our min aggro range and if the enemy is in our Max Agra range so let's declare two protected billions so protected bool is player in min aggro range and protected pool is player in max aggro range like that and let's immediately go to our enter function and set these boolean's so is player in min aggro range equals entity dot check player in min aggro range and then is player in Max aggro range equals entity dot check player in max aggro range let's copy and paste that to our physics update function like that okay so for now what we're going to do to check if our player detected state is working or not is just when we detect the player we're gonna stop moving the enemy go into the player detected animation and then when the player leaves the max aggro range we'll just go back to the idle state so nothing else has to happen in the player detected state class for now we'll head to our e1 player detected state and then we can just delete the pre generated code and then make it inherit from our player detected state like that we can generate the constructor with control full-stop generate constructor and then we need to get a reference to our enemy so we have a private enemy one that will call enemy add that to our constructor and then this dot enemy the balls enemy like that and then we can generate our overrides again we don't want the first three we only want those click OK and now in our logic update we'll take care of transitioning to the different states so first we actually need to get to our player detected state so to do that we first need to come to our enemy one script and declare our player detected state so that we can transition to it so we'll add a public key one player detected state and we'll just call it player detected state the getter and the private cetera and then we need to get a reference to the data so Sierra lice field private D underscore player detected and we'll just call it player detected data like that then seeing as we already have our constructor set up for you one player detected state we can then create the instance so we'll say player detected state recalls a new II one player detected state and we'll pass it this as the entity state machine as the state machine the animation boolean name is just going to be player detected so the convention that I use for the boolean names is just the state name without the state and then we use camel casing where the first word is lowercase and then every word after that starts with a capital just to keep it consistent although I am notoriously bad at not keeping that very consistent but I'm trying okay and then we'll pass this as our enemy one like that okay now in our II one move state we can transition to our player detected state so what we'll do here is we'll come into our logic update function and we will say if is player in min Agra range meaning the array has detected our player then we want to transition to our player detected state so state machine dr change state and the state we want to change to is enemy dot player detected state simple as that and then after this we'll just change the second F to a else--if because we don't want this accidentally overriding the other transition and that's all we need to do in the e1 move state next let's go to e1 idle state and here we can do the same thing so if is player in min Agra range then state machine dot change state to enemy dot player detected state like that and then change this to and elsif so now when we come in range we should detect the player now in our a one player detected state just to test it up now in our logic update we will say if not is player in max Agri range then we want to transition back to our idle state so we'll just say state machine change state enemy dot idle state and we don't want the enemy flipping after the idle state so we'll come up here and we'll say enemy dot idle state dot set flip after idle to false now if we come back to unity oops okay so we have an error and that is because we forgot to pass the state data through to the state so after our player detected boolean name we'll just say player detected data like that okay that should be good make it inherit from scriptable object and make it so that we can create the asset just we can put it into the inspector so we don't have errors we'll come back and add the things we need in here later when we get to it so we can say square bracket create acid menu and then the file name let's just go back to our other data class just to confirm what we have we'll just copy this actually wait entity we want our state so let's copy this in here like that I will change it from new move state data to new player detected state so menu name is data state data prepare detected state like that okay now if we go back to unity in our enemy specific enemy one data folder let us right click say create data state data player detected state and we'll just call it E one underscore player detected data like that now if we click on our enemy one game object we can drag this in to our player detected data and now we also just need to add the player check game object so let's go to our a live game object and create a new empty game object call it player check go to enemy one drag player check into the Trant era into the slot and then let's just move it to a better position whoops when I move the player check to around actually not in front of the player we want to put it inside of the player around there that way if we get really close it'll still detect the player so about--there's fine okay so now if we look at our enemy one game object and look at our entity data as you can see our min and Max Agra distance the default values have been added so our max Agra distance is about four units which should be around here and then our men is three so we have to get about this close before the enemy actually detects us now let's just set up the animation so that we can see whether it actually worked or not so let's pull up our animation window click on our alive game object so that we can create a new animation navigate to the animation folder and we'll just call it enemy one underscore player detected like that we're only gonna use one frame for this so the sample rate doesn't really matter we can come down to our sprites folder our enemies and let's see which bright we want to use I'm just gonna use one where the enemy kind of has his arms up so here's our attack animation I'm going to use the this frame of the attack animation to represent our player detected so the enemy is kind of getting into like eight combat stance you just drag that in and then if we go to our animator we can see we have our player detected state so we can just put the animation window away for now and now let's look at our animation States we need to remember to add our player detected boolean and it's very important that this is exactly the same as we have it in the code and then the transitions between the animation states is going to be very similar to the transitions we have on our state diagram over here so let's make a transition from our walk state to our player detected state we want to uncheck house exit time and set the transition duration to zero just in case you don't know what these do basically exit time means how much of the animation were transitioning from has to play before we can leave so if if our transition had no conditions and exit time was set to 1 that means the walk animation would play all the way through once and then transition this is why it's important to set these two one on like our attack animations where we have an animation event at the end of the animation if the exit time is not set to 1 that animation event might not be played transition duration just has to do with how it blends between the two different animations because we wanted to instantly transition from our walk animation to our player detected animation we set the transition duration to zero so now let's add our conditions as usual we have to conditions the first one is that move is false because we're transitioning from walk to detected and then the next one is that player detected is true now we can do the same for a transition from idle to player detected untick has exit time sets the transition duration to zero add two conditions first one has to be idle is false and the next one player detected is true so now when we leave our Max Agri distance we want to transition back to our idle State so let's make a transition from player detected back to idle this is just temporary just for testing so let's click on the transition untick has exit time transition duration is zero add our two conditions so the first one is player detected is false and the next one is idle is true perfect okay let's test it and see if we did everything right so if we run this okay and one last thing before this is going to work is in our entities data we also need to set what is player equal to player okay so now if you run the game when we get close to the enemy you can see he detects us it's not quite right yet and I know what and that is because we forgot to stop the enemy when we go to the player detected state so if we go to our player detected state in our enter function we need to say entity dot set velocity to zero F so now if we run this jump in front of him as you can see he goes into his a little combat stance he's detected us now if we move left he'll go out of it because we're no longer in front of the array how'd you see when he turns around he detects us if we move out of the max Agria range he goes back to his idle state and he doesn't flip after idle perfect so our player detected state works let's take another look at our state machine diagram so once we've detected the player we have two other states that we could transition to so if the player is detected for a certain amount of time the enemy is going to charge at the player alternatively if the player is detected but the player is close to the enemy the enemy might just attack the player immediately and as you can see if we charge at the player and we get in range of the player we will also attack the player so next we're gonna take a look at creating these two states I hope you guys can start to see how this is coming together and how easily we can create more States and more behaviors for the enemy and I can't wait to show you guys how simple it is to create a second enemy by reusing a lot of this code it's it's it's it's actually amazing again if there's anything that you guys don't understand or something that I did not explain super well please reach out to me in the comments or on discord and I'll be happy to explain more and yeah so again I would just like to thank all my supporters and wonderful people on patreon who really helped motivate me to keep this series going and a big special thank you to the absolute Matt Ladd Louis for your support on patreon I hope you all have a a wonderful day
Info
Channel: Bardent
Views: 6,997
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, 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, respawn, hit, finite state maching, state machine, enemy, behavior
Id: GB1Ri_SRtZY
Channel Id: undefined
Length: 24min 11sec (1451 seconds)
Published: Fri Apr 17 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.