Hello guys.
Welcome to the video.
In this one we're going to make another enemy.
This time it's going to be enemy that shoots bullets.
It's going to be easy to do quite fast one.
And I want to say that I guess we're going to make maybe 2 or 3 more enemies, and then we're going
to be done with enemies for now, because we need to develop other parts of the game.
We cannot make enemies only, and I think this setup will be enough to make a base game, and other
enemies can be as additions later on, sort of a, you know, DLC.
Okay, so I'm going to remove a chicken and I'm going to remove Rhino and I'm going to duplicate the
mushroom.
Let me duplicate it, move it down over here.
Then we're going to do a prefab.
Unpack completely.
Let's change the name to Enemy Plant.
Then we want to replace sprite on a sprite renderer we need to go to graphics enemies.
Plant.
Let's take the idol and make sure they all have pixel per unit 16.
Then let's take one of the sprites and drag them on a sprite renderer over here.
Very good.
Now we need to reset Collider and we can take away this script.
So I'm going to remove it.
Gonna reset Collider and going to adjust it to something like.
This.
Yeah.
Very nice.
Now let's take damage trigger.
Make it.
Wider like so.
Maybe.
Yeah, this should be fine.
Now I'm going to move it down.
And we need an animator controller for this one.
And script.
And let's go quickly make a script.
Can I name it as enemy plant?
I'm gonna put it on the enemy.
I'm going to put it on the enemy.
And now we're going to go to animations enemies.
We need a new folder for plant.
And let's go inside and let's make animator controller enemy land.
Okay.
Gonna drag it to this field over here instead of mushroom.
Then we're going to go to Animation Window and create a couple of new clips.
One of them going to be Enemy Plant Idle.
We need to go to graphics folder.
Enemies land.
Let's take the idle sprites.
Put them here.
Sample rate 20.
Now we're going to go and make a new clip.
Enemy plant attack.
Let's take the attack animation.
Drag it here.
Sample rate 20.
And we need one more hit.
So I'm going to do create new clip enemy planned hit.
I'm going to take these sprites drag them here.
Sample rate 20.
Before we go to animator we need to go to Asset Animations Enemies plant.
We're going to take these.
Hit and attack and we need to uncheck loop time over here.
This is important.
Okay this is good.
Now we can go to animator of the enemy plant.
We're going to have idle by default.
And we're going to need two triggers.
One of them going to be hit to trigger animation of the death, and another one going to be trigger
attack to trigger attack animation.
Let's make transition from any state to enemy planned hit.
Over here.
Hit and transition duration zero and transit to self uncheck.
Then for the attack, we're going to transfer to attack.
If trigger was called, let's select it.
Choose attack trigger.
And check exit time.
Transition duration zero.
Then we're going to transfer back to idle after let's say one.
So exit I'm going to be one.
Transition duration zero.
We're going to play animation once and then go back to idle.
Very good.
Most of the functionality is ready.
Let's go to enemy plant.
Let's go inside of a script.
Over here.
We're going to inherit from the enemy.
Enemy.
And then we really have most of the functionality.
Let's override update.
And let's make a method private void.
Um.
Attack.
This method will set trigger of the attack parameter.
Then in the update I'm going to do, if player detected is player detected then attack.
All right.
So basically this is enough to make an attack.
It's not going to be perfect.
We still need to do a bunch of things.
But for now let's go and see this.
Let's see how fast it was and how easy.
Let me do close all by this and let's go back to unity.
We have a plant here.
Let's make.
What is ground?
Ground?
Let's assign ground.
Check over here.
What is player?
Player.
And I think.
Uh, what else do we need?
We can take ground check and move it down a little bit, but it's not as important because the enemy
plan is not going to move anywhere.
So these parameters are here, just, you know, just to be there.
Really.
Okay, uh, let's go to play mode.
So plant stands in idle.
I actually bit in the air.
So we're going to fix that.
And I'm going to jump and be triggering attack animation.
For now, this is quite fast and that is the problem.
And we're going to fix it also.
By the way, there is a message parameter x velocity does not exist on the animator because this one
now is uh, in the method handle animator.
And it is called in the update all the time.
And it is also called on the update over here.
So somehow we need to solve this problem over here.
How can we solve this?
Uh, we don't need this enum set float on the enemy planned.
Really?
Uh, let's try this.
Let's go to enemy planned.
Let's go.
Override handle animator.
And over here we're going to remove base.
So now there's going to be empty.
Animator and enemy plant will call this method in the update instead of the one that is in the base.
And because it is empty we're not going to do anything.
So.
Keep it empty.
You need to update parameters.
Okay.
Very good.
Now, uh, let's go back.
Now let's go back and.
Fix that collider on the enemy plant.
Gonna just raise it a bit like so.
And take the plant itself.
Move it up.
Yeah, this should be good.
Now, let's keep talking about the attack functionality.
We need to make cooldown for the attack because now it is too often for us, right?
We don't need it like that.
Uh, for that we can use time dot time.
If you never heard of a time dot time, it basically returns the info of the current time in the game
since the game begun.
Let's make, uh, header.
Land details.
And over here I'm going to make public float.
Last time attacked.
Then every time we attack, I'm going to do last time attacked equals to time dot time.
Now let's go back to unity and see what's the value is equals to when plant is attacking.
So from the start of the game we can see it is zero.
We're going to go to play mode.
He is.
It is zero.
I'm going to jump into the view of the plant and we have 3.5.
And every time he attacks, value is updated.
Right.
So we can use it to detect if plant is ready to attack again once cooldown is over, or if cooldown
is not over.
We can do that simply by checking time dot time at the moment of his attack.
And if time to time at the moment of his attack is bigger than last time attacked, plus cooldown,
then we are ready to attack again.
Uh, I'm going to go here and quickly try to explain.
Let's make.
Let's make a boolean over here.
Bool can attack and it's going to be equals to Time.time is bigger than last time attacked plus cooldown.
And I guess we can have a dedicated variable for this.
So I'm going to do serialize field private float attack cooldown.
Let's make it equals to 1.5 by default and use it over here.
Now how it's going to work.
Let me try to explain real fast.
I'm going to put some comments here.
And let's say when we attacked for the first time over here, we registered last time, attacked into
this variable, last time attacked.
So we attacked when it was zero five seconds in the game.
Last time.
Attack is zero five seconds in the game.
Okay.
Next time we try to attack, let's say time to time.
The time in the game is equals to seven, time in the game is seven and we try to attack and we see
if seven.
If seven.
The current time in the game.
Time the time.
This is just example.
I'm trying to explain it this way.
Okay, so if it is bigger than five plus attack cooldown 1.5 F means we are ready to attack again because
seven is definitely bigger than 6.5.
But if we would do this test in the time of let's say six seconds since the start of the game, then
this would be false and we are not ready to attack again.
This is how it works.
So we're here.
We're going to place and can attack.
This is very good because this is basically all what we need to make a cooldown for this attack.
I'm going to go ahead.
And try this.
Let's see this how it's working right now.
Uh, we're going to just jump in front of the plant and we're going to see the time of the last time
attacked and also the frequency of his attacks.
And now we can see that last time attacked is bigger by 1.5.
Every time we use an attack, it's a bit difficult to catch because values are so random.
But let's say I'm going to make it 25 over here.
Okay.
26.5.
28.
29.5.
31 and so on.
So we do attack every 1.5 seconds.
And that is exactly what we need.
Uh, now, let's make bullets for him.
Let's make him shoot bullets and see if this is too easy for the player.
And then we're going to proceed with development.
How do we make a bullet?
Uh, we need asset graphics.
Enemies.
Plant.
And we need this bullet sprite over here.
Okay, let's bring it to the, uh, enemies layer.
Let's rename it to Enemy Bullet because this one will be used by another enemy as well.
Then on the bullet we need rigidbody 2D.
We need to switch off gravity scale for this object.
Also, let's make a interpolate interpolate collision detection continuous.
Very good.
Now we need circle Collider.
Let's make it smaller.
And I know that point three should be okay.
Very good.
Now we need a script for this.
I want to make a new script for enemy bullet.
Sharp script.
Enemy bullet.
Let's place it on the enemy bullet.
Over here.
This will be the object that we use as a prefab and create every time plant is attacking.
We need to go to prefabs and turn it into a prefab like so.
Very good.
Now we can delete it from the scene.
We're going to go to enemy plant and do something here.
First of all, we want to hide this variable because now we know how it is working.
Now we want to have reference to a GameObject prefab.
So serialize field.
Private GameObject bullet prefab.
And we need sort of a gun point, because if we use the, um, transform position of the plant.
Then bullet will be created over here and it will fly from here.
But we want it to fly from here, right?
So let's go to script.
Let's make serialize.
Field.
Private.
Transform.
Gunpoint.
Nice.
Very good.
Now let's go and make a method.
Private void.
Create bullet, in which we're going to instantiate the object.
And before we did instantiate the game object.
But now we're going to need to instantiate game object.
And then we need to get access to rigid body of the bullet or script of the bullet.
So we can give it a velocity.
Because of that, I think I'm going to create a variable of an enemy bullet as a local variable over
here.
And it's going to be equals to instantiate.
Bullet prefab.
At gunpoint.
Position with the quaternion identity.
And over here, instead of having variable of a game object, we can make a variable of enemy bullet.
Now this will be instantiated and together with it we can get access to the script and do something
with it.
But let's not do anything for now.
Let's move to enemy bullet script for a bit.
Let's go to enemy bullet.
So on the bullet, we're going to need a reference to the rigidbody.
Let's make a private rigidbody to the RB.
And we need a wake, which would just get component of a rigidbody.
Then we need a method that we can call to set up velocity of the bullet.
I assume we're going to use this script for other bullets as well.
That fly not on the left and right, but also up and down.
So I'm going to make a public void set velocity which would take a vector two as a variable.
And then over here we're going to do RB velocity equals to velocity.
Then we're going to need ontriggerenter 2d.
And here if bullet is colliding with player, it's supposed to kick the player and then destroy itself.
And if it's colliding with the ground, it's supposed to just destroy itself.
So this is what we're going to do if collision GameObject dot player is equals to layer mask name to
layer.
And here we need to be sure we don't make any mistake I'm going to do.
Yeah.
Let me do string here.
So it's easier to double check.
And I do serialize field private string player layer name.
It's going to be player by default.
And also we're going to need ground layer name.
Ground layer name.
It's going to be ground by default.
Okay.
This is another way to detect collision between objects by using layers.
So over here we can just.
Say that if we collide it with a.
Layer layer name.
Then we're going to do collision get component of a layer.
And then we're going to do um.
What was that?
Knockback.
What's up boy?
Oh, and we need to give it.
Okay.
Transform position dot x.
And then we're going to do destroy game object.
Then if collision game object layer is equals to layer mask named layer.
Ground layer name, then we're going to just destroy game object.
Simple as that.
Again, it could be done differently.
It could be done same way as we did with the damage trigger.
Could be just by using layer matrix in a preference of unity, like in a project settings.
Uh.
Over here.
Our project settings, we could set up collision between Bullet and Player only, but this time I want
to show you how to use, uh, name of the layer to detect collisions.
So this is just one of the ways of doing it.
Okay.
Now let's go to enemy plant.
And over here, after we create a bullet, we're going to do new bullet set velocity.
And here we need bullet speed.
So let's make serialize field private float, bullet speed.
Let's make it equals to seven by default.
And we're going to do bullet speed.
Multiplied by facing direction.
And for the Y, we're going to use zero.
I think we need to turn it into vector two.
I forgot, let's do.
Victor two.
Bullet speed equals two.
New vector tool facing direction multiplied by bullet speed with a zero on the Y.
Okay, when something like this happens, it means you're using same name on a local variable and on
a global variable.
One of the ways to fix it is to use different name.
Or you can just type this over here and then it will use global variable.
From this script you can see it says class enemy planned bullet speed.
But not to confuse us more than we already did.
I'm going to change the name of the variable over here to, um, new velocity.
Okay, now over here we're going to pass new velocity.
Or maybe it's better to use bullet velocity.
Let's rename it Bullet Velocity.
And just in case bullet will fly off the level, maybe you will not have, uh, walls on your level.
We need to destroy the bullet after some delay so we don't create lots of objects, and then they will
fly forever.
So let's do destroy, um, new bullet, a new bullet game object after, let's say 10s.
Okay, now we need to call this method.
At the moment of the attack, we're going to go back to unity.
Find the animation on the enemy plant.
Let's go to enemy plant attack.
Find the frame of the attack.
So I guess it is here.
Yeah.
Over here we're going to add event and choose enemy plant methods.
Create bullet.
Then we need a gunpoint.
So I'm going to make him at gunpoint.
Going to drag it over here.
Let me move this gun point somewhere here.
So bullet will start here and it will fly to the facing direction.
Then on the enemy plant, we need to open Project Asset Prefab.
And assign enemy bullets over here.
Okay, this is done.
Let's go and see this.
And there is the enemy.
I'm standing there.
He shoots!
Oh my God!
This is so random.
Uh, we need to.
We need to go to enemy bullet.
And check is trigger.
Okay, let's go back.
Now he'll shoot me and damage me.
And if we jump away, then it will be destroyed on collision with a wall.
Cool, right?
I think it's destroyed too early when it's colliding with a wall.
So maybe I will do a bit of a trick here on the enemy bullet.
Let's do delay here.
Maybe of 0.05 F, like a really small delay, and it will destroy bullet a bit later than it's supposed
to be.
And because of that, it's going to look like it flying into the ground.
Now let's go ahead and see this.
I'm going to jump in front of the enemy.
Going to get damage.
Okay.
Very good.
Now when I'm jumping away, going to be destroyed on hit with a wall.
Would be nice to make some sort of visual effect, but now it's not that important.
So we're going to do it later on a Polish stage.
But now we need to do something else.
And it is very important.
We need to be able to flip enemies in the editor before we start the game, because as of now, my plan
can look only to the left.
But what if I want to place him over here, for example, or over here?
Then I would have to go back to the script, change his facing direction.
Lots of headache.
So this is what I offer you to do.
We can flip the sprite on the X in the editor, just so we can see where enemies should be facing.
Then in the script we can read this parameter and flip him if we need to do so.
So this is how it's going to be.
We're going to go to the script of enemy.
Let's go all the way down.
Uh, maybe somewhere here.
We're going to make a.
We're going to make a public void lip default facing direction.
It's a bit long, but it's okay.
It will do the job.
Now inside we need access to the sprite renderer, so I think we can go all the way above.
Let's make a private sprite sprite renderer.
SR and it's going to return us get component of a sprite renderer.
Just like that.
Let me clean this up because there is lots of extra stuff.
Then we can go down back to this method.
And over here we're going to do uh SR flip x equals to not sr flip x.
So it will set the value of that boolean to an opposite value.
And we need to call this method from the editor so we can type here Contextmenu.
Lip facing direction or change facing direction.
Just like that.
And thanks to this, now we can go to the start method.
And here we can check if SR flip dot x is equals to true and not facing right.
Then we need to flip the enemy.
And we're going to do flip the enemy.
And we're going to do SR flip dot x equals to false.
So we're going to switch off the flip uh of the sprite on the x.
Now let's save this.
Let's go back to unity.
Now I can take the enemy plant.
Click right button over here.
Find change facing direction I'm going to flip the sprite.
So that's good.
Now I can see enemies facing to the left.
And when I'm going to the play mode.
We're going to disable this flip X and flip the enemy entirely.
So now he's facing to the right, and I can jump in front of him and he's going to shoot bullets into
an opposite direction.
And this will work for all of the enemies.
Just before it was not so important.
For example, for mushroom, it's not that necessary because anyway, you're going to walk left and
right all the time.
But for enemies like plant, it is very important.
That's why I wanted to do it here.
Okay.
Let's change it back.
Let's take the enemy plant.
Change it back as well.
Then I'm going to go to prefabs.
Make the prefab out of the enemy plant.
Also want to double check collision over here is trigger.
Okay, good.
Now I can delete this.
And let's go to the next video.