Charging at the player - Complex Enemy Behavior - 2D Platformer - Part 15 [unity]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
what is up guys welcome to Barden my name is Heinrich in the last episode we made it so that our enemy can detect our player when we come within a certain range of them so like this the enemy sees us we can move around a little bit if we leave a nother certain range the enemy will go back to moving now we're gonna take a look at how we can make it charge at the player and also look for player stage so let's first start with the charge state so as you can see when the player has been detected if it is in range for a certain amount of time we're going to transition to the charge state in which what is going to speed up the movement speed of the enemy in the direction of the player so it's jump into unity and stop this head to our files and then let's get started let's head to our scripts folder enemies and then States and then now let's create a new C sharp script and this is going to be our charge state just go ahead and open that up ok and then let's go to our data folder and let's create the data class for this state so de underscore charge state like that open that up ok head back to the enemies folder and then let's go into the enemy specific folder enemy 1 and let's create the e1 underscore charge state like that and let's open that up as well ok so we have our charge state which I realize I accidentally named charge instead of charge state so let's just add state in here oops save it then we just need to close it go back to unity go back to our state's folder and then rename it here as well which is kind of annoying that's okay and let's open that back up okay so we have our charge state stripped or enemy one charge state scrip and then we have our data script let's start with the charge state we'll get rid of all the pre generated code then change it to inherit from state instead of monobehaviour and then we can generate the constructor just like that okay now let's get a reference to the state's data so it's going to be protected and D underscore charge state called state data add it to the constructor so the underscore charge state state data and then inside the constructor we say this dot state data equals state data and then let us generate the function overrides and take the first three click okay so when the enemy charges at the player we just need a different movement speed so let's come to our chart state data script and then get rid of this code make it inherit from scriptable object and the first thing we're going to need is a public float charge speed and by default let's just set it to something like six six sounds good to me so now back in charge state all you do is in our enter function we will start off by calling entity dot set velocity and we're going to set it to state data dot charge speed like that so what I want to do is I want to make it so that the enemy charges at the player only for a certain amount of time and then when that time is up we will go back to either the player detected state if the player is still in range or will go into a different state so let's actually add in our D charge state script it's at a public float we'll just call it charge time let's just make it two seconds to start off with so if we take a look at our state machine diagram again we can see that in our charge state we want to either transition back to player detected if the if we've charged for a certain amount of time and the player is still detected or we want to go to the player tag state if the player is in range to be hit so let's start with getting everything we need for this transition back to player detected state we want to transition back to player detected state if the character is still within the minimum aggro distance so in our charge state script let's create a protected bool and we'll just call it is player in mini aggro range like before and let's immediately come and set that in enter so is player in mini aggro range equals entity dot check player in min aggro range like that and then let's copy that and put it in our physics update as well when the enemy is charging at the player we also don't want it to keep charging once it reaches a Ledge or a wall so let's add those billions in here as well so I'll say protected pool is detecting ledge like that and protected bull is detecting wall and that's immediately come and set both of those as well so it's detecting ledge equals entity check ledge and is detecting wall equals entity top check wall like that and then just copy and paste but for those in our physical update okay so I just realized that I'm doing something really dumb why would I call these three functions in physics update and an enter because that means if I need to change something I need to remember to change it in both of these so let's actually quickly change this so that we have one function where we can put all these calls in there that gets called and enter and physics update for all of our state's now this part I did not plan out so we're doing this on the fly let's see how it goes so let's go to our state class if that is so open it is not so we'll go back to unity go to scripts enemies States no enemies state machine open up our state class and let's just add another public virtual void function here and we'll just call it do checks something like that now in this function will just write those functions that we need and then while we're here we can just call do checks from enter so do checks and then we can also call do checks in our physics update so if do checks like that okay let's fix our move state and idle state so long so go to move state we can click on the move state name control full stop generate override and now I just want our do checks function it adds it up here so we can just cut this code from Enter and put it in here like that and then remove it from physics update looks good to me let's do the same with our idle state so idle State click on the name control full stop generate overrides we want to do checks one do that and in here we're just checking for the player in the min Agra range so let's cut that put that in dude checks and then remove it from our physics update like that okay and then next we have our player detected state and do the same once again so generate override we just want that one cut these checks put them in there and then remove them from our physics update and this may seem like a little bit of extra work now but again we're doing all of this to make our lives easier so now finally our charge state we can do that again control full-stop generate overrides do checks put this in here and remove it from our physics update now before we go on let's head back to unity and make sure we did all this correctly so the enemy should stoled it yes we still moving so everything's working there he's detecting alleges he detects us perfect everything works so now when we create a new state and we generate our overrides this new checks function is going to be there for us we don't have to remember to call it from enter or from the physics update perfect now I need to remember where we left off so we're busy checking to see if the player is in the minimum aggro range and then we want to transition back to our player detected state if once the time has run out okay so let's create another boolean for the charge time and we'll just call it is charge time over and then in enter we need to make sure we set this to false like that and then in our logic update we're going to say is if time time is greater than or equal to star time which again remember star time is a property that all our states have plus our state data dot charge time if this is true then is charge time over equals true so we use this boolean to determine when we need to transition to a different state so we can save this and then let's head to our one charge state class if we can get rid of the code and this time we make it behavior from charge state like that now we can generate our constructor and then we add the reference to our enemy one so private enemy one enemy add it to the constructor enemy one enemies and then in the constructor we say this dot enemy controls enemy and now we can generate our overrides and it's not quite necessary to generate all of these if you don't want to I dislike having all of them there but for the most part we don't add any extra code to a lot of these in this case for the enemy specific classes we generally only add code to the logic update to decide which states we go to so now in our logic update we can say if is charge time over then depending on if we are detecting the enemy or not we're going to transition to different states so in here we'll say if is player in min Agra range then state machine dot change state to enemy dot player detected state like that so when we are charging once we've charged for a certain amount of time if the player is still detected we will go to the player detected State now if we look at our state diagram here there's actually supposed to be another transition from charge state to the look for players state so if we have finished the charge time and the player is not in range and it's also not detected we will go to the look for player state but we'll worry about that later for now we still need to make it so that we can go from our player detected state to our charge player state so back in our code let's go take a look at our player detected state we didn't add much to this yet so when the player is detected we want to wait a certain amount of time and then charge at the enemy so we need to declare a wait time so let's go to our D player detected class which is here and in here we're going to declare a public float that we're just going to call action time because from the player detected state depending on which enemy we have we might not go to a charged state but we're just going to say after the player has been detected for a certain amount of time perform whatever action we assigned to it which in this enemies case is going to be to charge at it and by default let's just set that to 1.5 F whoops like that so now in our player detected state and another thing I should mention is we're going to have two sorts of actions when the player is detected we're going to have a long-range action and we're going to have a close-range action or a short-range action whatever you want to call it basically in this case for the for this enemy the long-range action is going to be to charge at the player and the short-range action is going to be to attack the player so if the player is detected and he's really close we will immediately attack the player in the case of the other enemy or long-range action is to fire an arrow and our short-range action is to jump away so for now let's start with the long-range one so let's create another protected pool that we will call perform long-range action like that and now the condition for performing the long-range action is going to be set in logic update where we will say if timed uptime is greater than or equal to start time plus our state data dot action time like that and it might be better to name this long-range action time instead of action time so if we click on action time and press ctrl R twice we can rename it and it'll rename it everywhere for us so long-range action time like that and now inside of this if statement we can just say perform long-range action equals true and we just need to remember in enter to set this to false so perform long-range actions equals false cool so now if we go to our EU one player detected class so currently we're saying if the player is no longer in the max Agra range we go to idle but instead what we want to say is if perform long-range action then state machine that changed state to enemy 1 dot charge state although we have not yet declared the charge state on our enemy 1 in class so this isn't going to do anything but we'll take care of that just now we just need to remember to remove this line as well like that cool ok let's go to our enemy 1 class and let's create the state so we'll save public II 1 underscore and we're creating a charge state and we'll just call it charge state we can create the public getter and the private setter for it like that let's create a reference to the data so a serialized field private d underscore chart state and this is our charge state data like that and then it's called a constructor from start so we'll say charge state equals a new II 1 underscore charge state again this state machine the boolean name is going to be charged and let's remember to pass the data this time so charge state data and this as our enemy 1 like that so now if we go back to our II one player detected state the error is gone let's go back to unity and now the first thing we need to do is create the animation for the charge state so let's pull up our animation window click on our a live game object create a new clip navigate to the animations folder enemy and we'll call it enemy 1 underscore charge now for this animation I'm going to use the same sprites as the walk animation I'm just going to play it at let's say double the speed so we usually change the sample rate to 15 I'm gonna change it to 30 we can see what that looks like go to our enemies folder in our sprites folder and sprites 0 to 7 is our walk animation drag that in let's see what that looks like that's maybe a little bit too fast let's try 23 it slipped fast maybe just 20 oops that's not that's 20 that's a bit too slow 23 was good I think makes him look really rushed ok cool now it's a bit too fast we'll go of 21 again so we're done with the animation window for now then we need to go to our animator here we have our charge state and if we look at our state diagram we go to charge state from our player detected state so from a player detected state we're going to make a transition to our chart state untick has exit time set the transition duration to 0 add the two conditions the first one which is player detected is false and the second one is solely to create it is a bull that we call charge and in the conditions set charge is true now I also need to make a transition back to player detected and for that again antek has exit time set the transition duration to zero add the two conditions the first one is charge is false and the second one is player detected is true so let's try this out let's go back to our scene view I'm just going to move the enemy over to this platform where our player currently is and actually we should test to see if it actually works with the walls I didn't actually check that so let's see if that works it should it does ok cool now if the enemy detects us it goes into the charge state but it doesn't work oh we forgot to add the charge state data so let's go back to our scripts folder enemies enemies specific enemy one data and then create a new data state data which we can't do yet because we forgot to add the code okay let's come back to visual studio and then come back to our D underscore charge state we need to add the create acid menu line at the top such as come copy that from our move state like that will set the file name to new charge state data and the path is the same except this needs to be charged like that and now if we go back to unity we can right-click say create data state data charge state and we'll call it E one underscore charge data like that click on our enemy 1 game object and then drag our charge data on to the enemy so if you run this now when the enemy detects us start charging perfect he does not detect the ledge however how we did not put the conditions for that in yet how long does he charge for our charge time is currently two seconds that's a bit too long let's set this to half a second just to see if that part works so he detects us charged us stops go back to play detected perfect everything works just the way it should let's fix that so in our code let's go to our a one charge state class and before we do this if is charge time overstatement let's create another if and in the safe we will say is detecting ledge actually it's supposed to be is not detecting ledge or is detecting wall then in this case we want to look for our player but we don't have that state yet so let's leave ourselves a little note over here a little to do and we'll say connect to look for player like that and then we need to change this to else if we'll create them look for player state soon if anything we should really do that before we do the attack state let's take another look at our state diagram so we currently have this transition from player detected state here and then we have a transition from charge state back to our player detected state so before we do the attack state let's do the look for players state because the attacks it has a couple of extra things that we need to look at will probably save that for a different video let's get this working so let's go back to unity and let's create all the files we need so we'll start off by going to our state's folder let's create a new C sharp script and we'll call it look for player and I forgot to name it state again add state open it up in Visual Studio don't forget to add state here like that okay let's go to our data folder create a new C sharp script D underscore look for player let's open that up as well and then finally let's go to our enemy specific folder enemy 1 and then create a new C sharp script e1 underscore look for player state like that and open it up so now before we forget again let's go to our the idle State or something and copy this and then paste it in our D look for players state and let's just fix this wall right here make it inherit from scriptable object like that now we won't forget actually can you change this so you look for players state look-look for player like that perfect then let's go to our look for players state class get rid of this make it inherit from state like that and now let's generate our constructor and then we can add our state data reference so protected the underscore look for player called state data add it to our constructor like that this dot state data equals state data and then let's generate the overrides second 12 . generate overrides we don't want the first three okay perfect now that just think about how we want the enemy to look for the player again we're just gonna keep this super simple if the enemy is not detecting the player we just want to keep looking in a certain direction for a bit of time turn around look in that direction for a bit and then turn around again and then transition to a different state and of course in that whole turning around thing if we detect the player we immediately go back to the player detected state so let's start off by going back to our D look for players state class and the two variables we're going to need for this class is the amount of turns that we want to do and the amount of time between turns so the amount of turns is going to be a public int that we'll just call amount of turns like that and by default we'll set it to 2 so that way if the enemy is facing a certain direction it'll turn look behind it and turn back the direction was facing and then continue whatever it was doing next we want to create a public float that we'll call time between turns like that and by default we'll just set it to let's say 0.75 like that so in our look for players state we want to keep track of if we are detecting the player in the minimum aggro range so we'll declare a protected fool cold is player in min aggro range like that and then do the check so is player in managua range equals entity dot check player in min aggro range like that that is quite a mouthful anyway next we want to keep track of whether or not we've done all the turns and we also want to keep track of if we have done all the turn times so let's declare two more goals one is going to be called is all turns done and the next is going to be cold is all turns time done so this one is just going to keep track of if we did all the turns this one is going to keep track of the amount of time that has passed basically next in order to do the turns need to keep track of the time that we did the last turn so we'll declare a protective float hold last turn time like that and also declare a protected int called amount amount of turns done now another thing we might want to do in this look for player state is make it so that when we enter it we turn immediately so let's create another pool that we can set from outside the same way we did with the idle state flip after idle parameter and create a protected boolean that will call left immediately like that and now let's just create a public void function that sets this so public void set flip immediately and it'll just take in a bool that we'll call Philip doesn't really matter in this will say flip immediately equals flip like that so we can call this function from other states now to set that parameter and then in our logic update we'll take that into account to determine when we should flip so let's look at our logic update function for this state we want to say if flip immediately is true then we're going to say entity dot flip you need to keep track of our last flip or turn so say last turn time equals time time like that I don't like that I call this flip instead of turn so let's just press ctrl or twice on that and we'll change it to turn immediately that should change the function name as well from set flip to set turn like that okay and then back in if turn immediately we want to say amount of turns done plus plus because we did a turn and then we want to set turn immediately equal to false otherwise we're just going to keep coming back into this if statement after this we want to say else if and in the if statement will say if time duck time is greater than or equal to last turn time plus state data thought time between turns and naught is all turns done so basically if the current time is greater than or equal to the last time that we flipped plus the amount of times between flips and we haven't done all the turns were supposed to do then we're basically going to against a entity dot flip like that and then last turn time equals time duct time and then amount of turns done plus plus and that should take care of flipping the enemy next we reason to see if we've done all of our flips so we'll say if amount of turns done is greater than or equal to state data dot amount of turns then we want to set all turns done equal to true like that now to make it so that after the enemy does his final turn he looks in that direction just for a little bit before going back to whatever other state we choose will say if timed up time is greater than or equal to last turn time again plus state data dot time between turns and is all turns done is true so that means we've done our final turn now we need to wait for one more turn time and then we can transition so here we'll say is all turn times done equals crew and we'll use this is alternate times done boolean to determine when we transition so that should be it for the look for player state let's come to the e1 look for players state we can get rid of this code make it inherit from look for player like that then we can generate the constructor get the reference to our enemy so private enemy one cold enemy add it to the constructor enemy one enemy this dot enemy equals enemy like that generate the overrides like that we should all start becoming experts at this and now in here basically all we're going to say is in the logic update if is player in min aggro range so we're looking for the player and we detect him we'll say state machine topped change state to enemy dot player detected state like that and then we'll say else if so else if our is all turned high I'm done then state machine dot change state to enemy dot move state like that so our enemies going to look around for our player if he finds the player we'll go back to the player detected state if he doesn't find the player he will just start moving again perfect now we just need to go back to our enemy one class and add this state so up here we'll save public e one underscore look for players state and we'll call it look for player state get the public getter and the private setter like that and then we need the reference to the data so to create a sterilized field that is a private the underscore look for player data and we'll just call it look for player state data like that then in our start function we can call the constructor to create the instance so look for player equals a new be one underscore look for players state and the entity is this the finite state machine is state machine the animation boolean name is going to be looked for player with a lowercase L state data is look for player state data and the enemy is also this so now before this is going to work we also need to set up the transitions from our other states to our look for player state so let's pull up the state diagram again and so the state diagram is a little bit outdated we're actually going to make a transition from player detected to look for player state if we leave the range and then we're also going to make a transition from charge player state to low prepare state if we no longer detect the player so let's start with the player detected state 1 so let's go to our a one player detected state which is here and so after this if we will say else if not is player in our max Agra range then state machine change state to enemy dot look for player state like that and then in our charge state so you want charge state let's get rid of this to do and then we'll say state machine dr. change state to enemy dot look for players state like that so now we can go back to unity and then in our animator we don't have a specific animation that we're going to use for this we're just gonna reuse the idle animation so we can just right click in the animator and create a new empty state and we'll just change the name to match everything else so say enemy one underscore look for player like that and then under the motion we can just click on the circle and select our enemy one idle animation as this animation now let's add the parameter so we're adding a new boolean and this is going to be called look for player like that okay so now let's set up the transitions we want a transition from our player detected state to our look for players state click on it on Tech has exit I'm set the transition duration to zero add the two conditions the first one is player detected is false the second one is look for player is true and then we need a transition from this back to player detected on tick has exit I'm set the transition duration to zero add the two conditions the first one is look for player is false the second one is player detected is true next we also want to transition from our charge state to our look for player state and then we want to unpick has exit time transition duration is zero add the two conditions the first one is charge is false and the second one is look for player is true and now we just need to remember to add the data to our enemy so let's go back to our scene view click on our enemy 1 game object and go to our data folder right click create data state data look for players state and we'll just call it e1 underscore look for layer data like that click on enemy 1 and then just drag this into our slot so now when we run the game when the enemy detects us and we leave as you can see the enemy turns and then breaks let's figure out why so we're currently still stuck in the look for pair state okay so we're still missing a transition from our look for players state to our move state or our walk state so make a transition from look for player to our walk on tick has legs a time transition duration is 0 at the two conditions the first one is look for player is false and the second one you his move is true so if you run the game now the player takes us and he starts looking okay so currently the enemy flips immediately which is not quite what we want let's figure out why so if we go back to our look for players state class we forgot to add everything to our enter function I'm a big dumb okay so in our enter function we need to start off by setting the boolean to false so is all turns done people's false is all turns time done equals false and then we need to set our last turn time equals start time like that and then our last turn time equals our start time and then amount of turns done equals zero and then finally we just need to set the velocity to zero just in case so entity dot set velocity to zero F like that okay now if we go back to unity and run it this should work so as you can see the enemy looks in one direction a little bit first before he flips there he chases after us and he stops the ledge and looks for us perfect everything is working beautifully I'm going to end this part here so we currently have our idle state moving state player detected state charge state and look for player state so next we're going to make it so that our enemy can actually attack us and then after that we'll probably look at how we can stun the enemy and then eventually kill the enemy so as it is right now we can't actually hurt the enemy like we could before nothing happens when we hit it we just have a error saying that our send message has no receiver which is fine so that's it for this episode I hope you guys are enjoying this as much as I am this is really exciting for me I had so much fun creating all of this I learned so much new doing all of this I'm sure I'm soul doing some things that can be done in way more efficient ways but this is a huge improvement over how I was planning on doing this and it's it's awesome so I hope you guys are enjoying it and I would just like to give a big thanks to my supporters and wonderful people on patreon you guys mean so much to me and a huge thanks to Louis for your support and I hope all of you have a wonderful day
Info
Channel: Bardent
Views: 6,391
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, Charge
Id: s2Mes9K8M4E
Channel Id: undefined
Length: 42min 7sec (2527 seconds)
Published: Mon Apr 20 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.