Hello guys.
Welcome to the video.
In this one I want to show you how to make a ghost enemy.
This ghost will appear from a random point.
It will fly towards the player and then it will disappear after some time.
That's what we need to do.
Before we do that though, let's do something to improve logic of flying enemies.
So first of all, maybe I'll take the bet.
I'll place it over here and I'll decrease aggro radius to something like.
That.
All right.
Now let's go to layers.
Let's add.
Enemy fly or something like that.
Yeah.
So basically flying enemy maybe let's do flying enemy and then let's go to Edit project settings.
We need to disable collision between flying enemy and other enemies and also between flying enemy and
ground.
That's what we need to do because enemy not supposed to interfere with platforms, even though we're
using movement with a vector to move towards.
And it does not bother us.
Now, just in case I want to do things right now, let's go to prefab.
Let's take players prefab and let's change what is enemy to enemy and flying enemy.
We just need to hold shift and click flying enemy as well.
Like that.
An enemy bet itself can be flying enemy now.
Now this object only.
And then I'm going to apply overrides.
Very well.
Now we want to make a ghost enemy.
Let's go and check the graphics.
Sorry enemy.
Ghost.
Here it is.
Idle it.
Uh, ghost particles appear and disappear.
So this is what we want to do.
Uh, how can we do this?
First of all, we need to take them all.
Make pixel per unit 16.
Then let's do prefab unpack completely for the bed.
I think we're not going to use it now.
It will only make things harder to test.
So I'm going to do unpack completely and let's change it to enemy ghost.
All right.
Now, uh, let's take maybe idle sprite, give it to sprite renderer over here.
Here we have a ghost now.
And let's go to animations and make animator controller enemies.
We're going to make a folder ghost.
Let's go inside and let's make animation.
Animator controller enemy.
Ghost make.
I'm going to sign it over here.
And then we need to create a bunch of animations.
Enemies.
Sorry.
We need to create, uh, enemies.
Ghost.
We're going to have enemy.
Ghost.
Uh, move!
There's an idle animation, but it will be used for moving.
So let's just do move here.
And then we're going to go to graphics enemies.
Uh, ghost.
Let's take this idle animations and drag them here.
Sample rate 20.
So this is how it looks.
I think it can be used for flying as well, so I it's fine, I guess.
I like it this way.
Now let's make another clip.
Enemy ghost hit.
Going to take this hit.
Drag it here.
Sample rate 20.
Then we want to go and make.
Enemy ghost appear and disappear.
So maybe let's call it that appear.
I'm going to take animations of appearing.
Sample rate 20.
Let's see it.
Yeah, fast enough, but it's okay.
And we also need new clip.
Enemy ghost disappear.
And we're going to take these sprites over here and drag them here.
Sample rate 20.
Regarding the particles, I'm not sure I want to use them.
Just some particles.
Well.
We could basically take the dust effect we have and just reduce the emission to make the amount of particles
less than we have on a dust.
But I think I'm not going to use it.
It's okay.
Now let's go and, uh, think how it's going to work.
We need a script on this.
So I'm going to go ahead to scripts folder enemies and we're going to make.
Enemy ghost.
Okay.
Let's put it on the script.
I mean, on the game object, enemy ghost.
And let's go inside of the script.
We're going to inherit from the enemy as well as always.
Then we want to make a header.
Let's do, uh, let's do ghost details.
And then I just want to explain how it's going to work.
So we're going to have an idle timer and we're going to have an active timer.
While ghost is idle.
It's going to be invisible.
And it will not chase the player.
It's going to be basically not there.
And then when ghost is active, it's going to appear from the random side of the player, and it's going
to move towards the player and it's going to feel threatening, like he's always chasing you and you
don't know from which side he's going to jump.
Before we do entire functionality, let's just make him appear and disappear with a cooldown.
Okay, so I'm going to do serialize field, private float active duration, and I'm going to make Private
float Active timer.
Then let's override update.
We're going to do active timer minus equals time dot delta time.
Oh and also we need private bool is active.
Then we need two methods private void start chase.
And we need private void and Chase.
In the update we're going to do a simple check.
If is active is false and idle timer is less than zero.
It means we've been idle for long enough and it's time to chase the player.
And we're going to do start chase.
Then if we are chasing the enemy, I mean the player.
So else if is active and active, timer is below zero.
So time to chase is over.
We're going to do end chase just like that.
Inside of these methods, we need to do something super simple.
When we start the chase, we just say that active timer is equals to active duration and is active.
True.
And when we end the chase we're going to do idle timer equals to idle duration.
So it's going to be idle for a while.
And we're going to do is active pulse.
And maybe let's rename this to is chasing.
Yeah a bit better.
More logic in this.
And I think this could be good enough, but I want to trigger animation as well.
So before I forgot this let's do anim triggers.
We're going to do anim set trigger.
Of, uh.
When we start Chase, we appear.
So I'm going to do appear over here with a small letter, and then we're going to need disappear.
Disappear.
Okay.
Uh, let's go back to unity now.
Over here.
We're going to select animator of the ghost, and I do not see any animations.
So I will have to restart unity.
Give me a sec.
Okay.
Here are the animations.
Let's move any state over here.
Ghost heat over here.
Move over here.
Appear and disappear.
Okay.
So we need two parameters.
Three parameters.
One of them going to be heat.
This is for, uh, making enemy die.
So I'm going to use condition heat duration zero can transit to self and check.
Then in the animator.
It doesn't really matter how we do it here, because it's going to be pretty much the same anyways.
And let's go and copy the name over here.
So I will not make any mistakes because I'm like that.
Um.
Disappear.
And then.
Ah!
We're here, I'm here.
Trigger.
Appear.
Okay, so while we move, we can do transition to ghost appear.
Let's do appear.
Transition duration zero.
Exit time and check.
Then we're going to transfer back to move with the exit time of one, transition duration zero, and
we need to do same for disappear.
So we're going to transfer here with the trigger of disappear.
Transition duration zero as exit time, uncheck and transition back will go with the exit time of one.
Transition duration zero.
So basically it will play animation once and then it will go back to Ghost Move.
Now let's go back to Scene view.
Let's take the anime ghost and we want to assign ground check over here.
What is player.
Sorry.
What is ground?
What is ground and that should be it.
Let me check colliders.
This is Box Collider.
Barely visible, but it's fine.
And then.
Damage trigger.
Like that.
Should be okay.
All right, now let's go over here.
Let's make active duration equals to 1.5.
Idle duration is 1.5, and if I'm not wrong, it's supposed to just appear and disappear.
Now.
Appeared.
Disappeared.
Appeared.
Disappeared.
Very nice, very nice.
Now let's make something else.
Let's make this ghost transparent every time it disappears.
There are many different ways to do that.
I think I'm going to do this with the help of animation events.
And let's go somewhere below.
And let's make private void.
Make invisible.
This will do.
SR we have sprite renderer, I'm sure of that.
Let me check enemy.
This one is private.
Okay, I'm going to make it as protected.
All right, let's go back.
And we're going to do this.
Our color.
This is invisible.
So I'm going to do color dot clear.
And then we're going to do private void make visible.
It's going to be SR color equals to color dot white.
Very nice.
Let's save this.
And let's go and try this again with the disappearing, uh logic.
You're going to go to enemy ghost appear.
And every time we appear over here, we want to make ghost visible.
So enemy ghost methods make visible.
Then we want to go to enemy ghost disappear.
And we want to make it transparent every time we disappear.
Maybe one frame after that.
Over here.
Enemy ghost methods make invisible.
Now this is supposed to work.
I just want to see this.
Also, I'm a bit worried that we will not see all of the frames of animation.
So I'm going to take these frames, move them like so.
So first frame will make it visible.
Then it will play the animation, but it will be so fast we will not notice an extra frame.
Let's go to play mode.
Visible.
Invisible.
Visible.
Invisible magic, right, I love it.
Now we also need to disable colliders so it will not damage enemy and it will not be killed.
And we have logic with the colliders over here, but since we need it for the second time, I guess
we can extract it as method.
I'm going to do extract method enable colliders.
We're going to pass a boolean over here, same as we did before.
Enable.
Then we're going to pass enable over here and over here we're going to say false.
So it's just the same as it was before.
Now we can go to enemy ghost and we can expand these methods.
And when we make it clear and invisible, we're going to do enable colliders.
Oh, I'm sorry, that method is private.
Let's go and fix it.
Let's make it as protected.
Okay, I'm going to save it.
Go back here.
Enable colliders polls.
Then we want to extend this method over here.
Enable colliders.
True.
Okay.
Very good.
Now, this is half of the job that we need to do.
Uh, once we start the chase of the player, we want to place ghost at some random position around the
player.
I know from a testing and from experience that we should not have a very big position on the Y, probably
something like from 0 to 10, a random one.
And for the X should be at least five, maybe on the x.
So let's go ahead and make some variables.
I'm going to make a space and then I'll do serialize field, private float.
X mean distance, then I want to have serialized field private float y.
Min distance and serialized field.
Private float y.
Max distance.
That's all what we need.
Now we're going to go back to start Chase method.
And over here.
First of all, we want to check if there are players on the map, because if there are no players on
the map, then we're supposed to end the chase immediately.
We're not supposed to even start the chase.
So this is what we're going to do.
We're going to make list of player right here.
Sorry.
Player list and we need to go here.
Click alt enter using system generics then equals to player manager dot instance get player list.
So this will make a list inside of this method.
And it will fill it up and make it equals to players list on the player manager.
Then we're going to check if player list dot count is less or equals to zero means we cannot do any
change because there is no one to chase.
So we're going to end Chase immediately and we're going to return from this method.
And if that's not the case, then we can move on.
And first of all, we would like to find a target that we want to chase.
So let's go ahead and make a variable private transform.
Target like that.
Then we can go back to start Chase method.
And we want and we want to make target equals to random player from the list.
So I'm going to do int random.
Index equals to random range from zero to player list dot count, and then target equals to player list
with a random index dot transform.
Nice.
So now we find the target is going to be random player from the list.
After that we want to calculate the position that we will have for this ghost.
So I'm going to do so I'm going to do float y position equals to random range from mean y distance from
y minimum distance to y.
Maximum distance is going to be random y.
And for the x we don't want to have position because we have only one value minimum x distance.
But we want to have the offset.
Uh the offset will be very simple.
It's going to be either 1 or -1.
And because of that, uh, ghost will appear sometimes on the left, sometimes on the right.
That's all what we want to do.
So let's do y x offset equals to.
And over here I want to do a quick if statement.
Uh, before I do that let me show you how it looks without quick if statement.
So we do fly.
So we do float x offset equals to one.
Then if random range between 0 and 100 is less than 50 then it's 50% chance to turn it into x offset
equals to minus one.
So this is how you can write it.
Or you can write it this way equals two.
We're going to ask random range.
From 0 to 100 is less than 50.
If yes, do minus one.
If no, do one.
And it's a bit cleaner and prettier.
So we've got the offset and the Y position.
Then we can take transform position and make it equals to target dot position, which is a players position
plus new vector three with x minimum distance multiplied by x offset and y position.
Just like that.
And this will make ghost appear from different sides of the player.
Let's go and see this.
And then we only need to make it move and it's going to be it.
Let's go and try.
I forgot to set values over here.
Let's do x minimum distance five y minimum distance.
Let's try random from maybe -7 to 7 okay.
So they're going to be a range on the Y.
Let's go and see this.
It disappeared because there is no player I'm going to respawn and then it appears from random size
of the player.
Wait.
I don't see it.
Oh, there it is.
Very nice rate.
Yeah.
Really nice, I love it.
Now let's use it and let's make him move towards the player and also face the player.
You're going to go back to script.
Um.
I guess when we start the chase, we can do handle flip.
Wait about what?
If a player jumps over the ghost or runs below it?
Then we need to do it in the movement method.
Yes.
Uh, let's go and make.
Private void.
Handle movement.
If can move equals to false, then we return same as before.
And then we do transform position equals to vector to move towards from transform position to the target
dot position with a move speed multiplied by time dot delta time.
Just like that.
Then we want to handle movement over here.
And probably we should stop movement when we kill the ghost.
So let's go and override.
Uh die method and do can move equals to false.
I don't want to stop movement in the base method, because it is funny when mushroom is running and
you kick him and he is flying to the direction that he was running, I love it, so I'm going to keep
it.
But other than that, I think we're good.
We don't need to do anything else here.
Uh, let me go and see this.
There is a ghost.
Ghost enemy.
I'm going to give him off speed of maybe four.
Just when I feel.
How dangerous he is.
And I respond, oh no, he's not facing me.
Oh, did I kill it?
You.
This is so funny.
Okay, I've seen him jump into a new location after I killed him.
That is not what we supposed to have.
So first of all, let's go to animations enemies.
Ghost.
Let's take this animation appear, disappear and hit disable loop time.
Then let's go to the script.
We're gonna go here and do something very simple.
If is dead, then return.
This is supposed to help.
He will not get new position.
And yeah, if you want, you can turn this into a boolean for sort of clearance, but I think it's fine.
And was there something else I forgot.
I forgot what was.
Is it okay?
I don't remember.
Just.
Our flipping.
Yes!
Oh, my.
Can you imagine?
Over here we're going to do a handle flip according to the target position.
Dot x.
Yeah.
This is good.
All right.
Thank you so much guys.
This was amazing and pretty fun.
Yeah I'll see you in the next video I guess.
By.