Full transcript
Outcome of This Part
0:00[Music]
0:05welcome back everyone to Part 12 of our
0:08smart enemy AI Series in this part we're
0:10going to be setting up our team system
0:12so right now I have all these teams all
0:15these enemies in team number one as you
0:16can see here and I'm also team number
0:18one as a player so none of them will be
0:21attacking me because we're on the same
0:22team
0:24now if I change this guy to be team
0:26number two
0:27then he's gonna try to attack me and as
0:30soon as they see him they're all gonna
0:31try to attack him so we're not only
0:33going to be looking at
0:35um how to get enemies to perceive people
0:37on their team or not on their team but
0:39we're also going to make sure that the
0:41melee enemy and ranged enemy can't
0:43damage people that are not uh that's
0:45sorry that are on their same team so
0:47we're pretty much disabling Friendly
0:49Fire
0:50so let's get started
0:52all right so before we start with
Improving the Block Functionality of the Melee Enemy
0:54setting up our team system I want to fix
0:57um something annoying which is uh when
0:59you have multiple melee enemies and you
1:01attack them they all block at the same
1:04time
1:06um this is quite annoying because they
1:07detect when their attack Target is
1:10attacking they don't detect if they're
1:12the ones being attacked or if the attack
1:14is actually going to hit them or not so
1:16we're going to modify the block Behavior
1:17to make the group enemy combat look a
1:20bit more realistic so let's start by
1:22doing that
1:24so first thing we need is in our AI
1:27folder uh Behavior trees and our melee
1:30enemy tree we're going to delete our
1:35where is it our block branch
1:40is yeah so this one so we checked the
1:42target's attacking and then we do a
1:44block I'm going to delete this Branch
1:46completely okay we're not going to
1:47handle the block functionality now in
1:49the behavior tree
1:50why is that because I want the melee
1:53enemy to block as soon as they take
1:55damage and that means we're going to
1:57handle it in the take damage function
1:59so let's see how we can do that
2:02let's now open up our
2:05enemies our melee enemy
2:10all right
2:12and where we
2:15um
2:18so over here this is where we do our
2:20blocking right I'm gonna keep these
2:22functions so the start block unblocked
2:25and N block we're still going to use
2:26them but we're going to modify them a
2:27bit uh but what we actually want to do
2:30is override the take damage function so
2:33we have take damage here that's
2:35implemented in the base enemy and in the
2:38base enemy all it does so take damage
2:40all it does is call take damage from the
2:43um damage system from the damage system
2:46component now the nice thing about using
2:48a actor component is that we can keep
2:51this function call but over or do things
2:53before or after it in our melee enemy so
2:56I'm going to go back to the melee enemy
2:58and double click on my damage to take
2:59damage function now I've overridden this
3:03function so it's now not under
3:05interfaces but under functions that
3:06means I'm overriding whatever base
3:08implementation was already there
3:10and I'm going to just paste the take
3:13damage function from the bpc damage
3:15system as is
3:18plug everything in like it was but now
3:21right before
3:23uh I call take damage I'm going to try
3:27to block and I say try because I'm going
3:29to have it be a percentage so there's a
3:31chance that the melee enemy will block
3:32so let's create a function a new
3:35function here and call it try to block
3:39all right and this function
3:42um we'll call start block
3:44but it won't always call it it will call
3:46it under a condition right so we're
3:48going to put a branch here and this
3:50condition is if uh we generate a random
3:53float so let's say random floats this
3:57will give you a random number between 0
3:59and 1 and we're going to check is this
4:01number uh greater than or equal
4:05if we say for example greater than or
4:07equal 0.1 then there is a 90 chance that
4:13the sorry actually let's make it less
4:14than or equal
4:15I'll show you one so if we say if it's
4:18less than or equal
4:20um 0.9 that means there's a 90 chance
4:23that the enemy will block if it's less
4:26than or equal 0.3 there's a 30 chance to
4:29enable block and so on
4:31so I'm gonna make it
4:340.25 so 25 chance block and I'm actually
4:37going to promote it to a variable and
4:39call it blockchains
4:43all right and this will be the condition
4:44to our try to block function
4:48so that's really it
4:49um which checks if we have a chance to
4:52block and if so we call start block and
4:55if you recall start block stops movement
4:58sets is blocking to true this is the
5:00most important thing and does some other
5:02things we'll look at it in a bit
5:05over here in our take damage function we
5:07want to call our
5:08try to block
5:11all right
5:14um but there's also one condition you
5:15want to add here and if you recall not
5:18all attacks can be blocked so we have
5:20attacks that are blockable and attacks
5:22are not and this is in the damage info
5:24so if I pull off damage info and say
5:26break here I will have can be blocked so
5:29I'm going to first check if can be
5:31blocked is true because I don't want to
5:33try to block if I know this attack can't
5:35be blocked that's kind of useless
5:39um and by the way if I click here and
5:40say hide unconnected pins then it's
5:42going to make this a bit cleaner and
5:44only show the pin that I connected
5:46all right so now I check if I if this
5:49attack can be blocked then I try to
5:51block otherwise I continue and also on
5:54the false I'm going to just skip the try
5:55block and go right to take damage
5:57because if the attack can't be blocked
6:00then I just want to continue and not try
6:02to block
6:04all right
6:05let me just clean these up a bit because
6:08of my
6:09OCD
6:13all right
6:15looks better
6:17um
6:18great so now before we take damage we
6:21try to block
6:22um now let's modify our start block a
6:25bit
6:25if you recall we used to play a montage
6:27this is the Montage where the enemy
6:29first takes the block stance and then if
6:31they successfully block we play another
6:33Montage which is the one where they
6:35actually do the moving back a bit with
6:37their sword so we don't need this
6:39Montage anymore because
6:41the time between a getting starting to
6:44block and actually blocking or not is
6:46the time it takes for this Branch to go
6:49from here to here so it's pretty much
6:51instantly so this Montage will never get
6:53the chance to play so we're gonna remove
6:55it and we're gonna remove all of this as
6:56well
6:58um but actually let's keep end block
7:00because we still want to end block if
7:03something happens uh what do I mean by
7:05if something happens well in the normal
7:07flow we're going to try to block if we
7:10are successful we're going to block the
7:13damage and then
7:15um unblocked will be called and then n
7:18block will be called after the Montage
7:20is finished right
7:21but something could happen where uh we
7:24try to block which we set is blocking to
7:27true but we don't actually take the
7:29damage
7:30so in that case we need a way to end
7:32block as well
7:33so I'm going to set a timer so I'm gonna
7:35go over here and say set timer by events
7:40and this event will be say create event
7:43and it will be end block
7:46um actually we don't need this then
7:47because I'm calling it as an event
7:49and we're going to say after maybe two
7:52seconds so if you are blocking
7:56if you start to block two seconds later
7:57end the block
7:59and we're going to create a timer sorry
8:02variable for this timer we're going to
8:03call it the
8:05um hold block timer
8:11um
8:12and if
8:14we call end block before this timer ends
8:17we want to stop the timer because we
8:18don't want to call end block twice right
8:20so over here in the end block well
8:24actually no not if we unblock if we
8:26block successfully so right here before
8:28doing this we want to get a reference to
8:31our timer
8:32and say clear and invalidate timer by
8:36handle so that if we block successfully
8:38then ignore this timer clear it we don't
8:40need to block anymore
8:44um and also we need to do the same thing
8:47when we start blocking if there's
8:48already a timer running
8:50um delete that timer because we're going
8:52to be creating a new one
8:54so I'm going to move all of these this
8:56one to this one
8:59and paste this here
9:01so now we clear the timer when we start
9:03to block as well
9:05excellent now let's uh let's take a look
9:08at Let's test this out and see what it
9:09looks like
9:11all right so now I have multiple enemies
9:14all right he did not block he did not
9:17block we have a 25 chance
9:19remember but as you can see now they're
9:22not all gonna block oh that he blocked
9:24nice
9:25let me increase it to this blockchains
9:29here let me increase it to a hundred so
9:30one that means they'll always block just
9:32to see how it works
9:34so this guy nice and you see only the
9:36one that was attacked is the one that's
9:38blocking
9:42and let me show you one last time
9:44foreign
9:47I think this looks
9:50um a lot better than what we had before
9:52and now we can jump into our team system
Setting Up Team Numbers
9:57all right so the first thing we need to
9:58do is uh let me close the melee here
10:03um first thing we need to do is we're
10:04going to modify our
10:07um
10:08damageable interface so in our damage
10:10system and BPI damageable
10:13and we're going to add a function here
10:14we're going to call it get team number
10:18so we're going to have teams assigned by
10:20number so there's team one team two team
10:22three and so on so you can have as many
10:23teams as you want
10:25and of course enemies with the same
10:26number are on the same team or even the
10:28player can be of the same number as an
10:30enemy and it's just going to return the
10:32team number which is going to be an
10:34integer
10:37all right so this is in the damageable
10:38interface so there are two actors that
10:41implement this interface now our player
10:44and our base enemy
10:47so if I go to my player here I should
10:50see the get team number and it just
10:54wants me to return a number now I'm not
10:56going to set it here I'm going to create
10:57a new variable for it and call it team
11:00number
11:02an integer
11:05and we're gonna plug it in here
11:09compile to add a default value and let's
11:11say the player defaults to one and we're
11:13going to do the same thing the base
11:14enemy gets our uh get team number where
11:19is it so many functions okay
11:22um and well you can also right click
11:24promote the variable and call it team
11:26number
11:28and for the enemy let's default to T
11:31number two
11:33and also one thing to note for the enemy
11:35make sure to click on this uh I icon and
11:38say also uh you don't have to say expose
11:40on spawn but let's do it so instance
11:42editable and expose on spawn because
11:44that way you can click here and search
11:46for team number
11:49team did I not compile I did not compile
11:54now I can search for T number and I can
11:55change it so I can say this guy is team
11:57three this guy's team two for example
12:00you get the idea
12:03um
12:03all right so now we have a way to
Preventing Team Members from Sensing Each Other
12:06um assign team numbers uh now what's
12:09what what do we need to check where do
12:12we need to call this get team number
12:13well it's going to be in a few places
12:15but first one is in our enemy AI
12:18controller because this is where we have
12:19our senses right so when you sense sites
12:23we want to check did I see a team member
12:25or did I see an enemy when you sense
12:27um damage you want to see was I damaged
12:29by team member or otherwise I damaged by
12:31a non-team member
12:33um so to check if we're on the same team
12:37as someone or not we're going to create
12:38a function here and we're going to call
12:40it
12:41um on same team
12:44and it takes an input the other actor
12:47that we're checking so other actor of
12:49type actor object reference
12:53and it returns
12:56um a Boolean value same team yes or no
12:58or true or false
13:02but since uh we added the get team
13:04number as a interface then we can call
13:07it as an interface function and we can
13:09call it without casting of course so we
13:11can say get team number
13:13so now we're getting the team number of
13:15the uh actor that we just sensed or the
13:18other actor and we're also going to get
13:20team number of our self of the person
13:23the pawn that's this controller is
13:25controlling so to do that you can say
13:27get controlled upon this gets to the
13:30pawn that this AI controller is
13:32controlling and call get team number on
13:34that
13:36all right and they are the same team if
13:38these two numbers are equal so if this
13:41number equals this number then same team
13:45is true
13:47otherwise of course it's false
13:51all right so let's look at our handle
13:55sense site
13:57so here
13:59um we don't need this because this we
14:00were checking if the player is if the
14:03person we sensed is a player we're going
14:05to delete all of this
14:07because now we're going to do a new
14:08check we're going to check
14:11um is and what's it called on same team
14:15so we're going to check if this other
14:18actor we can get it from from here
14:22if this other actor is on the same team
14:25uh and if not so if they're not on the
14:28same team let me
14:30move this
14:33let's create a branch if they are not
14:38on the same team
14:41then we will continue
14:43and if they are on the same team we're
14:44not going to do anything I just saw
14:46someone on my same team don't have to do
14:48anything about it
14:51all right
14:53um and that's oh sorry and that's it for
14:56the sense site sent sound we're going to
14:59keep the same because you don't know if
15:01the sound is coming from your team
15:02member or not just hear a sound You're
15:04Gonna Go investigate even if it's coming
15:05from a team member
15:07uh damage though is an interesting one
15:09because
15:10um after this we're gonna make sure that
15:12actors on your same team can't damage
15:15you but sometimes there's an explosion
15:17for example that damages everyone so we
15:19don't want anything to happen if you
15:21sense damage from a team member so we're
15:23also going to check here
15:25if
15:27on same team this function we created
15:33pass our actor here
15:35and again only if we are not
15:40on the same team
15:45and plug this in of course you don't
15:47have to do the knot you can also plug in
15:49on the false but I feel like this is
15:50easier to read on same team not then do
15:53this I like reading this a bit better
15:59all right
16:02um anywhere else that we need to handle
16:04this
16:07I think this is good for now let's see
16:09how this uh looks like so obviously
16:11right now they are all on the same team
16:14by default so if I just play somewhere
16:16here behind them where they don't see me
16:19um
16:21they shouldn't be attacking each other
16:24why are they attacking he's team number
16:26two
16:28he's team oh he's team number three okay
16:32so actually it was working but yeah
16:34let's make them all the same team let me
16:35just start by two to make sure we don't
16:37have any weird Behavior so he's team two
16:40and he's team two
16:42right if I'm gonna play from here
16:45they're not gonna do anything of course
16:47if they see me now they're gonna attack
16:49me because I'm team number one
16:51and now if I change this guy to team
16:53number one as well
16:56uh and I play from here
16:59then they start attacking each other
17:02great
17:04um
17:05and
17:06um also because uh I'm team number one
17:09if I have only one enemy so if I remove
17:12this guy this guy is now team number one
17:14like me and he sees me he's not gonna do
17:17anything and if I damage him he's just
17:20he's just not gonna be happy about it
17:21but he's not gonna do anything
17:23and by the way we we can still block
17:25even though um
17:28even though it doesn't have a sword
17:29maybe we should check first if he has a
17:31weapon equipped or not uh but anyway
17:34um the team functionality is uh is
17:38working now
17:39so if I have
17:42two enemies here
17:44and two enemies here
17:46and let's make them different teams and
17:49watch them fight each other so this guy
17:53is going to be team three this guy is
17:55going to be team three and these are
17:57both team two and
18:00two
18:02all right let me go behind them so they
18:04don't see me
18:06excellent now they'll all be attacking
18:08each other great
18:12um
18:15yes
18:16seems to be working
Modifying Melee Attack To Not Damage Team Member
18:18now let's make sure that we don't
18:20enemies on the same team can't damage
18:23each other and why is this important
18:26um because
18:28right now if I look at my melee enemy so
18:30if I open up my EP
18:33enemy melee here
18:36uh you can see in my attack I do a
18:38sphere trace and as soon as this sphere
18:41Trace hits something I call take damage
18:43on this actor that we hit I don't check
18:45this actually on the same team or not
18:47so that means if I'm standing between uh
18:50one of my team members and an enemy
18:52I'm the one taking damage and it's not
18:55enough here to just say
18:57um if we're on the same team then don't
18:58take damage because then the person
19:01behind me should take the damage like if
19:05um I'm standing between these two
19:06enemies right here and this enemy is
19:09trying to attack this one
19:10then he should still be able to attack
19:12him even if I'm in between them this
19:15means that we can't do a single sphere
19:17Trace we have to check did the sphere
19:19Trace hit a team member no then do
19:21another sphere trace and check if it
19:23hits another uh one that's not a team
19:25member luckily we don't have to keep
19:26doing multiple sphere traces ourselves
19:28there's something called a multi-sphere
19:31Trace
19:33um and it does the same thing as a
19:35sphere Trace but instead it gets you a
19:37list of everything that it hits so then
19:40we're gonna do a trace we're gonna get
19:41all of the actors that were hit in this
19:43trace and check which one is not a team
19:46member and damage that one because of
19:49course a sword swing can damage multiple
19:51enemies not just one
19:53um so this is really important
19:55so let's replace this sphere Trace with
19:57a multi-sphere Trace
19:59um now everything is going to pretty
20:00much be the same so you can take this
20:02pin here the start is going to still be
20:04the start and it's going to be the end
20:06radius is going to be also 20 object
20:10types take it from here
20:12and also this execution pin goes here
20:15this goes here and now this is the only
20:18thing that's going to be different right
20:19so
20:22um now instead of having one hit
20:27structure we have multiple an array of
20:29hits
20:31so we're going to Loop over this array
20:35so I'll do a for each Loop
20:37and only if there is a hit
20:40so under the true here Duo for each and
20:43then plug this here
20:46all right so if I do this
20:48um something weird is going to happen
20:50and let me show you before we do
20:51anything first
20:53let me start by deleting all these
20:56enemies and have I deleted the floor and
20:59have one enemy
21:00so just for you to be aware I'm going to
21:03set the damage to 10. so the enemy can
21:05only do 10 damage but look at what
21:07happens uh when I play
21:10obviously my health is a hundred so I
21:12should only take 10 damage but I took a
21:14lot more than 10. I think my health is
21:1650 actually but I took a lot more than
21:1810. and the reason is multi-sphere Trace
21:21can overlap with the same actor multiple
21:23times so if I print here let's say print
21:27this actor
21:29look at what's being printed on the top
21:32left here player was printed one two
21:34three four five six seven like about
21:36eight or nine times
21:37so before actually calling take damage
21:40or checking if we're on the same team or
21:42not we want to check have we previously
21:44hit this actor or not because we want to
21:47make sure we only hit the actor once per
21:50sword swing we don't want to hit the
21:51same actor multiple times
21:54um so we need two things to check
21:56whether we hit this actor or not and
21:58whether they're on the same team or not
21:59so I'm going to create a function for
22:01this but I'm going to create it in our
22:03bpc
22:04attacks so this is our attacks actor
22:07component so right click here and edit
22:09the bpc attacks
22:11and I'm gonna create a function call it
22:13damage all non-team members
22:19and this will take us input the hits
22:21array so this array here because we want
22:25to Loop over it so I was going to take a
22:28hit
22:29hits and it's going to be of type
22:32hit results
22:34and then make sure next to the hit
22:36result click on this and make it an
22:38array so it's going to take this and
22:41it's going to return the uh actors
22:45damaged
22:48and this is going to be of type actor
22:52and is also going to be an array because
22:54it's the array of actors that were
22:55damaged all right so first thing is we
22:59need to Loop
23:00over these array over these hit results
23:04and then we're going to break and break
23:07each hit result and get the actor from
23:10it
23:11and check uh get team number of this
23:14actor
23:15so first we want to check is this actor
23:17on my same team or not
23:20so to get my same team notice that we
23:23are in the bpc attacks so to get the
23:26owner we say get owner the actor that is
23:30using this actor component we're going
23:32to call get team number
23:35so we're going to check again if they
23:37are equal or not so not equal
23:41so if they are not equal then this
23:44person is on a different team right so
23:47then we will proceed by damaging them so
23:49plug this here branch
23:53so we're gonna again get this actor and
23:56call take
23:58damage
24:02all right now the damage causer is also
24:05get owner
24:07uh but what's the damage info well we
24:09want to also make this an input to the
24:11function so the function will provide
24:13this so you can drag off this pin here
24:14and drop it
24:16to make it a input tier damage info
24:21all right so now we handled the check if
24:24we're damaging someone on the same team
24:25or not but what about damaging someone
24:28we've already damaged before
24:31so to do that we're going to create as
24:34soon as we damage someone we're going to
24:35put them into an array and then check
24:37the next time if they're in this array
24:39or not
24:40so we're going to create a local
24:42variable local means it's scoped to this
24:44function it's not used outside this
24:46function so it keeps it cleaner
24:48and it's we're going to call it
24:51currently damaged actors or actors
24:57damaged so far all right and this is
25:01going to be of type actor
25:03object reference and also make sure over
25:06here to click this make it an array
25:09so as soon as we damage an actor we're
25:10going to get this array of actors
25:12damaged so far and we're going to say
25:14add unique make sure not to do add but
25:16add unique
25:18because if we encounter the same actor
25:20again we don't want to add them a second
25:21time
25:22and the actor will be this actor here
25:25from our hit actor
25:28all right
25:30so oops so then we uh
25:33add
25:35to this array the actor that we just
25:37damaged but then before actually
25:39damaging them we need to check are they
25:40already in this array which means that
25:42we damaged them before
25:44so we can check it somewhere here so in
25:47this condition if they're not on the
25:50same team
25:51and we didn't damage them before so to
25:54check if we didn't damage them before we
25:56get this array and say contain items so
26:01again sorry if we say
26:03contains item
26:05and the item is our actor here just make
26:09a redirect node here
26:11so if this array contains this item
26:15not
26:18then we continue right so if the array
26:19doesn't contain this item which means we
26:21haven't damaged this actor before and
26:24let's make an and Boolean here to put
26:26both of these
26:29and this is now our new condition
26:31so our condition is we are not on the
26:34same team and we haven't damaged them
26:36before then proceed to damage them and
26:38add them to the array of damaged actors
26:41and at the very end we want to return
26:43the actors damaged uh don't don't plug
26:46this in here because this is again on
26:48the loop body we want this to be when
26:50the loop has completed so off of
26:53completed here
26:56and let me also just make this a bit
26:58straight
27:01what do we want to return we want to
27:03return our actors damage so far because
27:05we completed the loop so these are all
27:07the actors that we've damaged
27:12and that's it so this function will now
27:16damage all of the actors in This array
27:19but let's see how we can use it so we
27:21don't need this Loop we don't need this
27:23and we don't need the take damage
27:26now all we need to do is off of our bpc
27:28attacks
27:30say damage
27:32damage all non-team members
27:37and we're going to pass the array of
27:39hits from here
27:42oops
27:44and the Damage info will be this
27:48and then you can do something with the
27:49actors that you've damaged if you want
27:51for now I'm not going to do anything
27:53but let's see how this looks like now
27:56um
27:57if I print well actually okay let me
27:58Loop over all of them so for each
28:01and let me print
28:03so we're going to print each actor that
28:05we damaged and now I should only see my
28:08name being printed once
28:09yes perfectly and I took 10 damage and
28:12yes my health was indeed 50. so now I'm
28:15getting damaged only once
28:17now let's see and let's make sure that
28:19multiple enemies can be damaged as well
28:23so
28:24um I am going to create another enemy
28:27here and I'm gonna make him on my same
28:30team so on team one
28:34and I'm going to stand in between them
28:36and make sure that we both get damaged
28:40come on attack yeah
28:43yeah we both got damaged so I got hit
28:46and he got hit from one sword swing
28:48perfect
28:51um oh and I should not be getting hit
28:52from the one that's on my team so let
28:55them hit each other ones first
28:59yeah so we both got damaged but this guy
29:01shouldn't be damaging me right so you
29:04should only damage the other actor
29:06so I'll try to hit perfect yes he didn't
29:08damage me nice
29:10so this is working as expected let me
29:13remove the print now
Modifying Ranged Attack To Not Damage Team Member
29:18also the ranged enemies attacks so in
29:22and this is we do it here in our bpc
29:24attacks we have this uh fire bullet
29:28so fire bullets also does a single line
29:30Trace
29:31um from the ranged enemy to their target
29:34and if it hits something it causes take
29:37damage on that something as well
29:40so here we want to do the same thing we
29:42want to check if
29:44um we're on the same team or not but we
29:47don't want to damage everyone because
29:50well maybe you do maybe you want the
29:51bullet to be able to go through multiple
29:53enemies so it hits the first enemy the
29:54second one and so on in the line but
29:57what I wanted to do is actually so if my
30:00let me get a ranged enemy here
30:03so if this ranged enemy is targeting
30:06this melee enemy
30:08but this one is in the way
30:11if this one is in the way and they're a
30:14team member I want the attack to go
30:16through the team member so this one is
30:18targeting that one and this one is a
30:20team member of the ranged enemy I want
30:21the bullet to go through the team member
30:23but if this one is an enemy
30:26and even though this ranged enemy is
30:30targeting this one
30:31but it hits another enemy while on the
30:34way to their original targets I want the
30:36one in the middle to be hit because it's
30:38more realistic if you're firing a bullet
30:40at someone but it hits someone else then
30:42they're the ones that take damage unless
30:44they're on the same team this is of
30:45course where the unrealism of games
30:48comes into play we'll have the bullet
30:50just go through straight straight
30:51through team members
30:53so we are also going to need a multi
30:55sphere trace for assault multi-line
30:57trace for this so this line Trace we're
30:59going to replace it with a
31:03multi-line trace for objects as well
31:08all right and plug in almost everything
31:11as well let's start to the start and to
31:14the end object types uh
31:20and anything else
31:22plug this here and this condition
31:28all right
31:32yeah and also we want to I'm not sure I
31:34don't really have this actress to ignore
31:36we want to make array and ignore the
31:39owner so we never hit ourselves that's
31:42important
31:44um
31:46all right so now that we have this uh we
31:49are going to
31:50replace a take damage as well
31:53buy something else
31:55this time we're not going to call damage
31:57all non-team members because like I said
31:59I don't want the bullet to go through
32:00all non-team members and damage them
32:02maybe this is what you want but I'm
32:04going to create a new function and call
32:05it damage first
32:08non-team member
32:11so the first non-team member you
32:13encounter damage them and then ignore
32:15all the rest
32:17so this also takes an array of hits
32:22you know not get hit
32:26um and it returns a single damaged actor
32:29because we're only damaging one actor so
32:32actor object reference and make sure to
32:35change this from array back to single
32:38uh oh and it's also going to take the
32:40damage info
32:42oh
32:43damage info which is a damage info
32:47struct
32:52all right so this time we're going to do
32:55a for each Loop but make sure to choose
32:58for each with break
33:00for each with break it gives you this
33:01additional break execution pin which if
33:04you enter this pin you stop the loop you
33:07break from the loop because once we
33:09encounter our first non-team member we
33:11want to break from the loop we don't
33:12want to keep looping
33:14um so we're going to Loop over all of
33:16these hits we're gonna break the hit
33:18result this is a different break than
33:20this one
33:21and we're gonna get the
33:24team number
33:25of this actor
33:29and we're going to get our owner so this
33:33is the ranged enemy or whomever is
33:34calling fire bullets and get team number
33:37of the owner as well
33:39and check if this is not equal to this
33:48a little bit here
33:51um if this is not equal to this then we
33:54are going to
33:57call take damage
34:02on
34:04this actor
34:12and the Damage info will be this damage
34:15info and the Damage causer will be get
34:17owner
34:19and then once this condition is true
34:22we're going to break so pull over off of
34:25here and put it in the break and also
34:29let's clean it up a bit
34:35yep
34:39all right and then we want to return the
34:42damage actor oh if you want to return
34:43actually then we need to do something
34:44before we break we need to call it
34:46sequence because we're going to do two
34:48things
34:49first we're going to break
34:51well
34:52first we're gonna break then we're gonna
34:54return
34:55because you can't do anything after the
34:58return so first you have to break and
35:00then return and in blueprints returning
35:03doesn't automatically break from the
35:04loop if you return the loop will still
35:06continue
35:07and this is our actor
35:13alright so we check if they're not on
35:16the scene we Loop over all the hits we
35:18check on the first one that's not a team
35:20member call take damage on them and then
35:23break from the loop if we don't want to
35:25Loop anymore and return this actor
35:29so back here in our event graph then
35:31we'll call damage first non-team member
35:34pass in the array of hits pass in the
35:37damage info
35:39from here
35:42um and we are doing a report damage
35:46event here which requires a damaged
35:48actor that's why we returned it so we
35:50can just plug this damage back through
35:51here
35:53and of course
35:55um
35:58this is pretty much all we need let's
36:00draw the debug
36:02so that we see what's happening
36:04and let me show you how this works so
36:07I'm going to delete this enemy and I'm
36:09going to make sure these two are on the
36:10same team so this is team two and this
36:13is team two
36:14and I'm gonna try to stand behind him
36:18so
36:20bullets went right through him so you
36:21see there are hits but they're all red
36:23so the Bullet went right through him
36:25again I'm going to show you now this
36:28time it didn't uh hit him I wasn't
36:30standing correctly
36:32all right stand stand come on come on
36:36yes do it hit yes perfect so it goes
36:39right through him and hits me
36:41now if he was an enemy so I'm gonna make
36:43sure he's an enemy now but they're both
36:45going to be attacking me
36:47so this guy is team two and this guy is
36:52team I don't know three so we're all now
36:54enemies of each other we're all on
36:55different teams
36:57um but I'm gonna make them both see me
36:59first so that they attack me
37:02instead of each other
37:05all right so now if I stand between him
37:08come on come on come on shoot
37:11he's the one that got damaged see and he
37:13blocked
37:14all right and I noticed that the and
37:16melee enemy is always blocking and I
37:18think we forgot to return the block
37:19chance yeah so the blockchains is one
37:22they'll always be blocking let's put it
37:23back to 0.25 like it was
37:27um
37:29all right
37:30and let's let's also do a uh sort of a
37:35multi
37:37enemy battle here to see so we're gonna
37:39have
37:40uh
37:43let's say melee enemies all on the same
37:46team team two team two
37:49team two versus
37:51ranged enemies all on team three
37:58and let me stand behind them so they
38:00don't see me and let's see what this
38:02looks like
38:04nice so they're all going to be
38:07uh the melee enemy is still pretty good
38:09at blocking
38:10is it still at 100 no no he's okay he's
38:13getting hit it's okay
38:18looks really cool
38:23um and as you can see we have two uh
38:26melee enemies or actually all three are
38:28attacking the same Target uh maybe
38:30because they saw this target first
38:33um one thing we can do to modify our
38:35targeting system is to make sure that uh
38:38let's say if the enemy attacks a Target
38:40and this target already has someone
38:42attacking him by let's say they don't
38:43have any tokens then they can try to
38:45switch to
38:46um to other targets now we can do we
38:49haven't really done anything with
38:51targeting so far so maybe we'll be
38:53touching on targeting systems in the
38:55next tutorial
Fixing Bug
38:57all right sorry one last thing before we
38:58close I noticed a bug that's if
39:01um this enemy is now on my same team but
39:03if I damaged him and he doesn't block
39:06he's gonna try to attack me and then his
39:09damages his attacks won't do anything
39:11because we're on the same team but why
39:12did he try to attack me even though
39:14we're on the same team
39:16I noticed that well we handled the sense
39:19damage and if you sense damage you don't
39:21attack but we didn't handle in our base
39:24enemy on the hit response on the hit
39:26response here we passed the damage
39:30causer
39:31if there is no last known attack Target
39:33if there is a last known attack Target
39:35they'll use that one but otherwise
39:36they'll use or actually the other way
39:38around
39:40um
39:42so attack targets if there is no last
39:46known attack Target yet indeed they will
39:48use the uh this new attack Target
39:51so we need to change this to also check
39:54is this attack Target on your same team
39:56or not otherwise don't do anything
39:59so we're gonna add another check here
40:03um let's get the from this attack causer
40:07let's get the team number and let's
40:10control drag all of these here
40:13and we are going to check if the get
40:16team number is equal to my own team so
40:18I'm going to say get team number make
40:20sure to call this one the function call
40:22that's on target is enemy base
40:25because this is our own get team number
40:27or actually don't need to call again
40:28team number you can just get the team
40:30number variable here
40:32so if
40:34um this get team number is not equal
40:40to this skept team number then proceed
40:44as you would
40:47um
40:48oops sorry we need a a branch here
40:56all right
40:57uh but what if it is equal sorry yeah so
41:00what if I am on the same team
41:03well if I'm on the same team I still
41:05want to
41:06be straight I still want to call set
41:09State as attacking but this time I don't
41:11want to pass
41:13um an attack Target I only want to pass
41:16a
41:17um the use last known Target so actually
41:20instead of a branch you can do a select
41:21node not to be a bit better
41:23so here do a select
41:27on this Boolean value
41:29so if we're not on the same team then
41:31just pass in this
41:36and on the false you don't pass anything
41:37so if we are on the same team then don't
41:40pass anything and keep use last known
41:42attack Target
41:44and by the way if last known attack
41:45Target and attack Target are both not
41:48valid then the enemy won't do anything
41:49so let's test this out now I damaged him
41:52he doesn't do anything because hey he's
41:55my team member what am I gonna do
41:57nice
41:58and that's it
Outro
42:01as always thank you all for watching I
42:03hope you enjoyed this part and if you
42:04did please consider giving a like And
42:06subscribe and if you want to download
42:08the full project files then consider
42:10joining my patreon where you can also
42:13join for a free seven day trial and
42:15download everything if you want to do
42:17that and you can find the link in the
42:19description as well as right here and I
42:22haven't decided yet what to do for the
42:24next part so if you have any suggestions
42:26or if you want to learn something
42:28specific then please leave it in the
42:30comments below and I'll see you there
42:31[Music]
42:45thank you