Transcripts
1. 01 Opening: Hi, my name is Romi Fozzy, and I've been a treat artist for more than 14 years and a game developer for
more than six years. Al jam Dalila, I've helped and taught game development
to more than 10,000 students
all over the world via my YouTube channel
and online courses. I've also published a mobile
game called Bober Mraz, and Alam Dilla It has
been downloaded for more than 300,000 downloads, and it has been featured by Google on the Playstore
twice so far. I've also worked on
various unity projects for clients such as Nike, Bentley, for Armes,
and many others. In this course, you will learn how to create a
vertical scrolling, shoot up game similar
to sky force. We will delve into best
development practices for Unity and C sharp, as well as object oriented programming, scriptable objects, creating a basic sia
curve for movement, safe and load system, weapon and stats upgrades, achievements, and many more. This course is
intended for students with intermediate unity and
C sharp knowledge because we are going to go through
a lot of topics in developing the game and most of the basic stuff will
not be explained. This course has been
updated and it is now compatible up to Unity 2019 0.4. So if you want to expand your game development skill and learn how to create
a vertical shoot them up with complete
features similar to sky force then this
is the course for you.
2. 02 Scripting Concept: So in this video, we are going to discuss
about the scripting concept. Basically, we are going to
create a class as a component, and each class has its
own functionality. And for example, for the player, we will have a movement
script attached to it. Also shooting and health
and destroy component, so we can take damage, and if it's reach zero, then we can destroy the
object and also a damage on collision with other ship
to check for the collision, magnet, and coin pickup. And for the enemy, We are going to also add a
couple component to it. For example, it will have its own shooting
component note movement, and the shooting
component will be the same as the player
shooting component. So we can reuse the script and also health and
destroy component, and it will have a
script that emits coin. As you can see here, the
health and destroy script are the same with the health and destroy from the player script. So we can reuse that also. This way, we can create
different behaviors between different game object by mixing different
components attached to it. For another example, we
have the missile turret, the missile turret will have the same component
as the enemy, which is the help and
destroy, also shooting, but it will have another
different component which are going to
look at the player. This way, we will
have a different behavior than the default enemy. And we are going to also have another turret that will have the health and
destroy component, but it will have a
rotating component, so it will keep
spawning bullets using the auto rotate component and the shooting component
attached to it. Another game object
will be the enemy bus. It will have the same
component as the enemy. It will have the
shooting, the movement, and the health and destroy. But it will have
another component called parent scroller. So whenever the enemy
bus gets activated, it will get parented to the scrawler and it will
follow the camera movement, so we can keep fighting until
we defeat the enemy bus. And we are going to also have the human rescue game object, and this human
rescue game object, we'll have a rescue
component attached to it.
3. 03 Project Setup: In this video, we
are going to set up the base project for
the shoot a Map came. That's open Unity application. And for this course, I'm
using version 2017 3p1p4. You can use any version, but I suggest you used
the same version as mine or at least 2017 above. Okay. And we can set
the project 23d. We can also disable the
analytics because we are not going to use that and then press the create
project button. Now Unity is open. First, we need to import the package I have
provided in this course. You can download it from the resources link and go
to the assets menu, import package and then
click Custom package. I'm going to go to the
folder where I have saved the package and here it
is. Let's import this. This assets contains
all the three D models, textures, and audios that are
needed to create this game. Press the Import button. And now the assets are currently being imported
to the project. Okay, now before we continue, I'm going to change
our platform settings, and currently it is set to
PC Mac and Linux stand. We can change this
via the Val menu, then go to the build
settings and then select Android and then press
switch platform. And right now, it's going
to re import all of the assets that we are going
to use for this project. Now it's already finished
switching the platform. We need to go to the player
settings right now and we are going to change a couple of
values in the inspector. So I'm going to change
the company name and also the package name. Okay. We also need to change the resolution
and presentation settings, and let's set the default
orientation to portrait, so that would be all
four player settings. Now let's save the
scene and let's create a new folder to save all of the scenes and I'm going to call this one gameplay. Now let's open the
models folder. And inside, we have
this plane A model, which is the hero plane model. So let's drag this model
to the hierarchy panel. And I'm going to also put the tank And as you
can see right now, the objects are overlapping
with each other. So let's fix this
overlapping issue. We can switch to the
top view by clicking on the y axis on the view gizmo
top right of the scene view. Let's zoom this out a
bit and let's adjust the main camera position by aligning it to this
view right now. But before that, let's change
the field of view 225. And now with the
camera selected, we can align it by going to the game object menu and then select the align
with view menu. This will automatically align the camera to the current view. Now if we go to the game view, the camera view
will be from top. I'm going to zero the
x and z position under the transform and set the y to a round number 35 in this case. And this is still too close, so I'm going to increase our
field of view value 230. Now we have set up
the camera position. Next, we are going
to set up the layer, so the plane can be rendered on top of the tank and not overlapping with
each other like this. So first, let's create a new camera and change
this camera tag to tag. Whenever a script search for the camera using the
main camera tag later, it will automatically
grab this one and don't forget to pair on the second
camera to the first camera. For the second camera, let's change the name to
ground object camera, and this camera will only
show the ground object, and rename this one
to air object camera. We also need to create
a couple of layers so under the layer drop
down, press Add layer. And here, I'm going to create a new layer called air
object and ground object. Next, let's change
the plane layer to air object and the
pan to ground object. And just click to affect the layer changes to the
children game object. And for the air object camera, let's clear the layer under
the culling mask drop down by selecting nothing and
then select the air object. And also set the clear
flag to death only. Okay. And for the ground camera, we are going to leave
the culling mass options with the default value. But we need to make
sure that it has lower death value than the
air camera death value. Let's change it to negative two. Now if we zoom the view, you'll see that the ship is being drawn on top of the tank. Although it occupies
the same y position, because we put these two
objects on a different layer, if we bring the camera closer, you can see the plane
is getting drawn first. Let's set the y
position back to 35, and I'm going to
move the tank aside. And now let's create
a couple of tags. We already have a player tag. So we need to create a
new tag for the enemy, and then we also need to create the bullet tag and enemy bullet. Now let's save the scene
and also the project, and we are going to continue our lessons in the next video.
4. 04 Player Movement: So let's continue
with our project. And in this video, we are going to create the
player movement script. First, let's delete
the Tank game object. And next, let's create
a new folder in the project panel to
hold all of our scripts. We can call this scripts. And inside the scripts folder, let's create a new
subfolder called transform. And this folder will hold all of the scripts that's related
to manipulating transform. And inside this folder, let's create a new
C sharp script, and we can call this
player movement. But before we work on the
player movement script, let's set up the player
play game object structure. In the hierarchy panel, let's create an
anti game object, and we need to reset
the transform value and rename this anti
game object to player. We need to also add
a box collider to this empty game object
and also a rigid body. But since we are not going to use the dynamics properties, we can disable the use gravity and check the S
kinematic option. We need to do this so this object can listen
for collision or trigger. And then let's parent the plane A model into the player
antigame object. So I'm going to direct the plan A model to be the child of the player anti igame object and move it slightly forward. So the model are positioned in the middle relative to
the player game object. And here, if you look
at the X rotation of the three D model,
it is rotated. Usually, when a model export from lender,
we'll have this issue. And to compensate this, we can create
another empty child on the player game object. Let's call this psal
because we are going to put all of the isual model
as the child of this empty. So just direct plan A model to be the child
of this isualGame object. Now to emphasize banking motion, we can just rotate
the local z axis of this isualGame object. And now with this
setup, save the scene, and let's attach the
player movement script onto the player game object. And then let's also
open the script. Okay, now the script is open. Let's create a couple
of variable first. First, we need to create a
float variable that is public. A float is a floating
point number, which means it is a number
that has a decimal place. A integer is a number
without a decimal point. Let's call this
float variable speed and set its default
value to five. I C sharp, float numbers are usually denoted by F character. We also need to create another float variable
called banking value and set its value to 90, but later we can change
this in the inspector. And the next variable
we need to create is a private variable
with type of camera, let's just call this cam
we also need to create a private float variable
called distance to hold the distant value between
camera and the player. We also need to create a couple private
factor three variable. The first one will
be the velocity, and the second one would
be the last position. And this is for calculating
the velocity later, and the third one
will be the rotation, and then touch pos and the
last one will be screen two l. And we also need another public variable
type of transform called visual child for holding the three
D model reference, so we can manipulate
it transform. And inside the start method, we are going to initialize
a couple of things. The first, we are going to grab the camera into the cam variable by using the camera class and accessing its main property. So this is basically to get the first enabled camera
tag with main camera. And this is why we have set the first camera
tag to main camera and the second one to tag we will be able to grab
the air object camera. I forgot one thing,
but we need to add another private variable
type of rigid body. So let's just create
one and call it my RB. And let's grab rigid
body reference by using the get component method and pass it to the MRV
variable on start. Basically, get component method is used if we need to grab a certain component in the same game object where
this script is attached to. And this is called caching
the component into variable. So whenever we need access to the rigid body component
from a script, we can just access
this MRV variable. And then we need to also
get the distance of the camera to the player and pass it to the
distance variable. And to calculate the distance, we can substract
the camera position with the player position. So let's get the camera position by accessing the variable, transform position and substract it with transform that position, which is the player position. And because the distance
variable is a float, and this is a
vector calculation, let's grab the y component
from this vector calculation. And why are we
getting the y values? Because as you can see
here in the scene, the y component is the distance due to the
camera positioning. And here if we select
the player game object, you can see the y value is zero, and if we select
the camera again, the y value is certified, so we can agree that y Delta can be treated as the distance. And inside the update, let's set the velocity
to the current position, but substract it with
the last position. And let's execute a
method called move. But we are going to create
this method in a moment. And then let's start the transform position value into the last position variable. We need to grab the last
position for calculating the velocity in the next frame by getting the
position differences. And now let's create
the move method. So first, we need to
get the mouse position. And the mouse position will be on the same plane
of the camera. But we are going to
change the z value to the distance value between
the camera and the player. So we will get mouse
or touch position lined to the player plane. Let's set the touch
position variable value to the input mouse position and then overwrite the z values with the distance variable. Some of you may ask why are we using the z
component instead of y? So here in the scene, if we select the camera, and then if we change
the coordinate or Gizmo from global to local, the distance is
represented by the z axis. And because input that most position are going to be aligned with
the camera plane, we need the distance between camera and the player so we can project the most position to the world position that
aligns with the player. So that is why we
are overwriting the z component of the touch position variable with
the distance value. And next, we need to set up
the screen to world variable by converting the touch position into a world position
using the camera, and we can use screen to world point method and pass the touch position
as the argument. Now we are using mouse
position, but later, we are going to change this
into a real touch position. Next, we want to create a temporary vector three
variable called movement, and then we want to interpolate vector three values using. From the current trans position to the new screen
to world position, which is going to be the
input position in the world. And for the third argument, which is the t or
interpolation value, we want to pass the
speed variable. But since we are running
this inside the update, we need to multiply the
speed with time dot time. And this is to make sure so the speed will be time dependent instead of frame dependent, and it will be the
same regardless of the FPF performance
on different devices. And now we are going to apply the movement value by
accessing my RB variable, and we can access the
move position method from rigid body component and then pass the
interpolateed factor, which is the movement variable
as the method argument. And now let's test this script. Back to unity. The script
is currently compiling. And here, as you can see, we have exposed public
variables in the inspector, but I'm not going to
change a thing for now. Let's press play.
Now, as you can see, the player ship are following the most position with a
slight delay or damping. It's working, but now we need
to add the banking effects. It's roaming from
the future here. I just want you to let
you know if you are using Unit 2019 or above, you need to change a couple of settings to make the
player movement work. First, we need to
go to the project settings Under the physics. Make sure you check
the autoinc transform. And we need to modify
the script a bit. Here in the b code, we need to change the
initial position, which is the transform
position instead using the rigid body variable that
position and safe this. And now this should
fix the issue where user cannot move the
plane on newer unity version. So let's direct the
child Visual game object into the Visual child
slot in the inspector, and then we need to
modify its transform. Next, we need to modify
the rotation variable, and we need to only modify
the z rotation value. Let's just set this to the value and multiply it
with the banking value. And then let's apply
this rotation. Using the MRB variable, we can access move
rotation method, and this as for a quaternion
as the parameter. So let's set up a new quaternion
value using its class, then add the uler and
pass the rotation. And why do we modify
the z rotation? Because if you see here in the editor and select
the fissile game object, if we rotate on the z axis, you can see the ship is banking, like if it's moving sideways. And this code is going
to do just that. And here, only the x value from velocity that will
drive the banking, and then we convert the rotation
value into a quaternion and pass it into the move rotation method
of the rigid body. Okay, so let's save the script and head back
to unity to test this. And as you can see, there
is a slight banking motion, so let's increase
the banking value and make it twice from
the previous value. And let's test this again. Now we can see it better, but the banking is inverted. We can easily fix this, add a negative sign
on the loc x value, and the rotation
will be inverted. So let's test this again. It is now banking correctly, but the movement
is a bit bitary. So we need to also fix this. Since we are modifying the rigid body in
the update method, it is recommended to do this
in the fixed update instead. So I'm going to change the
update into fixed update. And we also need to change the multiplier of the speed from time dot Delta time and use time dot fixed
Delta T instead. Tim dot Delta T is the time difference between
frame in an update cycle, and time dot fixed Delta time
is also time difference, but between physics
step inside unity. Save the script, and
let's test this again. And now we have a much
smoother movement, and the banking rotation
is also very smooth. So this conclude the
player movement lesson.
5. 05 Temporary Pooling: In this video, we
are going to create a temporary version of
the object pulling, so we can implement
shooting mechanism and later implement the
correct pulling system. Let's create a new folder and we can rename this to
pulling system. Inside this folder, let's
create a new C sharp script, and we can call it pulling
manager. Let's open script. First, let's delete the default
start and update method, and then let's declare a public
static variable to create a static reference for easier access and set the
type to pulling manager, let's just call this instance. The static reference will be available on all of the
scripts in this project, and it can be accessed easily without using get component
or fine object of type. Static field can only be
occupied by one instance. Any reference to it will always
refer to the same object. In this case would be
the pulling manager. Next, let's create awake method. When creating static reference, we want to initialize
it on awake. The static rep will
be available on error classes inside the
start method if needed. To initialize the variable, we can just type instance
and then pass this keyword. This will set the static
variable value to this class. We need to make sure there are only one object that use
the script in the scene. Next, let's create a public
method called use object. This will be used for getting
the object from the pool. For the parameter,
we need to set the first one to game
object called OBJ. The second one would be
a vector tree called pause the last one would be a
quaternion called rotation. For now, we are going just to instantiate an object
inside this method. But later, we are going to replace the code with
the pulling system. Let's pass the OBJ pause and the rotation into the
instantiate arguments. But we need to change the
return type to object, so we can return the
instantiated game objects. Let's add return keyword before the instantiate
code This way, we will pass the instantiated
object in this method. Okay. Let's save the script, and for the next method, we want to create a
public void method called return object. This is going to be used
for removing the object from the scene and putting
it back to the pool. But for now, we are going
to destroy the game object, and later, we will replace the code once we implement
the pooling system correctly. Save the script, and
let's go back to unity. Now, let's create a
new empty game object and rename it to
pulling manager, and let's add the
pulling manager script into this newly
created game object. And this concludes
this video. Okay.
6. 06 Scriptable Object for Weapons: In this video, we
are going to create the scriptable object to
hold weapon characteristic, such as damage and firing rate, and this scriptable
object will be used by both the player
and the enemies. Now let's create a new folder
inside the scripts folder, and let's call it
scriptable object. And inside this folder, create a new C sharp script, and we can call
this shoot profile. In the console, there is an error saying we have two
audio listener in the scene. Let's select the
ground object camera and remove the audio
listener component on it. The error should have gone now. Let's open the shoot
profile script. We can safely delete the
start and update method, and now we need to declare a couple of public
float variables. The first one would be
the speed and then damage fire rate interval destroy rate for removing the bullet in seconds if it doesn't
hit anything, and the degree for the spread. We also need to create a
public integer for the amount. This is for deciding
how many bullets do we want to shoot per
interval in seconds. We also need to
add an attribute, so we can instantiate the
scriptable object inside the project panel with square bracket type
create asset menu, and then we need to pass string argument as the
file name parameter. I'm going to call
it shoot profile, and for the second argument, which is the menu name. Let's just call it
shooting profile. I'm going to add the
optional argument, which is the order for
showing the menu to be one. There is an error because I need to type the parameter name, which is file name,
then assign it. For the second string, the parameter name is menu name. Let's just set it and I'm going to close
this so I can save it. Let's go back to unity
and on the assets root, let's create a new folder and we can call it
weapon profile. Inside this folder, we
can create the profile, which actually an instance of the scriptable object
we've just created. But there is one thing I forget. We need to open the shoot
profile script again. Here, we need to change the base class from mono
behavior to scriptable object. Let's save this and this
time it should work. Let's head back to Unity and go to weapon
Profiles folder. If we right click here, then go to the create menu, we will have shooting
profile menu on top. Click the menu to
create a profile, and let's rename it to player underscore
level underscore one. Now, let's define the profile. For speed, I'm going to set this 230 and set the damage
to one fire rate 20.1, and we can set the
interval 20 because we want to make the player
shooting continuously. Destroy rate, we can
set it to 2 seconds and three degrees for the spread and set
the amount to one. In this level, it will only shoot one bullet
per fire rate. In the next video, we
are going to continue working on the shooting
mechanics. Okay.
7. 07 Bullet Setup: In this video, we are going to prepare
the bullet prefect, and the bullet itself, it's actually a sprite. If we go to the sprite folder, there is an asset
called bullets. If we open the sprite editor, we have three slides of sprites. The core, glue and a
different shape of bullet. And this should be name circle, so I'm going to rename it. Pricing apply will save
the change to the sprite, and let's expand
the bullet sprite. But before adding the sprite, let's create an
empty game object, and this is going to be the
base for the bullet prefect. Also, make sure the game object z or the forward
axis are facing in the same direction as the word z as shown here on the Gizmo. Don't forget to set the
gizmo here to local. Then let's add a
capsule collider. And a rigid body
component onto it. Under the rigid body component. Don't forget to disable
the use gravity option, but leave the iskinmatic
off because we are going to set the pre fax
flocit later when spawning it. With the bullet sprite
expanded on the project panel, let's drag the
bullet base sprite to the empty game object
in the hierarchy. This will make the sprite
as the child object. If the child sprite
is not centered, just set all of the
position axis to zero, and we need to
rotate the sprite on the x axis by 90 degrees. So it can be viewed
correctly from the top. Then let's set the color of
the bullet sprite to bluish. Then I'm going to also add the glow object to be the child
of the empty game object. Set the position x is to zero and rotate the
x axis also to 90. Let's set the color to
the same bluish color. Now we can see a slight glow on the bullet in the game view. To make it more interesting, we can change the bullet
and glow sprite render material to this sprite
additive material I've included from the package. It is basically a mobile
particle additive material. Now, let's apply the material to the bullet based material. And also to the glow
sprite render material. I'm going to scale the glow to around 1.5 in the x and y axis. Next, I'm going to adjust
the capsule collider size, so it fits nicely with
the bullet sprite. First, let's change the radius. As I scrap the value, it is clear that the direction was not aligned to the sprite. To fix this, let's change the direction of the
capsule collider to z axis. Now the capsule collider is
facing the correct direction. Let's change the
height value to around 0.39 and the radius to 0.1. This fits nicely
with the sprite. Now we have set up the bullet. Let's save this to
prefab But first, let's create a new subfolder
inside the prefab folder. We can call this folder weapon. Let's rename the game object to bullet and set its
tag two bullet also. Then let's drag it to the
weapons folder. Okay. Now we need to create a script. Let's create a new subfolder
inside scripts folder, and rename it to weapons. Inside the folder, let's create a new C sharp script
called bullet Move. The script will handle
the bullet motion. Let's open the script. Here, we need to declare a
couple of variables, and the first one will be a public float
variable called speed. The second one will be
a private rigid body, and we can call it MRB. And inside the start method, let's initialize
the MRB variable by using get component method
with type of rigid body, and this will return the
first attached rigid body on the bullet game object. Let's also change the
update to fixed update. Inside the method,
we are going to move the bullet using the velocity properties
of the rigid body. Let's just type MRBt velocity, and then we need to
pass a vector here. We want to make sure that
the bullet is going to move according to the forward
or its local z direction. Fortunately, unity
already provide us a way to get the local forward
direction in world space, which is transform dot forward, and we want to multiply
this value with the speed. So let's save the script, and let's get back to unity. I'm going to attach the
script onto the bullet prefs. Okay. And then let's
set the speed 210. Let's save the scene,
and let's test this. And as you can see, the
bullet is moving in the correct direction
along its forward axis. Let's also make sure
the capsule Cleder of the bullet is trigger
option is checked. Let's save the bullet prefabs. If you are using Unity
version below 2018 0.3, you can just click apply on the inspector with
prefab selected. And for version 2018 0.3 and above with
the prefab selected. You can select the
over right button on the inspector and
then click Apply A. And we want to also enable the trigger option on
the player collider. Now we can save the scene, and this concludes the
bullet prefab setup. Okay.
8. 08 Auto Shoot: In this video, let's create
the shooting script, and we should already have temporary pulling class and the bullet prefabs
up to this point. So now inside the
weapons folder, let's create a new
C sharp script. And we can rename
it to auto shoot. And then let's open this script. And in this script, instead of using the update
method to loop a code, we are going to use
a core routine. A C routine is a special method that returns enumerator types, which can pause execution
and return control to unity, but then continue where it left off on the
following frame. A coroutine can also loop its code with a
specific interval, whether to loop it every frame or loop it every certain second. This makes coroutine quite
useful in game development. I'm going to show you how to
create and use coroutine. Let's create a new method with a return type of enumerator, and let's call it
shooting sequence. Inside this co routine, I'm going to create
a while statement with a true keyword
as its condition. Inside the WIL statement, let us just print
shooting as a message. This will print the
message into the console, and for every routine, we need to tell the
flow of the execution by using a yield return keyword. In this example, let's just
type Yield return null. This will loop the while
blocks every frame. Let's save the script. Go back to unity. And I'm going to attach
the script to the player. Now open the console window so we can examine the messages, and let us test this. It seems I've forgotten
to run the core routine. Let us go to the script
again and we need to call this co routine
inside a built in method. Let us run it in
the start method. And to run a co routine, we need to call it
using a method called start routine and pass the
co routine as an argument. Save the script again, and let us test this again. And now the shooting message
gets printed every frame. Now let's go back to script, say we want to loop the
code every 2 seconds. Then we can instantiate
a new class by typing a new wait 4 seconds after the return statement and pass two as the
weight seconds value. Save and let us
go back to unity. I'm going to clear the console, and let's test this again. And now the shooting message gets printed every 2 seconds. So you can see how
useful Coroutine is. I'm going to set
this back to no, and let us start working
on the shooting script. So first, we need to declare
a couple of variables. First would be a
public game object for the bullet pre reference. We can call it bullet prefps The next would be a public
with a type of transform, and this is going to
be the fire point or the bullet spawn position. We will also need
a public variable with a type of shoot profile, and let's just call
this shoot profile. This will define the
shooting characteristic. We will also need a couple
of private variables. The first one will
be the type of float and we can name
it total spread. And we also want to create
variable type of weight for seconds called
rate and interval. This will be used for the shooting sequence
routine loop and delay rate. Let's change start to unenable and let us also
add an disabled method. This is basically the
opposite method of unenable. It gets called every time
the script gets disabled, either from set active to false or if the objects
gets destroyed. Inside disabled, we want to run the stop all
coroutines method. This will stop all of the coroutines running
in this class instance, which will stop the
shooting sequence. Inside on enable method, let us initialize the interval
value by typing interval equals new weight
for seconds and we can pass a float from
the shoot profile, which is called the interval. For the rate, we
want to do the same, but we want to pass the shoot
profile fire rate instead. I'm going to also check if
the fire point is null. Then we want to set its value to the transform
of the script owner. Now, let us create
the shooting method. We want to pass a float number for the angle of
the bullet spread. Let us delete this print line. Inside the shoot method, I'm going to create for loop, and for the length, I'm going to use the shoot profile amount. I've made a mistake here. This loop code
shouldn't be here, but it should be inside the while loop of the
shooting sequence routine. Let us move it. Inside
the shoot method, let's create a local game
object variable called TM, so we can hold a reference
to the spawn bullet. Then we can use the
pulling manager by accessing its
static reference, which is called instance, and then use the use object
to spawn the bullet prefabs. And use the fire point
position and rotation. Next, we want to rotate the pawn bullet using the
transform rotate method, we want to use the second
overload of this method, which requires the
intended rotating axis and the angle value. We can pass factor three
dot up into the axis, which is going to be the y
axis and the angle argument. Let us call this shoot method inside the co routine four loop. But before that, let
us declare a float called angle before the loop
and set its value to zero. And we are going to
calculate the angle based on the amount and the spread
value from the shoot profile. We need to set the total
spread value first. Inside un enable,
let's define it. Total spread would be
the value of shoot profile spread multiplied
by shoot profile amount. I'm going to create
an if statement to check if the amount is greater than one and put the four loop inside
the statement block, and then we can
calculate the angle. The angle would be the
total spread multiplied by the I or loop index value that's been divided by
the shoot profile amount. But we need to cast
it to a float so we can have a decimal value and we want to shift
the rotation value. I'm going to explain this. If we have the
shooting direction, if the amount is one, then we can simply shoot it straight up. But if there are more than one, then we need to rotate
it based on its index. For example, the second bullet
would be rotated like so, but we need to rotate all of the bullets by half value
of the total spread, so the spread distribution
is nice and centered. If we have more
bullets, let's say, then if we don't shift the rotation, it
will look like this. The bullets will only spread
slightly to the right. When shooting, we need to shift the angle to
compensate this. Let us decrement the angle value by the value of total
spread divided by two. And then we want to yield return the rate inside the loop. And outside the loop, let's change the yield return le to yield return interval. Vector unity, now let's set up the Auto shoot.
Script on the player. First, we can pass the
shooting profile we've created before to the
shoot profile slot. Okay. And also the bullet
prefabs to the prefab slot. For the fire point, we
need to pass a transform, and in the player game object, I've already added an
empty child called shoot point and set its position to be in
front of the ship. With the coordinate
set to local, make sure that the z or
the forward direction of the shoot point points to the same direction of
the z axis of the world. Let us assign it to
the fire point field. In the shoot profile object, we have set the amount to three. Let us test this and it doesn't shoot because I forgot to call
the shoot method. Let us just add a call to the shot method and
pass the angle value. I'm going to comment on the
shifting code temporarily, and let's test this. It seems we have an issue with
the pulling manager here. And this should be fire
point equal to null. Since we are running
the core routine in the un enabled method, we might have a
race condition with the pulling manager
initialization here on wake. To fix this, we can just delay the shooting
sequence a bit. We can just copy the
return rate line and paste it at the
beginning of the routine. Let's go back to
unity and press play. Now it shoots, but we have a slight delay causing a
weird spread distribution. Let's go back to the script
and fix the problem. First, let's add an if statement to check for the
yield return rate. Let's set a condition. If the fire rate is
greater than zero, then we want to execute
the yield return rate. Otherwise, we don't
want to execute it, so the loop runs
on the same frame. Now, let's test this again, and I've forgotten to set
the fire rate back to zero. Let's set it back
and test this again. And now, as you can see, it fires correctly, but the
spread is not centered. The bullet is spreading
to the right side. So let's go back to the
script and fix this. Now we can uncommen this
line, and basically, this line will shift the angle value by half of
the total spread value. Let's test this again. Now the spread is
indeed shifted, but now it is slightly
shifted to the left. We need to compensate
for this shift by substracting the value with the spread value from the profile divided with the amount from
the shoot profile. Let's go back to unity
and test this again. Now the spread is
nicely centered. If you want to have a
faster bullet rate, we can lower the interval value. Let's lower it to 0.1, so we can create a different
tiers of weapon with different characteristic
by trying different values in the profile. And this is also applicable
to the enemy weapon behavior. For example, if
we want to create a bullet that is
spreading sequentially, we can set the rate
to some value. For example, let's
set the amount to ten and fire rate to 0.15
and the interval to two. Now we have an
interesting fire pattern and we certainly can use this kind of
pattern for the enemy. With only one script, we can create a
different pattern for different weapons. Okay.
9. 09 Health System Part 1: In this video, we are going to implement the starting point
for the health system. And first, we need to create
the bullet for the enemy. So let's go to the
preface folder under the weapons folder. We can select the bullet
prefps and we can duplicate the prefabs
by pressing Control D, and then let's rename the
prefs into enemy bullets. And with selecting the
enemy bullet prefs, we can change the tag
under the inspector to enemy bullet and to
differentiate the visual, we can expand the enemy bullet, select the bullet
based game object. And here under the inspector, change the sprite color to
a slightly orange color, and let's copy the color
and then paste it to the other game object color of the sprite
render called glue. So now if you select the
enemy bullet prefabs, you see that here the inspector, the bullet has different color compared to the player bullet. And next, let's create
the health script. So let's go to the script folder and inside the scripts folder. Let's create a new folder, and we can call the
folder gameplay. And inside the gameplay folder, let's create a new
C sharp script, and I'm going to call
this health system. And let's open the script. And as usual, we need to
declare a couple of variables. And first, let's declare a
new private string variable, and let's call the variable tag. And this is going to
be the bullet tag that are going to be detected whenever a bullet hits this game object where this
script is attached to. I'm going to change
the name to tag name because the name tag has
been reserved by unity. And we want to set the tag name here inside
the start method. But before we set the tag name, we want to create
another variable, which is a type of bullion
with a scope of public, and let's just call this is my, and we are going to assign different tags based on the
value of this bullion here. And we can set the default value to true because we are going to assign this health system script to a lot of enemy object, and we only need to check this
one on the player prefab. So I'm going to set this
value default to true. So inside the start, we want
to create an if condition and we want to check if
the bullion value is true. And if we want to check for the false value of this bullion, we can add an exclamation
mark in the front. And with that exclamation mark, this will check whether the
bullion value is true or not. And if the enemy value is true, we want to set the
tag name to bullet. And let's add an L condition, and for the L condition, we can set the tag
name to enemy bullet. So now with this
bulon option here, we will set a different tag. So this game object that
has the scripts attached, we'll know which
bullet that we have to take into account inside
the trigger method later. And we can just delete
the update method here, and we need to create a
new public float variable, and we can call
this MX health And this variable will set the starting health for
each of the health system. We can set the
default value to ten, and let's add another public variable type
of game object, and let's just call
this hit effect. And this is for the effect
prefabs that we are going to instantiate whenever this
object gets hit by a bullet, and we want to add another
game object variable, so we can just add a comma here and then type
the name health bar, and this will declare two different variable
in the inspector, and let's create a
private float variable. And we can just call this
underscore current health. And this will be the local
variable that gets calculated. When the game is running, I'm going to remove the
underscore here for the sake of naming consistency. And next, let's create the
untrigger enter method. And inside this
untrigger enter method, we want to check
the other collider that are being passed
as a parameter here. Using an if statement, we want to check its tag, and other will be the other game object
that are going to hit this game object where this health system
script is attached to. So we can use the compare
tag method to check its tag, and we can just pass the tag
name as an argument here, and this will check if
the other game object has the tag of the tag name that we've declared
on start here. And if it's true,
then we want to do damage inside the If statement. But instead of doing
the damage calculation inside this If statement, let's create another method, and I'm going to
set the scope to public return type to void, and let's just call
this take damage. And I purposely expose this
method using a public scope, so we can call this method
later from other script, such as the bomb script and
the other script that are not going to use the conventional
trigger enter to do damage. And for the take damage method, we want to pass a parameter Which is a type of float, and we can just
call this damage. So this method can take different value for
the damage value. And inside this take damage, we can just substract the
current health variable with the damage value that are
being passed as the parameter. And here inside the untrigger
enter, under the statement, we can just run the
take damage method, and we need to pass
the damage value here. But we don't have a
specific value here. And for the damage,
we are going to put the damage value into the bullet name whenever
we instantiate the bullet. But we need to modify
the auto shoot script. So let's go to the Auto
shoot script here. Inside the shoot method, whenever we incentiate
the bullet, let's set the object name, which is TM name, and we can get the damage value from the shoot profile object, and let's get the float
damage variable here, and we can just run
the two string method. So this float value will be
converted into a string, so we can apply the
damage value as a name. And here, back to the
health system script, whenever we take
damage from a bullet, Now we can create a
float value by passing the bullet object name
into a float value. So now let's create a
temporary float variable called damage here above
the take damage method. And let's grab the
other dot name, which is going to
be the bullet name. But we want to parse
this into a float value. So we can type float type in
front of the other dot name. And then run the pars
method and pass the name or the string as an argument
of this pars method. So this way, name of the bullet will be converted
into a float value, which actually is a number that we are saving in the
autoshoot script. And we can pass this
float damage value as an argument into the take
damage method below here. And now let's save the script, and let's give it a try. Let's head back to unity
and back inside unity. I'm going to go to the
weapon profiles folder here and I'm going to modify the
player underscore level one, shoot profiles here, and let's
change the amount to two, and let's just set the
fire rate to zero. And currently as you can see, the damage is set to one. So I'm going to leave the
damage value as it is. And now let's create a new
cube object here in the scene, and we can move this
along the z axis, to the front of the player ship, and then let's add the
health system script into this cube here. And as you can see, the Mx
health value sets default 210, and back to the
health system script, we want to change
the start method into an un enabled method. And insect this unenable method. Let's set the current
health variable into the mix health variable. So whenever this object
gets re enabled, we want to reset the
current health variable. So let's go back to unity, and here under the inspector, I'm going to change the
mode to debug so we can see the current health value and make sure the my
bulon is checked. And let's also set the box collider is trigger
options to enable. And let's run the game. And now, as you
can see, whenever the bullet hits the cube, the current health
gets substract. And currently we are shooting
two bullet at a time, so the health gets substract
every time by value of che. So now, as you can see the
health system is working, but I need to remind you, why didn't I put a
rigid body component into this cube here? Because on the bullet game
object here, in the prefect, you can see that we have a rigid body components already
attached to it. So in order for the uncollision
enter or trigger enter method to work with every
trigger or every collision, one of the object needs to have a rigid body component
attached to it. Otherwise, it won't work. But of course, later when
we are designing the enemy, we are going to put a
rigid body also into the enemy game object because the enemy are
going to be moving around. So for object that
are moving around, we need to put rigid
body component attached to it for
optimization sake. And as you can see before, when we are testing, the current health is
currently working. And in the next video,
we are going to expand this health system and create the death system
and its effects.
10. 10 Hit Effect: In this video, we are going to continue working on the
health system script. So now let's open the
health system script. Let's continue
where we left off. And now let's create
the it effect. And in order to
create the it effect, let's modify the
pulling meager script. Let's open the pulling
measure script, and under the wturn
object method, let's add another parameter with type of f and we
can call this delay, and let's add a
default value of zero. So we don't need to input
the delay every time. And for now, we want to pass the delay value as the time on the destroy
method argument. So we can just add a
second argument to the destroy method and
then pass the delay value. And this will add a delay
when destroying the object using the destroy method here based on the delay
value in seconds. And let's go back to the
health system script. And here under the
untrigger enter, We cannot detect the point of collision because we are using
the triggered enter method and the collision position
or the impact position only available with the
collision enter method. But there is a way
to calculate this. And to calculate
this, we can use the closest point on bounds method from the collider object. So let's create a
temporary variable with a type of factor three, and let's just call
this trigger position. And we can use the other
collider object here. And from this collider, we want to use the
closest point on bounds, and this will get
the closest point to the bounding box of
the attached collider. So this will detect the
trigger position or the collision position when using the trigger enter method. And here we need
to pass a position and we can pass this
game object position. So let's just transform
the position, and we need to also define the direction for
this hit effect. So let's create another
temporary factor three variable, and we can just
call it direction. To get this value, we can just substract the
trigger position, which is the closest position on bounds from the other object that are hitting this object. And then substract
that trigger position with this script
holder position, which is the
transformed position. And with that calculation, we will get the direction from the surface of the
collider is facing. And with this two
vector calculated, now we can instantiate
the hit effect. So now we can just create a temporary game
object variable, and we can just call this F x. And let's use the
pulling manager that instance and we can use
the use object method, and we need to pass the prefabs, which is the hit e x variable. So let's just pass the
hit effect variable into the game object parameter. And for the position, we want to pass the trigger
position factor. And for the rotation
or the direction of the particle or
the hit effects, we can use the look
rotation method from the quaternion class and then pass the factor
three direction. And this will calculate
the rotation from the direction factor and convert this value
to a quaternion, so we can use this
as the rotation of the hit effect that we are
going to instantiate here. And now let's try
using this value. But if it's inverted, we can always invert
the direction value. And we need to also destroy the hit effect with
a delay of 1 second. So whenever the particle
animation stops playing, then we can destroy
the game object or remove the game object
from the scene. So let's use the
pulling manager again, access it instance
static reference, and we can use the
return object method. And this time, we want to
pass the F x game object, not the hit fx prefab, because we want to remove
the one that we are instantiating, and
for the delay, we can just pass value of one, and this will delay the
destroy for 1 second. And here we need to also destroy the other game
object, which is the bullet. So now let's just destroy
the other game object here. I'm going to put the code
below the take damage here. And now we can use the
pulling manager again. And it's static
reference instance and use the return
object method. And we want to pass the
bullet game object, so we can just grab it from
the other collider object, but get its game object using
the game object property, and we don't want
to pass any value, so it will get
destroyed right away. Now let's save the script, and let's go back to unity, and let's give it a try. Okay, there is an error because we forgot to put the effect prefabs in the prefab slot
on the health system. So let's select the
cube game object. And we can put the
sparks prefabs here, and I've already
provided this from the initial assets that we have imported on the
start of the course. So let's just go to
the prefs folder. Under the X. We have
the Sparks prefs. So just select the sparks prefbs and then drag this to
the hit effect slot. Let's save the scene, and
let's give it another try. And as you can see here, this park gets
created, actually, but we cannot see
it because all of the prefabs are
deactivated by default. So let's just fix this inside
the pulling manager script. So here in the use
object method, we need to create a temporary
game object variable. And we can just put
the instantiate code here to the game object
temporary assignment. And we need to remove
the set active command. And then we can just activate the game object by accessing the name T and then run
the set active method after the object is instantiated
and then set the value for the set active methods
we return the game object, and let's save the script, and let's go back to unity,
and let's try it again. And now, as you can see, we have a very nice spark whenever the bullet
hits the cube, and as you can see, it
calculate the position and the direction correctly based on the collider surface normal. And this concludes the
hit effects setup. And in the next video,
we are going to set up the health bar and as
well the death system.
11. 11 Death System: And now let's continue work
on the health system script, and let's open the health
system script again. And from the last video, we've implemented the effect, so now we have a visual feedback whenever the bullet
hits the object. Now let's create a new
function to check the health. So we can just type
the return type void, and we can call this
method checked health. And inside this method, we can just add an statement, and we want to check for
the current health value. If it's less or equal than zero, and I add a less
comparison because sometimes the
current health value can get below than zero. If the substrator or the damage value is bigger
than the last health amount. So, for example, if the
last current health amount is one and the damage is two, then it will become
negative one. So we need to make
sure that we check if the value is below than zero. And if the current health
is less or equal than zero, then we want to destroy the game object or
we want to make this game object or
this entity to die, or to get destroyed. So here inside the
current health method. Let's create a couple of comment for the code that we are
going to create later. And the first, we
are going to create the code to destroy or to
make this game object die. And we want to also
check if it's an enemy, then we want to add
a point or score. And now let's create
the death system. So head back to unity
and let's create a new script inside the scripts
and then gameplay folder. Let's create a new
C sharp script, and we can call
this death system. And we want to also create
another C sharp script, and we can call
this create object, and this create object
script will be used to instantiate another object
upon one object death event. So when there is an object
that we want to destroy, when the death
system is invoked, then we can trigger
this create object to create another object such
as coin or explosion. And now let's open the
death system script first. And let's just delete the
start and the update method. And we need to declare
a couple of variables, and I've already
prepared the variables. So I'm going to paste this
and explain this one by one. And the first variable
is a type of bullion, and I'm going to
call this destroy, and I'm going to set
its default value true. So this will decide if we want
to destroy the game object physically in the
scene or we want to leave the object
enabled on the scene. For example, the ground enemy, we want to keep the
object on the scene, but we want to add a flame
and explosion effect whenever that game
object is beaten. And for the second variable, the type will be a float and
we can call destroy after. And this will decide
how many seconds we want to destroy whenever
the death is invoked. So it will be the delay for
destroying this object. And the third variable, is a array of create
object class, so we can just hook the create object script into the slot later when we
want to spun the object. For example, if we want to spun the explosion and the coin, then we can add two different create object script
into the slot here, and each will incentiate the different game object that are being set up in that script. And the last variable will
be a type of unity event. And this is for invoking
another method from another script whenever death
is occurred on this object. So we can chain another method
to this unity event here. And this unity
event will trigger the other method that are added
to the Unity event entry. And for the Unity
event, we can just call the method on death event. And to use this unity event, we need to import the unit
engine dot event namespace. So let's just add
this above here by typing using and then
unity engine dot event. And once we add this
namespace here, you see that the Unity event
keyword turns to blue, and we don't have the red squiggly lines anymore,
underlining the keyword. And let's save the script. And let's go back to Unity and let's select the
cube game object. And now we want to add
the death system to it. And this is how the
unity event looks like, and we can add an entry. And for each entry, we can add an object. And for that object that are put inside the object slot here, we can trigger the function from each of the
object components, such as transform
or other script, and we can trigger any function
from that component here. So for every object that we
add to this on death event, we can trigger the method. And whenever we
add those entries, when this on death
event is invoked, then all of the
trigger listed in this entry here
will get executed. And basically, we need to invoke this event whenever
the health runs out. And now let's add the
start method first. And on start, I want to get
all of the colliders that are attached to this game object where the de system
is attached to. So we need to create
a private variable. And for the type,
we can just use the collider array and we can call this colliders
and on start, we want to grab all
of the colliders, and we can use the get component The plural form, which
is get components, and this will get
multiple colliders, and it will store all of the colliders into
this collider array. And we need to pass the type, which is collider
and enclose it with a sets of parenthes
because this is a method. And now let's create
a new public method with a written type of void, and we can just call this death. And now we want to spun all
of the spawn objects that we are assigning to create
object array variables. So let's just
create a four loop. And for the length, we want to pass the pawn objects length. And this will return
how many create objects script that we are assigning to the
spawn object slot. And we can run the
spawn function, but we haven't
implemented this yet. So we are going to
implement this later. And below here, we want to add an if statement to check if the destroy bullion
value is true, and we can just write
the shorthand version, just type the keyword,
and this will check if the Bulen
value is true or not. And if it's true then, we want to destroy the game object. So we can just use the
pulling manager instance, and we can just use the
return object method and we want to return
this game object. And for the delay, we can just pass the destroy after variable. And now we want to disable
all of the collider, so we need to create
another four loop here below, and for the length, we can just use the colliders
variable dot length, and this will return the number of the colliders that are
being grabbed on the start. And let's just disable
using the index of I, so just type colliders and then pass the index using
a square bracket, and we want to access the
enabled property and we can set its value to false and this will disable the
collider component. So, for example,
for ground enemy, if we don't want to
destroy the game object, we want to leave the game
object on the scene, We can just uncheck the
destroy bulon and this will prevent the pulling manager from returning this game object, but the colliders will
still gets disabled, so we cannot shoot
the enemy further. And using the spawn
objects array, we can create a flame effect to indicates that the enemy
has been defeated. And let's save the script. And let's go back to
health system script, and we want to add
another variable. And for the scope, I'm going
to set this to private. And for the type, it's going
to be the death system. And let's just call
this death script. And we want to grab the
death script on start. So now let's create the
start method and we can just assign the death script using the get component method. And for the type, we can just pass death system. And here below inside
the check health method. And inside the statement. First, we want to check if the death script is null or not. So if the same game object
where this health system is attached to has the death
system script attached also, then the death script
will not be null. And if it's not null,
then we want to run the death function. So let's just type that
script the death method. And for now, I think this
should do the trick. Let's save the script again, and let's go back to unity. And now let's try to
destroy this cube here. So let's press play. We need to hit a couple of times before this object
gets destroyed. And as you can see,
it is not destroyed, so there is probably something
wrong with the script. So I'm going to post the game, and I'm going to change
the inspector to debug. And here, as you can see, the current health
is negative six, so there is some issue
with the script. And as you can see
the death system is registered on the
death script slot. So now let's check the script. I see there is an issue here
in the health system script. So basically, the issue
is the check health here. We already declared the
check health method, but this method
never gets called. So we need to call this
inside the take damage. So whenever the object get hits a bullet and
taking a damage, we need to check its health. So let's just run this
method here below the current health line
and save the script. And let's go back to unity, and let's try it again. And now, as you can see, once the health is depleted, the game objects get destroyed. And on the next video, we are going to continue
working on this feature.
12. 12 Spawn Objects & Health Bar: In this video, we are going to continue working on
the death system to add a spawn object feature and also the health bar feature. And now let's open the
death system script. And I'm going to also open
the create object script. So here in the death
system script, we already create a public array of create object
called spawn objects. And inside the death method, we already create
the four loop to look through this
spawn object array, and we need to run
the spawn function. So now we need to go to
the create objects script, and we need to start working on the spawn method
inside this script. And here, I'm going to
paste a couple of code, and I'm going to explain
this one by one. So the first variables
a type of game object, and this will be the
prefabs that we want to create upon death event, and this can be an explosion, flame particles
or a coin object. And the second variable, It's a type of integer, and this will decide how many object that
we want to spawn. And here below, we have the header attribute to separate the fields in
the inspector later. And I've add the title
auto destroy properties. So to use this attribute, you can just start
with a square bracket and then type the
keyword header. And inside this parenthesis, we need to pass a string value, and this will be the title of the header in the inspector. And the next variable is a type of bull
called auto destroy, and this will decide
whether we want to destroy the game object that we've spun using this component
here, or not. And the next variable, it's a type of float, and this will delay the destroy if we decide
to destroy this object. So this time to destroy can
add delay whenever we want to destroy a object that has been spawned by this
create object component. And the last variable, it's a type of vector tree, and it has a scope of private, and this variable are
going to be used as the position to spawn the
object by this component. And next, we can just delete
the update and start method. And here, I'm going to
paste the code here, and this is the method
that we are going to use to spawn the object.
It is called create. And it has to be
a public method, so we can access this
method from other script. So here in the start
of the method, we are setting the
position value to be the transform
dot position. This will grab the position
of the script owner, but then we want to
zero the y value. So in the next line, we are overriding the
position dot y to zero, and we need to do this because if we are
going to spawn a coin, then we want to make sure
that the coin is spawn on the same y axis or
y plane as the player. So the player can collide with it and can
pick up the coin. And here, next, we are
creating a four loop so we can spawn multiple object depending on the create amount value. And if we set the create
amount value more than one, then we are going to
create or instantiate multiple objects
inside this loop here. And here, the pull
manager throws an error because the pulling manager script called
pulling manager. So let's just replace
the pull manager name into pulling manager on
both of the lines here. And here, basically,
inside the loop, we are instantiating the object using the pulling manager, and we store this to a
local or temporary variable called t and we pass the object to create prefabs
as the argument and the position and quaternion
identity for the rotation. And if the auto destroy
bulon is enabled, then we are returning or destroying the object
using the pulling manager. But this time we are passing
the TM because we want to destroy the ones that
are instantiated on the scene, not the prefab. So we need to pass the
TM as the game object. And for the delay,
we are passing the value from time
to destroy variable. Now if we go back to the
death system script, inside the death method, we can run the create function inside the first four loop
by typing the variable name, which is pon objects, and we need to pass the index. So let's just add
a square bracket and then pass the integer, and then we can run
the create method. And here we also have the unity event called
on death event, but we never invoked this
in the previous video, and this basically can
trigger everything in unity. It can trigger method
or functions from component and from
other objects. So whenever we want to enable or disable the child
object or other object, we can use this or we can run
a certain custom function. We can also use this
on death event. So here below the
first four loop, I'm going to type the
death event variable, and I'm going to run
the invoke method by adding dot invoke and
sets of parentheses. And this will invoke all the registered callbacks
on this on death event list. And another thing that we
need to do is we need to create an update UI function inside the health system script. So let's just go do that here below the check
health method. I'm going to paste the code here and it's called update UI. So I'm going to make sure that we already declared the
health Bar variable, and we have already
declared this. And let's just copy the name
and paste it here because the code that I've pasted has
a different capitalization. And here for the health, it should be the current health divided by the max health. So we get the normalized
health value. So basically, this DUI method
is going to check first if we have a reference inside the health bear
variable or is it? And if it's not, then it will run the code inside
of the block. And then we are creating
a factor three value. Called scale. And we are setting the value to a
vector three dot one, which is one on all of the xs. And we are going to use this to change the scale
of the health bar. And next, we are
creating a float value, and this will be the x axis
scale for the health bar. And for the value, basically, we are dividing the current
health with the MX health. So we get the
normalized health 0-1, and then we pass
this float value into the x component
of the scale vector. And after we modify the x
component of the scale vector, we are passing the
scale value to the health bar
transform local scale. And this will create
an illusion of health depleting by modifying
the local scale of the health bar game object. And we need to call this update UI method inside
the take damage method. So here we can just
type update UI and open and close parenthes
Let's save the script, and let's go back to unit. Okay. And first, we are going to modify
the cube game object. Let's select the cube,
and let's change the inspector mode back
to normal from the debug. And here, let's add a
create object component. And let's go to
the prefex folder. Under the F x folder, we
have the explosion prefab. So let's select the cube again, and then let's drag the
explosion prefab into the object to create slot under the create
object component. And here we need to
check the duration of the explosion particle, so we can just select
the explosion prefs. And under the inspector, we can see that under the
particle system component, D duration is set to 1.5. So we can use this value
to delay the destroy and make sure also the looping options is disabled
on the particle system. Now, select the cube again and let's enable the auto
destroy bullion. And for the time to destroy, I'm going to set this to
a value greater than 1.5. So I'm going to set this to two. And let's expand the
spawn object here, and I'm going to direct the
create object component to the span object slot, and it will automatically add this component into
the first element. And let's also add the flame smoke prefab
to the cube here, and you can see we have a
flame in the game view, and let's disable the
flame smoke game object. So it is disabled on start. And if we select the
cube game object, let's add an entry to the death event field under
the death system component. And we can drag the
flame smoke game object to the object slot here, and let's bruce
the function here, go to the game object, and here you can see
the set active method. So let's just select
the set active method, and let's enable the bulon here or the check box
by checking it and that function or that
method are going to basically change
the active state of the flame object here. So right now it's set
to disabled by default. But whenever the death
event is invoked, it is going to enable this
flame smoke game object. Here, we want to leave the
cube game object alive. So let's just uncheck
the destroy option, and this will prevent the
object from getting destroyed. And now let's give it a try. And there you go. When the cube gets destroyed or the
health is depleted, you see that we have
this explosion, and the flame smoke
also gets enabled. And now the box collider
is also disabled here. So now we cannot shoot
this object anymore. Okay, so let's stop
the game here. And now we are going to
set up the health bar. And let's create a Canvas under the cube game object here. And let's set the Canvas
render mode to world space. And because we are not
using the event system, for this Canvas here, we can just safely delete
the event system, and event system, it
is used to detect, click on Canvas object or
cast on Canvas object. And we are not going to use
that for this help bar, so we can just safely
delete the event system. And let's rotate the Canvas
by 90 degrees on the x axis. Let's zero out the position. And let's decrease the
width and height to 200100. But it's still too big. And to make this smaller, we want to change the scale. Otherwise, the UI object
is going to be very big selted if we decrease the
width and the height value. So let's just change the scale value to
a very small value. I'm going to set this
20.05 on all axis. And let's move this canvas
to the cube position. We can set the z
position to zero. And I don't think we need
this canvas to be this big. So let's just decrease
the width to 100. And under this canvas, let's create a new image. And let's just call this health. And I'm going to change
the width to around 25. And for the height, I'm
going to set this 25. And I'm going to
move the health bar to be in front of
the cube object. And this is going to be
the health bar background, and it's still too
thick on the height. So let's just change
the height to 2.5. And as you can see
here in the game view, we can see the bar nicely. And I'm going to set the bar
color to a grayish color. And let's duplicate the
bar by pressing Control D, and I'm going to set
the second health or the second image to be the child of the
first health object. And this is going to
be the health bar. And I'm going to
change the color to red And here using
the anchor preset. I'm going to change the pivot by holding the shift
on the keyboard, and then I'm going to select
the one on the left here, the preset on the left, and this will change
the pivot of this image to be the most left on
the image boundary. And this way, if we modify
the x scale of the object, it will keep the anchor on
the left side of the image. So we we will be able to create the health bar illusion here or the illusion of
the health depleting. And now we have set
up the health bar. Let's select the
cube game object. And under the health
system component, we can track this
health bar game object to the health bar slot
on the health system. And let's save the scene, and let's give it a try. Now, if I shoot the cube, you see that the health
bar is decreasing. So we have a very
nice representation of the health on the scene. And another thing
that we can do, we can disable the health bar once the enemy is destroyed. So here under the
health system script, and under the check
health method, we can add a code inside the current health is
less or equal than zero. And here, we can just access the health bar and
access the transform and then parent and then
game object and then run the set active method and
set its value to false. And we need to access its parent here because if we go
back to unity and see that the health
object is basically the child of the
health bar background. So we want to actually disable
the health game object, not the health bar or
There is a better way. So I'm going to delete
this code here. And basically, we
can just disable the health game object using the on death event
under the death system. This way, we don't add more codes that are
not need to be added, and we can use this
on death event to invoke the action
that we want to do. So let's just add an entry on death event and we can drag
the health game object, and under the function dropdown, we can just go to the
game object and then run the set active
method and then set the toggle or the
bulon value to false. And this will disable the health game object when
this game object is defeated. So now let's give
it another try. And now, as you can see,
when the enemy is defeated, the health bar gets hidden. And this concludes
the spawn object and the Health Bar lesson. And let's continue
to the next video.
13. 13 Node Move - Creating Bezier Curve Movement: In this video, we
are going to create a movement script
that will follow a path defined by sets of nodes. We will use the script later
for moving a group of enemy along a path or the movement
pattern of our boss enemy. Let's create a new
C sharp script, and we can call the
script Note Move. Then double click it to
open it on our text editor. Once the script is opened, let's declare a
new list variable with type of vector tree. To declare a list,
simply type list, followed with angled bracket, and then type the
keyword vector tree, and then the variable name. Let's call this nodes. Then type keyword nest angled bracket vector
to construct the list. Don't forget to type the public keyword to make
it visible on the inspector. Next, let's create an integer that is a constant variable. This will define the
smoothness of our busier path. Now we can safely delete the
start and update method. Let's create a new
method that will handle the path or
curve creation, and this function will return
a list of vector tree. Let's rename the function or
method to get curve nodes. Since the method returns
some kind of data. In this case, a list of vectors, we need to type
return null first, and we will replace
the null keyword with our list of curve nodes. Before continuing, we
are going to create another method that will
return a vector tree. This method will be
used to calculate sier path based on four
different points or position, and it's time and time should
be on the range of 021. This method we'll
need a couple of arguments which are four
factors and one float. Let's call the factors
argument P zero, P one, P two and P three, and which will be the time t. Let's type return and then
some factor three value. So the script doesn't
give an error. In this method, we are
going to calculate a sier path using a cubic
sier curve equation. Let's Google the formula. Search for sier equation word, and open the first page result. Here, we're able
to see the formula or equation of the
cubic bezier curve. We will need for known
points or position, and the formula goes like one minus t and raised by power of three
multiplied by P zero, and then added with three
multiplied by one minus t, raised by power
of two multiplied by T and P one, and so forth. Let's write the formula
in our code. Okay. First, I'm going to type the
formula here in the comment, so I can easily construct it. The first part should be one minus t and then power of three and then
multiply by the first point. Multiply by P zero and then add it with
the second segment, which is three and
then multiplied by one minus t group together, and then power by two here, also multiply by t and
then multiply by P one. Then the third part is. This is like this, we can just copy all of this part here, but we are going to change this. This should be multiplied by t, and the t's powered by two. If we space this, we can read
it much better. Like this. Let's make sure if it's
correct, it's correct. Then the third one is
t powered by three, multiply by the last point here. Let's just type T powered by three multiply by
the last point here. We have this equation to
calculate a basier path, and this required four points. Let's just do that. Now
we are going to create a float of one minus t Since we are using one minus t a couple of times
over here as you can see. This is basically one
float minus T. Okay. And this is a vector
three result. Let's do the calculation here. Basically, we need to use
the math f function, power, and this will return return
the float value right to the power of P. We need to
insert the value first, which is one minus d, and then we are set of value powered by
three as shown here. Let's just type three flow here, and then let's multiply
this by P zero. Then we are going to add
this by three float, multiply multiply the
math f power again. This time is one minus
t, but raised by two, then we are going to
multiply this with T and then also multiply this with the second
point here, P one. The third one is going
to be three multiply by one minus t since this doesn't have any power
value over here, so we can just type one minus t, and then we are going to
multiply this by t times t, since this is only
powered by two, it's much easier to
type like this and then multiply this by P
this is P two here. Since I copy paste it and I
never got to change this. The last one, I'm going just to enter the line here
and put the plus here. And this is going
to be math F power, T raised by three, and then multiply this
by the last point, which is P three here. I'm going to enter
from this point here, let's just put this back on top so we have this
calculation here. And this is actually
one formula, one continuous formula,
but since it's too long, I'm just going to enter this. And if you don't divine
a semicolon over here, the unity or the code will
read this as one lines. You can do that. And
once we have this, I'm going to return
the result. Yes. There you go. Save
the script first. Next, we are going to get
curve nodes function, which return less vector tree. First, we are going to
create a temporary variable, which is less vector tree This is going to be
the curve nodes, new less vector tree. The first member of
this curve notes, it's going to be our
transform position. But later we are going to change this to a local transform. So just bear with me. I'm going to explain
this all of it. Now, let's just look all of
the member of the notes here. We can just get the count. But we want to make sure that we subtract the count by
minus by three here, and we want to increase
the value also by three. We want to iterate
every three points that are available in
the curve nodes here. Now we are going to create
a couple of factors. This is basically
the first point, and this is going
to be the nodes. This is not the curve node,
it should be the nodes. Just change this nodes here because we want
to look through the nodes that we define
in the inspector. This is going to be the nodes. The second one is going to be
nodes index of i plus one. And let this copy this line here and past this couple time and this is going
to be the P 2.2, and this is going
to be i plus two, and the third one P
three is going to be i plus three index. This is why the loops index
gets increased by three. Since calculate baser
path method needs four points or position
for every iteration, we will calculate a baser
path using the method, but also includes the last point from the previous iteration. First, we are going to make
sure if i is equal then zero, Then we are going to
create the first path. We are going to add
to our curved nodes, since this require
a vector tree, we can just type the function,
calculate busier path, and we can just put
our points from here. The one we declared here, and type P zero, a P one and P two
and then P three. For the P, we are going to
use is going to be zero, this is the first position. And semicolon here. Now, let's create another
loops with index of j. Since these loops are
inside of our first loops, and the letter I has been used as the index
of the first loops. And for the length of our loops, we are going to use the constant curve segment
that has value of 20. This means for every
iteration of the first loops, we are going to generate 20
points on the second loop. We are going to create
a float t here from our value by the curve segment. But since T is a float and
this is basic integer, and this is also an integer, best we convert one of
either the number here, or the divider to float. I'm going to just to cast
this to a float here and make sure it has a float result. Now let's just copy this here, paste this and for
the float here, parameter we are going to
insert t from this value here. Let's save this and
we need to create some sort of representation in the scene so we can see it, so we can just use the function
for it on go selected. Basically, we are going to
create the curve function here by create a new list
of vector three. And just name this
curve positions. To a new list vector three
and save this sorry, we need to add a parentheses
and for the curve position, let's just run the get
curve nodes function. So we have the curve nodes
inside of our curve position, and now we can look through
our curve position. So I'm going to
copy the variable and I'm going to look
through its count here. And I'm going to draw sorry. I'm going to gsm draw line. I'm going to use
this function here. And basically this
needs to factor. So I'm going to
start for one and basically I'm going to draw the first position is the
curve positions i minus one. So if i is equal one, then this will be zero, and the second one will be
the curaron index like this. To make things interesting, we can just change gizmo color
to let's say color green. This is basically a basic color that unity already provide, which has value of zero, and the green is one, the blue is also zero and
the Alpha is one. But if you want to
create a new color, you can just type new color and try your value
here, for example, one, 0.5 and you can just
do this if you want to. Or if you want to
put Alpha also, you can just type
value for the Alpha. But for this case here, I'm going to use the
pre divined color that Unity already has provided
for us. Just use this. Let's save this and see
if this is working. Let's just choose our cube here, and let's add the node move. But basically, the
script isn't moving yet, so we are creating
the curve first. And as you can see
here, we have nodes. And if we type if we
put some value here, we can for example, I can set some value here, It should be drawn, actually. Let's just set some
value, some random value. And, so there is an
error from the script. Okay, okay? Let's just fix this. We need to make sure if the curve position
has some value here. Now we can simplify this by put the function right away when we declare the curve positions. We forgot to return
the curve notes here that we already built
from the get curve notes. Let's just return
the curve notes. Save this and that is compile for a while
and let's clear off. There you go. We can
see our path here. We can basically
adjust its position there and we can just move this and it creates a
curve, basically. But I know this is
not quite intuitive. In the next video, we
are going to create handles using editor scripting, so we can design with
a more intuitive a
14. 14 Node Move Editor: In this video, we
are going to create an editor scripting to
create a custom control, to make controlling
the curve much easier. First, let's go to
the script folder, and then let's
create a new folder and we can rename the
folder to editor. And for all of the scripts
related to editor scripting, we need to put it inside
the editor folder because all of the script inside this editor folder will not
be included in the build. And inside this editor folder, let's create a new
C sharp script. And let's call this
note move editor. And once it is created,
let's open it. And here we have the
Note Move script from the previous video. It is not finished yet. We are going to
extend this later. But for now, let's work on
the note Move editor script. And first, let's just delete the start and
the update method. And we also need to include the Unity editor
namespace here above. So let's just type
using Unity editor. And we need to make
sure that the script inherits from the editor script. So let's just replace the
mono behavior with editor. And we will also need to
add a custom editor text to target the script that we want to create this custom inspector. So let's just type custom
editor and an open parentheses. And then type off, and then another
open parentheses. And here we need to put the class name that we want to create the custom inspector for. And with this setup, the script will overwrite the default inspector for the note move script
on the inspector. Once we've defined all of the custom inspector
inside this script. And in this script, we are
going to declare two method. The first one will
be an inspector GY, and this is an overwrite method from the base class editor, and the script we draw all of
the custom inspector later. In the editor here, it will replace the
default inspector, and the other method
that we need to create is the scene GI method, and this is for creating custom
gizmo on the scene view. And now we are going to focus
on this scene GI method. And first, let's create a
reference to the target class, which is note move here. So we can just declare a
variable type of note move, and let's just call this source. And here, at the beginning
of the unseen GI method, let's grab the target class
into the source field. So let's just type source equal, and then we can cast
the target into note move by adding a casting in front of
the target keyword, and target is basically the object that are
being inspected. In this case, it is
the note move class. Next, we need to look
through all of the nodes on the source or on the
node move object. So let's just create
four loop here. And for the length,
we can replace this with source dot nodes, and nodes is the list of vector that we have declared
here in the inspector. But we need to add the.co
properties so we can get the member amount to
loop in this four loop, and for Each of this vector
inside the node list, we want to create
a custom gizmo or handles to make it easier to
control in the scene view. So first, let's just grab each of the member
from the nodes by typing source node
nodes and then index of I using
a square bracket, and here can set the
value to handles, and from the handle class, We can use the position
handle method, and as for a factor
three position and a quaternion rotation. And this method will create a position handle
in the scene view. So for position, let's just pass the source dot nodes index of I, which is the factor three
values from the nodes member, and for the rotation,
we can just pass quaternion dot identity. This won't change any rotation. And here below, we can create
a label for the handles. So let's just type
handles dot label, and we can pass the position for the label position
as the first argument. And for the label, we can use the second overload
of the label method, which asks for a string value
for the second argument. So I'm going to type nodes, and I'm going to contentinate
with the y value, but I'm going to add
one to the eye value. So the first index will be drawn as one instead of
zero in the scene view, and let's add a semiclon
and then save the script. And now let's head
back to unity. And now, as you can
see, we have a couple of handles here on the sin view, and each all of the
handles has a label on it. And this is the last note. We can move this, but it doesn't affect the curve because
with this curve, we are evaluating the curve
every four notes in the list. So now it's easier to customize the curve from the sin view instead of modifying
from the inspector. And here we can also
draw a second line to connect the nodes here
to show the real lines, how it looks on the scene view. And to do that, we can just do it inside
the node move script here under the Gizmo
selected method, and we can create a new
four loop here below. Let's just look through the
nodes list member here. We can just replace
the length with the nodes co to look
through the nodes list, and let's just copy the
gizmo code here above. And let's change the
first index two, one. And let's just change
the color yellow. So let's just
create a new color, so we can create a
transparent color. So I'm going to create a
temporary variable called gzmoclor with a type of color and assign it
to the color yellow. And here below, let's
change the alpha. So let's just access the
gzmoclor variable A, which is the Alpha value, and I'm going to set
its value to 0.5. And instead of assigning the
gizmo color to color yellow, let's just assign
the gizmo color to this gizmo dot color here. And let's save the script. Here, I forgot to replace the list when we are
drawing the line. So let's just change
the curve positions into notes on both
of the argument. Let's save the script and
let's go back to unity. And now, as you can see, we have this straight line that connects all of the
nodes in the scene view. Another thing that we want to do with this cube game object, we want to parent this game object into
an empty game object. So let's just create a
new empty game object. And let's copy the
transform value from the cube game object here, and let's paste it
to the game object, so it will be on
the same position. And then let's
direct the cube to be the child of this
game object here, and we need to do
this because later, we are going to
convert the line or the nodes calculation from
world space into local space. And this will make it easier to reposition all of the object that are going to move
using the note move editor, and it will move relative
to the starting point. And this will make it easier to reposition the enemy
in our scene later. This part is optional, but we are going to add a slight adjustment for
the custom inspector of the note Move script
here and to make it easier to add points
or to add notes. So let's go to the note
move editor script, and here we already have
the uninspector GI method. And here on the
note move script, I want to add a button, so we can do this inside
the uninspector GI and this button will act as a way to add and remove nodes easily. So here on the uninspected GI. Let's grab the reference to the target and pass it
to the source field, and we can just copy the line
here from the unseen GI, and here below the base
uninspected GI code, we can create a button
using an if statement, and for the condition, we can just run
the button method from the GI layout class. And here for the argument, we can pass a text And
for the button name, let's just type nodes. And inside the
statement, basically, we want to add a new nodes
member to the notes list. So let's just access
the source and then notes and we
can run the method, and let's just pass
a vector tree here, and let's just grab
the transfer position, so it will create a new nodes at the position of
the game object. And we can also
add another button for removing the last nodes. So let's just copy all of this statement and rename
the button to remove nodes, and we can change the add
method to remove And I'm going to use the
remove add method and removed as for the index, so we can just grab
the last index from the source notes by
accessing its co properties, but we need to substract this
by one because as always, collection starts from zero. So the latest member
or the last member of the collection will always
be less than the co value. Let's save the script, and
let's head back to unity. And now, as you can see,
after the script is compiled, we have the two new buttons
on the note move script. And if we press the
add notes button, as you can see it add a new position or a new
member to the note list here, and we can add a
couple more nodes. And here we can just move
the node in the scene view, and then we can also
create another new nodes. The first note is somehow has been moved on the y axis,
so let's just adjust this. And if it's hard to
correct on the scene view, we can just type the value
here from the inspector, and it will also
change the nodes. With this custom inspector, we can easily create
or remove nodes whenever we are going to design
the enemy movement later.
15. 15 Node Move - Moving Objects: In this video, we
are going to create the movement for the
note move script. And as you can see, we
already created the Gizmo, using a editor scripting. So it's easier now to
design the curve nodes instead of modifying the
value in the inspector. Now we can modify the
value easily in the scene. And as we move this gizmo, it changes the notes
value in the inspector. And now let's open
the node move script, and now we need to declare
a couple of new variables. So first, let's create
a public float, and we can just call it speed. And we need to create a couple
of float variable here. So the first one
will be a speed, and I'm going to set the
default value to two. And the next one will
be a rotate speed, and this is for the speed
when the object is rotating. And let's just set
this also to two, and we can change this
later in the inspector. And the last one would
be the banking value. And this is the maximum
banking value in the grease whenever the ship turns
depending on the movement. So the banking value will affect the zero rotation of the object. And next, I'm going to create
a public bullion variable. And the first bulon variable
would be a rotate object. And this is for a togal
whether we want to rotate the object or not while the object is moving
across this curve. And the other bullion, we can just call
it loop movement, and this is for the togal check whenever we want to loop
the movement or not. And the next variable, it's a public integer, and I'm going to call
this loop to node, and this will decide which nodes are we
going to loop through. So for example, if we want to go back to the second or third node instead of the first node, whenever the object is looping, then we can set this loop to node to a certain node value. So it will loop through different starting position
instead of the first nodes. And I'm going to also
add a private integer, and this is going to be
called real loop node. And this is basically the real node position based on the curve
nodes because we are going to convert
the position from the nodes position
into the curve nodes. And we need to create a
fit on enable method. And let's also create a
void disabled method. And both of this method, it's a built in unity method and enable gets triggered
whenever the object gets activated and disabled executed whenever the object gets
disabled or gets the activated. And basically, we want to start the movement whenever we enable this game object
and we want to stop the movement whenever this
object gets disabled. So for moving this object, we need to create a coroutine. So let's type a written type of enumerator and we can just
call this start move. And here inside
the core routine, we want to create a loop so we can just create
a wi statement, and for the condition, we
can set the value to true. So this will get executed every frame while the
co routine is running. And we need to add a yield return null inside
the while statement. Otherwise, it will
cause an infinite loop, and it will crash the unity. And yield return le will
make sure that it will stop the execution and continue the execution on the next frame. And now we have declared
this co routine. We're going to work more on this curroutine But now we
can just add a start co routine inside the
nenable method and then execute the
start Move co routine. So just type start
co routine and then pass the start Move
coroutine name. And on the disabled method, we can just run the stop
all co routines method, and this will disable all of the co routines that are
running inside the script. And now we can work on
the start Move coroutine. And before continuing,
I'm going to rename the loop movement
variable to loop Move. So it is shorter. So inside the WL statement, let's create an statement, and we want to check if the
loop move bullion is enabled. We want to add an R statement. But before continuing this, let's create a local
variable here, type of integer, and let's
just call this position ID. And basically,
using this pus ID, we are going to keep
track which factor on the curve node list here
we are currently going to. And if we arrive, then we are going to
increase the pus ID, so it will go to
the next factor. And here on the R condition, we can just add the pus ID, and we need to make sure that if the PS ID is less than
the curve nodes length, But before we can do that, we need to generate
the curve nodes. So let's just create a
curve node here above and declare a local list variable
type of vector three, and we can just call this path, and let's just initialize
this by passing the result or the return from
the get curve nodes method. So we can just execute the
curve notes method here, and this will calculate
the curve nodes and pass those curve nodes into this list of vector
three called path. And now we can check if the position ID is less
than the path dot count, which is the number of vectors that are
inside this path list. But we need to substract
this by one because as always array index
start from zero, so we don't want to include the maximum count because it will create an
index out of range. Yeah, we need to
assign the value on the PoS ID because we have
this red squigglines. So I'm going to assign the PS ID 20 here
in the declaration. Yeah, I've made a mistake here. Basically, this condition here, the condition should be
on the WIL statement. So I'm going to cut
this if condition and then paste it inside the wild to replace
the true value. And here, inside
the if statement, we want to check if the object has already arrived
to the target position, which is the path index of pos ID, and that
would be the target. And if we already arrived, then we want to increase
the position ID value. So we can just type
path index of po ID, and then we can subtract this with the transform
that position. And from this
vector calculation, we want to get the
square magnitude, which is the distance, but it's the distance
in square value without the square
root calculation. So it's more performant
compared to using magnitude, and we can just compare this if the square magnitude is less
than a very small value, then it means that we already
arrive in this position. Or we are very near to
the target position. And here inside, we want
to add another check, and we want to check
if loop move is true, and let's just also
add an L statement. And inside the statement, the first block here, we want to add
another statement, and we want to check
if the PS ID is less than path.co
substrate by one, then we want to increase
the position ID. We can just type PS ID and
with double plus sign, this will increment the value. Or we can just type using the plus and then equal sign and
the value, which is one. This means the same
as the code before. We are incrementing
the integer by one, and we need to add
an L statement here, and here inside the L statement, basically, we want to reset the PS ID to the real loop node, and this will only applies if we enable
the loop move option. And this means that if the PS ID is at the
end of the path count, then we want to reset back
to the selected loop node. And the real loop
node value will be converted from the loop
to node integer value. And here in the L statement, we want to increase
the position ID if the position ID is
less than the path count, so we can just copy
this line from the first and paste it here
in the L statement. And now we want to
move the object. We can do it inside
the OL statement before this yield return, and we can access the
transform dot position, and we can use the move towards method from the
factor three class, so we can just type factor
three dot move towards and move move the object
linearly, unlike Lerb. So this is more suitable for moving the object using
this note move here. And for the first factor, we can just pass
the Caron position. So let's just type
transform that position. And for the target position,
which is the factor B, we can just pass the
path index of pus ID, and this will return the next factor that
we need to go to. And for the next distance Delta, we can use the value speed, but we want to make
sure that this speed is applied per seconds
instead of per frame. So we need to multiply the
value using time Delta time. And now let's save the script
and head back to unity. And let's give it a try. So let's press play. And as you can see, now, we have the object moving
to each of the nodes here. Now, let's go back to the script and we can work on
the loop movement. And now to calculate
this real loop node. We need to calculate this inside the GT curve
nodes method. So here we can just
type real loop node basically we need to assign the real loop node to the value of curve nodes co multiplied
by the loop node, divided by the nodes C, and this will get the fraction or the
percentage of the real nodes. And from this percentage, we can convert this to the curve nodes position
by multiplying with the of the curve nodes
because the curve nodes will have so many vectors compared
to the real nodes here, and with this percentage, we can get the index
that will translate approximately the real nodes position into the curve nodes. And now let's save the script. And let's give it a try here. Now, let's head back to Unity. We need to enable the
loop move option here. And now let's give it a try. And now it's moving, as you can see, but
let's take a look. Yeah, as you can see here, it moves back to the first node, whenever it goes to the N and then it will
continue moves again. This is for me from the future, and we need to fix a small box inside
the note move script. So basically here in
the temove script, whenever we calculating
the real loop node here, as you can see, we are dividing the loop to
node with the nodes, and both of these
value are integer. And this will produce either value of zero or one,
so we need to fix this. And in order to fix this, we need to cast the divisor, which is the notes dot
count here into a float. So we can just add a parenthese and then type float and
then close parenthese, and this will cast the nodes dot count value into a float. Once we cast this
value to the float, then we will have
a decimal value. And once we finish calculating this curve nodes dot
count multiply it with the percentage of the
look to note value here. We need to cast this
back to the integer so this will round the result
value to an integer, and we can use that integer
as a real loop node index. Otherwise, it will only return the first node or the last node because
the integer division. So this concludes the moving objects part
for the node move, and we can continue
to the next video.
16. 16 Node Move - World to Local: We are going to
continue expanding our note of script
here, let's do that. Somehow I moved the notes here. We basically already succeeded in creating a movement,
but there is an issue. Whenever we parent
this game object to another game object, let's say, and then we move
this game object here, so it should move. When we start to play this, the nodes is on the
world position. So it was moving to the
world position of the nodes. What do we want to do
is basically to convert this real world position
of our nodes into the local space of our object. Why do we need to do this? This will be useful
for the bus pop. Because whenever the bus appear, it will follow us and we
have to fight this bus. The basic concept,
it will be that the bus will get parent
to the world transform. We are going to have a
world empty object that are going to move the scene, but the camera and our player. And what we want to do is
whenever we encounter the bus, then the bus gets parented
with this world moving object. It will move together with us. But the bus will still to
have its own movement. Now we are going to do that. Okay. Let's just push this back here and go
back to our script, our move script here. And now we are going to
create another variable, and this is going
to be a transform. Let's call this
transform parent. I'm going to Iran
parent is available. If we have a parent,
then we want to set the parent to our
transform parent. L. If there is no parent at all, then we need to set this
parent to our own transform. We can use this variable
for any condition. Now here, we are going
to convert all of our pi our vectors
into a local space. In order to do that, we can use a comment can use the transform, for example, this parent, and we can use method called
inverse transform point. This is basically transform the position from world
space to local space. We need to use this. Now, I'm going to change every position that we have into
the local space. I'm going to type
this here parent and use the inverstrantfm point, and then I'm going to put this vector position
here inside the instrum. I'm going to just to copy this
out to make things easier, and then I'm going to paste this on every vectors
that we have here. And also here and put it here. The other thing I
think that should do we need to also change
the position here. Since we are drawing
on the world space directly before and now we already convert our points to the local space for the
curve notes member here. We need to change this.
Since this is also a vector, and we can use this directly, but right now we don't
want to inverse. We want to convert back from
local to world. Why is that? Because the curve position is
already on local position, local transform here,
since we are using this, we need to use another method which is called transform point. Basically, this one is
inverse and this one is transform the position from
local space to world space. We are going to use
this. Pace this at another parentheses and just use the other method
called transform point. Let's say this. Another
thing we need to do is to change our
position movement. Basically, now we are going
to use trans position, but transform local position. For this, so I'm going to chase
transform local position, and this is also going to be
a transform local position. Let's save this and cross
our fingers, hope it works. I'm going to save this. We can just press play and
see if it's working. Okay. There is an
error apparently. Okay. Yeah, I forgot one thing. Here, parent is somehow
is not defined yet. So we need to copy this comment here and also put it on
top on this method here. So we are going to make sure
that the parent is not. Okay. And let's
press play again. Let's try this again,
hopefully it's working working now we
can move its parent, and as you can see, our game object is
following the parent. It's still moving
on the same curve, but the curve is offset
relative to our parent here. I I move it again, then it
will move in this area here. But if I push this back, it can move to the
initial curves. Basically, we have succeeded
in converting the curve to the local space of
our game object here. Another performance
step, by the way, In order to move an object, Since we are moving the object, it is very recommended
to add a rigid body, since we are using collider. Unity set or explain
that we should not move an object that has only box collider and using the
transform that local position. I'm going to add a rigid body. But we can set the rigid body to schematic and
disabled use gravity. This will not calculate
any physical movement, but unity will see this
as a dynamic object. It's much more performant than without using
this rigid body. Okay. So just save the scene, and next, we can continue
on doing the rotation.
17. 17 Node Move - Rotate Objects: Now, let's do the fun stuff, which is rotation, and we are going to use
a lot of quaternion. But it's okay. Don't be afraid with
quaternion because we can convert from our ular
values to the quaternion. Let's go to the script. Let's open our note
moo script here, and we already prepared a
couple variable for rotation, but we need to add more. Let's type a new private float and this is going to be
the next angle grab. We want to get the
rotation value, maybe every half a second and we are going to lark our rotation
to that value every frame. We are going to have a
very smooth rotation, and I'm going to create a
private quaternion variable, and this is going to
be the rotation value. Rotation. What's wrong with
my keyboard. Okay. Now, let's go back to
our start routine here, and here we have this movement. Let's create a comment. This handles the index of the path vectors and decide the next target position. Now we are going to check
whether we have enabled the rotate object and here, I'm going to create another f, and this is going to be if time is greater than
our next angle grap. Whenever time the time is greater than our
next angle grap, then we want to grab
the new rotation. Here we are going to
increase our angle grap to a value of time time, but we are going
to add half float, so it means half second
to our current time. And this will get
evulated again whenever our time is bigger than
last angle grap here. First, we need to
create a vector tree, and this is going to be
the direction but equal. For the direction, it's going
to be path index of pus ID. The vectors that are currently our target and substract with our transform
the local position. Since all of the vectors are
already in local position, so we are going to
use this always. Okay. And here, I'm going to check if the square magnitude is greater
than a very small value, let's say 0.05 because I
want to avoid whenever the square magnitude or the
length of our vector is zero, and this could happen.
I want to ignore that. I want to make sure we
only calculate whenever our deer length is
greater than zero. Then we are going to
define our rotation value. This is a quaternion, and
we can use the quaternion struck and we can use the method inside of
it called rotation, and this create a rotation
with the specified forward. This will create a rotation that specified from a
direction factor. This direction for deciding the forward rotation
of the object. Okay. Let's just use the
deer for the upwards, I'm going to use the
vector three so the world because is the y
axis and basically, we want to rotate
our game object on its y axis over
here like this. That should. We
want to make sure that our axis facing up. Here, we have this rotation. Now we are going to we are going to create
a banking value. Let's type float z bang. We are going to get our current
rotation on the y axis, but substract with
our less angle. The angle from the
previous graph. Here, we need to create another variable.
Let's just do that. On top of here, I'm going to create an old angle variable and the type will be float
and I'm going to set this value to
eight fold of zero. But here, we are going to
get our current rotation, because this will
be our rotation, and I'm going to get its ular angles value and
get the y axis value here. This is quaternion,
and we need to get the y value from its ar value. Luckily, with quaternion, we can get its ular angles value by typing this ular
angles properties, and it will return the ularng. It will return the
ularngle representation of the rotation and subtract
this with our old angle. So we have a banking value
here that we can use. But I think we are going
to clamp this value. So let's just use a
math dot clam. Okay. And we are going to make sure that the minimum
value is going to be minus ten and the
maximum is going to be a positive ten flow here. Now we can create another
quaternion for banking value, banking, for this bank here, we are going to
create a new vector three and the value is going to be zero
on the zero on the y, and it's going to be
our bank value here. But let's multiply this by our banking value,
our variable here. We can create how
extreme is the banking will be or Yeah, like that. Since this is a quaternion, we need to convert this
vector to a quaternion. Let's just type quaternion ular put the vector
here or we can just type the new keyword new vector here and just put
its value here. There you go. We have this banking
quaternion rotation. But since this is a float, we want to round this value, it will be much smoother,
so we can use the math. F one, this one, and put the z bank here. Z bank inside of it. We want to make sure that Z bank always return a route number and we can multiply this rot
number by our banking value. Now since we already have our basic rotation and we
have our banking rotation, we can just apply this
banking to our rotation. In order to add a
rotation to a quaternion, we need to multiply this
quaternion with the quaternion. Let's just multiply this and equal the banking value here. After we already add our banking rotation to our basic direction
rotation here, we are going to
grab our old angle, and this is for the
next angle grab later. This will be our
rotation, ular angles. Dot y. That should do the trick here. I'm going to cut this all
since I put it somehow wrong, and I'm going to put this
below our movement here. So after the transform the
local position line over here, and after we enable
the rooted object, we want to apply the rotation. So we can just use
the trans rotation and we can use a quaternion sl, For the value, it's going to
be our previous rotation. Just like move towards, but
this is for the rotation, and this is the spherical spherically interpolates
between A to B. I will interpolate our quaternion a value to
the quaternion b value. For the b value, it's going to be
our rotation here, the rotation value that
we already calculate inside the next angle
gram moment here. For the speed, we
are going to use the rotate speed, as always, we need to multiply this
by our time dot a time. Okay. So we already
apply the rotation. Let's save the script and cross cross our fingers
if it's working or not. So now we set the
begging value to five and we should enable the rotate
object options over here. So let's play this. Now we can see here our
object is banking, but somehow it's banging
on the wrong way. We can fix this very easily. But I go to our
script here and set this banking value to a
negative value over here. We are inverting the value, and this should do the trick. Let's play this
again after I finish compiling and C,
and there you go. Our object is banking
every time it's turning. Okay. Yeah. So now we have a node move
script that handles curve, and so we can look the movement, and also we can do
banking animation or banking effects for objects
such as enemy plane later. With this, we can continue
on the next lesson.
18. 18 Enemy Waves: Okay. Now we already
have this node moving. Now it's time to create
the enemy wave script. With this script, we
can create a copy of our enemy depending on the
options on the inspector, and we can also set
the delay so we can have a nice my
flying formation. Let's create a new folder
and this is going to be enemy scripts and inside
this my scripts folder, I'm going to create a
new C script and I'm going to call this enemy waves. Okay. Let's open our editor. Yes. We already
open this script, and I'm going to
make a smaller bit. We need to declare a
couple of variables. I'm going just to copy paste the variable that I
have already prepared. Basically, I'm going to
explain this one by one. The first one, the integer
with the name num waves, this is the number of enemy
waves that we want to create. It sets the fat to one, but we can change it on
the inspector later. This is the interval
between enemy. How many seconds do you want
to launch each of the enemy separately and We want to disable the enemy
after 2 seconds here, and of course, we
can change this depending on the
length of our curve. Basically, what this variable
does is we want to remove the enemy after it doesn't get shot for let's say 2
seconds or 3 seconds. If we fail to kill this enemy, then we want to
remove this using a another method and we will
create those methods later. We don't let this one,
we can safely delete this. Save the script. This is basically a list of game objects and every
child that we instantiate, we are going to put
it in this list here, there are two private variables. The first one is game object, and this will hold
the first child. Basically, we are going to put only one child on the enemy
groups, but on start, that main child will
get instantiated depending on how many wave
number we have set up here. The next variable is basically
a wait for seconds type, and this is for the coroutines later for the interval
and also disabled after. The value of each of
this wait for seconds is going to be set from
this float here. Now let's start
creating the codes. I'm going to delete
the update method since we are not going to use that I'm going to declare
a coparl co rooting first. Let's create an it and here
we are going to get our main child type the
variable main child and we are going to get
from its strat form, get child zero, the first child. Since there will be
only one child on the enemy groups and we
are going to get its game. Another thing is, we want to get its
position in the world. Let's just do that, create
a new temporary variable, and this will be the main
child transform that position. And we want to disable
the main child, type the variable Mind and use the set active method
and set this to false. It will be disabled on
start and we want to add the main child here to our
child's game object list here. Just type the variable
name which is child and we are going to add
the main child game object. Now we are going to look through the waves
here, call this Okay. And since we already have
the first child over here, then we want to start
from one, not from zero, and we are going to instantiate a new game object and we
can just store this to a temporary game object
variable and use the instantiate command and we are going to instantiate
the main child. For the position, we are
going to get its position. And for the rotation, we can just get the main
child transform the rotation. Okay. So it has the same rotation as
our first child here. We want to add this game object temporarily to our list here. Child temp here. Now we want to make sure that this child transform set
parent can use the method here to our group game object or end game object that are holding this we script transform. This t game object will be
the parent of the child, and we want to also set
child to disable at start. We are going to use the
set active to false. Now we can save the script. This is for the initialization. Next, we need to do is to
create the coroutines. Just type I numerator and
let's call this start waves. Here, we need to look to
our number of waves here. We need to create a new
temporary variable. Just name this and set
this value to zero, and we are going to set while i is less than our numb waves, then we want to look the
condition below here. I'm going to add some space
here for easier reading. Now we want to
activate the child based on its index
I set act to true. Then we want to yield return based on the
interval that we have. But before yield the interval, we want to increase value. So we increase by one by
adding the two plusin, we are increasing by value
of one and we need to disable the child after
a certain seconds. And this will need a another coroutine
type this you do here. So we can remember later, we need to add the courtin here. Now let's create another croutin this is for disabled child. We need to pass the game object. So we can pass the child's index of I to this argument later. Here, we are going to
basically we want just to yield return using
the disabled after, and we want to check if the
game object is not destroyed. Then we want to set
the game object to. Now we have this. We can use this routine
to disable child. Let's just write it here. Start routine and pass disabled child here and pass the argument
inside this parenthese. That should do. Now we need
to also count how many. If we already killed
all the enemy or if there is a
chain loss event. We are going to create a new coroutine
called check combo. Okay. So first of all, we want to delay this
coroutine with a new weight 4 seconds and the value will be depending on our
transform child count. If we have six childs, then this combo here, this co routine here will
be delayed for 6 seconds, and then it will start to the codes below this yield
return weight 4 seconds. We want to check if the
transform child count is equal zero, s equals zero, It means that
we kill all of the child. And we can print something
here for the bugging later and killed Combo killed, maybe. And if we miss if we have child count
still greater than zero, then it means that we haven't
destroyed all of the child, so we can just print. Okay. Chain loss. Later, we can play a sound audio here describing that we have
lost a chain of enemies, just like in sky force. Now we need to put some
codes in the start here. Basically, we need to insert
value for the interval, since we haven't put
any values here, so we are going to put a new weight for seconds
and the value will be the interval between enemy
float and disabled after, it's going to be also a
new weight for seconds and this is going to get
the remove float variables. And let's run the int function. After that, we can just run the start coroutine start waves, and the second coroutine
is start co routine, and this will be
the check combo. Basically, we want to start the waves here, and
at the same time, we want to check the combo
and the combo will be delayed for depending
on our child count. Hopefully, we already destroyed
before this checks out. And we should do the trick, and let's start plying
the script on the object. Now for the cube here, we can just use an enemy here. I'm going to go to our models here and I'm going to
grab this plane here, the plane D and put it
as a child of the cube. We can just remove the cube
and measure the component. Later, we can also
scale the box collider, but now we are going to set this like this here
for the enemy waves, we want to put it on
the parent object here. So where the plate
is attached to, then we want to put it there. Let's just add the enemy
waves here and here, let's put some value
in the number waves, and let's name this enemy waves. Let's call this enemy wave, and this will be the
call this my play. Save this. So let's
try to play this. Okay. There you go. We have those copies. But as you can see here, since the ship is moving too
slow, gets destroyed easily. I'm going to make this
value of the speed to five here for the enemy waves, we can remove after
maybe around 10 seconds and for the interval between
enemy set 1.5 seconds. You can try whichever values that suits your design
your gap design. Let's try to play this again. There you go, two, three, four, But since we
have this looping, the movement, the
ship is looping. We need to make sure that this disable the loop
move nodes here. Later, we are going to put
this enemy waves outside of the camera frame
and we will have a collider on the enemy
wave to get triggered by the edge collide later that we are going to
divine outside the camera. Whenever an enemy gets
triggered by this collider, it will get activated. That should do for
the enemy wave and we can continue
on the next lesson.
19. 19 Auto Rotate: Okay. So now we are going to do a couple more
transform script. In this video, we
are going to create a script that will
automatically rotate an object. So I'm going just to disable
the enemy waves first here and I'm going to
create a new enemy. Let's go to our models folder. And here, I'm going to get our round turret I'm going
to put it on the scene. Where is it? There is it. And Okay. Now we have this
turret over here. Basically, this consists of
two object, the base turret, and the circle the upper part
here, the top part here. Now, let's just create
the script first. Go to the project, go
to the script folder, and under tranfm let's create a new script and call
this auto rotate. And let's open it. Now we have the script opened, and we need to create
a couple of variables. I'm just going to paste the variable from the
code I have prepared, and these are the variables, and I'm using a header
attribute for its variable. So this will make our variables group
under this header nicely and you can lay out your variables on the inspector
better for readability. Basically, We need
one float variable called the rotate speed, and we also need two
bullion variables. The first one called endless and the first one it
is called start. If we want to create a
continuous rotation, then we need to enable
the endless options. If we want to enable the
rotation on start right away, then we need to
enable this bullion. The second variable is factor, the last variable
is factor three and this is for
targeted rotation. It means that if we don't
use the continuous rotation, then we can use this
target rotation. It will rotate to
a certain angle that we want that we define
here on the vector tree. But I'm going also to change this rotate speed to
a vector tree first, so we can create different
kind of rotation, different kind of rotation here. Let's do this. First, I'm going to
delete the update. We are not going to
use the abate method and we are going to use
a routine over here. I'm going to create a new
public void start rotate, this will be a public method. Then we can use
inside unit event. For example, we can
use under here, the unit event on death
event or anything else. For example, if I'm going
to check for this Later, we are going to use much more
unity event, but basically, I'm making a public
method available, so we can use this for
another unity event so we can trigger this rotation from another script
using Unity event. If we don't want
to start it right away using the start function. Now I'm going to create the co routine and I'm going
to call this rotate. Here, I'm going to create
a new local variable, a quarternon this is for
the target rotation. The target rotation
will be the transform, the local rotation,
and the oler angles. Added by our angle rotation. But since this is in ular I need to convert
this to quaternion. I'm going to use the
quaternion class and use the ar method and put all of this ular values
inside a parentheses. Now we are converting from a
ular values to a quaternion. I'm going to check if the
endless bullion is enabled, then we want to do
the endless movement or endless rotations rotation. I'm using while here, this code will keeps
running because endless is true and we are
going to add a yield return. Here we are going to
rotate our game object. Let's just type transform, rotate and it's
using Euler angles. Let's just use our
rotate speed over here. Since the continuous rotation, using the Ls option here
and close this with A to C. To make this rotate
every second. I mean if we want to rotate
90 degrees every second, then we need to multiply the rotate speed
value using the time Time. Save this. We need to create
another condition whenever it's not endless, then we want to create another
while condition over here. We want to check
if our transform the rotation is not the same as our target
rotation currently, then we want to
continue rotating. Now we are going to
transform rotation, and we are going to use the
quaternion rotate towards. This is a function to
create a rotation from a certain quaternion value
to another quaternion value. And we already have
the target rotation. The previous quaternion rotation
would be local rotation, and the target would be our target rotation from
this value here. And we need to put a
max degrees Delta here. And for the rotate speed, we can just use the magnitude
of this value over here. Let's create a float that store this magnitude
once over here. Float speed and sorry, I somehow delete the
rotate speed over here. Let's create a float speed and get our rotate
speed magnitude. And we can use the
speed to define our degrees Delta but
multiplied by delta time. It accumulates in
seconds the speed here. Let's put a yield return. No. But I think for clarity sake, I'm going to delete this
here and I'm going to put another float inside
the target rotation and we are going to
put a speed here. We are going to use the
speed from this variable, so we can define
a different speed and just to group it better. The design or
whenever you want to design your level
design your enemy, you'll know whenever
you use angle rotation and you need
to use the speed. Otherwise, you
might forget to put some value inside this variable. Now we have this routine. Now we can start our routine. First on start, we
are going to check if on start is true, then we want to
enable our routine. Start coroutine and let's
execute the d rotate routines, and I'm going to just
to copy this lines here and paste it on
the start rotate. And I maybe some
of you wondering, why do we need this
method, basically, just like I explained it before, we need to create this
start rotate method, whenever we want to trigger this rotation from another
script using Unity event. I'll show you later just
how we can do that. But right now, we can save the script here,
and this is, of course, we'll get executed whenever
we start the game, but only if the start bullion
is checked or is enabled. One more thing we
need is to create a disabled method and Undisables basically a built in unity
method and it always gets executed whenever object is being disabled or
it's being destroyed. We can just stop all coroutines inside
this disabled here. Save this let's try this. Go unity, let's put script to rotate to the circle turret here and where is it
Outro put it here. Okay. And as you can see
here, we have a group of continuous rotation rotation. I want to create a
continuous rotation, and I want to make
sure that we are rotating on the Currently, I'm not so sure because the
axis is somehow rotated. I want to make sure that we
have a y axis to the top so I'm going to create
an empty game object and move it upwards, and this empty game object has a y axis facing up, and
this is what I want. I'm going to put our circle turret to be the child
of the game object. Under circle tre, I'm
going to delete our to rotate and I'm going to rotate the parent object,
which is this one. And just name this
upper part, start. And let's rotate this maybe
around 45 degrees per second, and I'm going to make sure
this is endless and I want to make sure that the
rotation starts from start. Let's play this. There you go. As you can see that we have
a object that is rotating. Now we can mix this with
I'm sorry, shoot script. For example, I can create
empty game object. I'm going to name
the shooter objects, and we can create empty again. I'm going to change this
view from the top view here, so to make it easier to lay out. I'm going to put
the first one here. I want to align the z axis
to this surface here, I'm going to put
it by 25 degrees. Let's add a auto shooter script, and we can use a profile. Let's create a new profile. This is the player. Let's just duplicate
this and rename this enemy or we can just
rename this circle turret. And change the speed
to a lower value, maybe 15 and damage
one and fire rate. I want to I want to make the turret to fire
for a certain rate. So it will fire for every 0.2 second and it will have
interval of 4 seconds. It will stop for 4 seconds
and then shoot again. Whenever it's shooting,
I want to set to shoot maybe five bullets
and I don't want to spread, so set the spread to zero, and we can set the destroy
to two, it's okay. Now we can use this profile
or I will shoot profile. And for the bullet prefs, we can try to use the my bullet first here for the fire point, I'm going to leave this empty because we want
to use this transform. Then I'm going to duplicate
this game object, and I'm going to rotate this
by 50 and put it here 50, but I think it
should be more 65. It means that we are adding 40, I'm going to just
to add 40 again. Something like that align
it manually if you want to. We can copy it again here. And line to the
surface. Copy again. Copy this again and rotate this and copy it again and one
more to go after this one, then we are set with the enemy. Okay. Now we have eight game object. And I want to make
sure that line, it's line properly
on the y plane here. Okay. Now I'm going to save the scene, and I've parent all of the shooter on a single
game object purposely, so we can disable
this object whenever we need you and can enable
whenever we need you. Now let's play this
and there you go. And after 4 seconds, it will start shoot again
and it will shoot 55 bullets with an interval of 0.2 seconds and
it will stop for 4 seconds and it will
continuously do that. With this multiple
script component system, you can create any
behavior that you want to for your enemy,
it's quite versatile. Next, we are going to create another script regarding
the transform script. To two for this video.
20. 20 Look at Player: Okay. So now we are
going to create a turret that are
looking to the player. The turret that will follow
the position of the player, some sort of pencil turrets, and let's just disable
our round turret here. Now we have disabled
our round turret, and let's go to
our models folder and we have a Where is it? At a object. I'm going to put it
this in the middle. Here, as you can see, we have two different kinds
of a shooter part of the tht. We are going to use this
one for the missile threat. I'm going to use to expand this. I'm going to select this
one and I'm going to delete this thredF there, missile, I'm going to duplicate
this object here, I'm going to flip the x scale to negative 100 and I'm going to move this
to the side here. Something like that. We can just copy
the position value here and paste it
with a negative sign. It aligns. Okay. Now we are going to set
a couple of things. First, I'm going to create
an anti game object, and this will be the upper
part for the upper part, I'm going to move to this
position on the y axis. Then I'm going to
set the upper body, the missile to be the chart of this game
object here. Okay. And now we can just
create the script first. Let's go to our scripts
folder and the transform. I'm going to create a new script that I'm going to
look at the player. So we can just rename this
look at player for the script. Let's open this up. Now, where is it. I need to open it again. Now we are going to declare some variables on top
here inside the class, I'm going to just to paste
we got that code here. This is are the variables
that we are going to use. This is the rotating speed. How fast our thread will
follow the player in terms of rotating speed and
the other variable is a private variable, which is the player reference, but it's not the game object. It's a transform and also a vector tree
for the direction. We are going to
store our direction inside this vector here. Inside start function or method, we can just type player, and we are going to
find the player using its tax se a game object class and we can use its method called find game object with
tag we can put tag here player since this
return a game object, we need to access its transform, so we can just use transform. Okay. With this, we found our
player transform and we store it to the
transform variable, this one here, and we can
use this inside the update. First, inside update,
we want to make sure if the player is not, then we want to do the
coding here, at function. Otherwise, if the
player is destroyed, then we want to stop looking at. We can just use the direction or look there and here we can get the player that position and substract it
with our current position. And whenever you subscribe
to different position, we will get a factor directing to this position
here the first position. So whenever we substrate the player position with
our transfer position, then we are going to
get the direction from the position of the holder of the script to the
player position. But since the y value could be on a different
plane on a different level. I'm going to reset
the y value to zero. So I'm going to make sure that the rotations only follow
the x and z plane position. Otherwise, if we didn't
do this line here, then it might rotate
a bit upwards, looking at the player
and we don't want that. Once we have this,
we can just rotate using the transform rotation, and we can use the
quaternar rotated, using rotate towards from we are going to use its
current rotation. And since this is a vector, then I'm going to use
a quaternion class. Inside this quateron class, we have a loc rotation. Crotation basically is asking
for a vector direction. We can use this
direction right away. We can use this rotate speed as our mix degrees lta
type rotate speed. As always, we need to
multiply this by time delta time since the code
is running every frame. And let's save this out. We can actually, we can use tod or we can use
the car function. I'm going to use the c
one and save this again. Let's go back to the unity. How do we set up this enemy? We can put the look at player
on the upper body part and I purposely create
a new tam object. We have a orientation that's
aligned with our world here. The y axis should be pointing
up like the y on the world. For the shooter,
we can just create a new tam object and put it
here, put it around here. And we can just add
an auto rotate, but auto shooter and
let's create a profile. I'm going to create a
new weapon profile. This is going to be a missile
with only one amount, and it maybe has
interval for every sec. This way we can easily select
our profile by its name. Here, we can change
speed to a low value. Let's say five or ten. I'm going to just
to make it ten. For the damage, we
can make this quite big and the fire rate
is going to be zero, but the interval is
going to be two, and it will have a
destroy rate of also two maybe and spread to
zero and amount to one. So do go back to
our shooter here, missile shooter and put the missile profile for the pullet preap we need to create a new preap
Let's just do that. I'm going to go to
the models folder and drag our missile
to the scene here, and let's just reset
its value first. Somehow the rotation is wrong, so I'm going to
rotate this again, but I'm going to rotate
to the other direction, and I'm going to create
a new antigam object. That faces forward like this. I'm going to set the miss to this child of the
gave object here. I'm going to zero out the
value and rotate this to our forward aligns with the forward axis of
our parent gave object. We are going to add a
capsule collider and set the direction
to the z axis and set the rates to a very
small value like 0.5. 0.7, and the height to be 0.5 like this and make
sure it's trigger is checked and I'm going
to add a rigid body, but we are going to make sure that our weapons behave
just like our bullets, so we are going to
uncheck the use gravity. So check use gravity
and call this missile. Okay. And we are going
to create the script. I'm going to direct this
as a prefabs first. Make sure you drab the
parent game object. Save this let's go
to our script here. Now we have this upper part, and we have also the shooter and I'm going to disable
the shooter first, and let's save this
and let's try it. But in order to try
this at script, we need to enable our player and make sure that we have set our player our player tag to player I'm going
to make sure we do that. And for the turret, I'm going to change the layer to
the ground object. And for the missile,
I'm going to change the layer
to the air object. I'm going to apply
these prefeps here. Let's just delete
our missile first. Save this and let's
play this. Okay. Okay. Now as you can see
here. It's quite small. I'm going to make
this bigger, maximize out. But there you go. As you can see, the turret is always looking
forward to the player. Now, let's create
the missile script. We already prepared
our prefep here. Let's put it on the scene.
Here, under the prep, we have a flame smoke here. Let's add this as a chart
of the game object. We have flame but
this is very big. Let's just create
some adjustment for this game object here. I'm going to reset its value. Right now, it's moving that way, so we are going to rotate
to the other direction. Should be 180, and I'm going to delete our point light here, and forming floe flame smoke. Let's move this to the
back to where the end of our miscel we are going to change a couple
of settings over here. So under shape, we are
going to make sure that the radius is a very
small v. Let's add this 20. And for the start size, I'm going to change this also
to a small value 0.120 0.3, let's say, see if it's working. Now our smoke is small, but the fire is still big, so Let's just change the flame here and set this to a
slightly bigger 0.2 to 0.4. For the emission
emission, sorry. For the shape, I'm going to set this radius to a
small value also, zero, the angle, I'm going to make this also very
low around seven. We have a straight rockets and make this also a small
value nine, for example. I'm going to lower
the lifetime also maybe 2.1 Yeah,
something like that. I'm going to change
the start speed to a very small value, 0.1. So it's very slow like this. And for the flame, let's
just change the start speed also to a very slow
value like this. But we want to change the
simulation space to world. So it will create
some trail movement whenever our missile is moving. Flame smoke, we also want to change the simulation
space to world. Save this and go to the p most parent of the missile give object
here, and press apply. And now let's go to
the scripts folder, and under weapons, let's
create a missile move script. So missile move, and
let's open this up. Okay. Now we have
this missile move, and we need to create
a couple of variables. So I'm going to paste this. Variable that I've
already prepared. Basically, this is
the rotating speed. Since the missile is going to rotate
following the player. We need to declare this out and dis missile here will derive
from our bullet move. So it will the speed
and not the rigid body, but the speed speed. But we need also to
inherit the rigid body. So let's just set
this to protect it. Virtual or just protected should be enough
protected rigid body, and under Miss Move, I can declare the rigid body. We can use the MRB
and as you can see, we have this variable available, although we didn't
write it since because the script is derived
from this bullet move. So we can just get component. Rigid body, like
this. Save this. We want also to declare
our physics timestep. Since we are going to use a
co routine in this script. Unlike the bullet
and we are using fixed update and for
the missile movement, we are using a co routine, we want to create
some delay that has the same amount in seconds
with our physics timestep. We just create a new
weight for seconds. Here we are going to type
fix Delta time, like this. This is the time step.
Let's change this away. And inside start, we're going to create a new start
for the start here, we are going to grab the player and using the same
method as before, we are going to use the fine
game object with tag and put the tag player inside the parentheses and we are
going to grab its transform, we are going to
delete the update S we want to create
a new enumerator, which is a routine, and let's just give it a
name of start follow. Here we are going
to at a argument, and I'm going to call
this follow duration, and we are going to set while follow duration
is greater than zero, then we want to do the follow. Otherwise, it will
just move forwards. Here, and outside this, I'm going to yield return
physics time step. Whenever the follow ation
is greater than zero, we are going to
substract this with our time fix delta time. This will be substract one by one and every second.
It's like a countdown. This should be inside our while. I'm going to cut this here. Here, we are going to make sure if the player is not null, if there is a player, then we want to
get its rotation, its direction and apply our missile rotation
to face the player. Let's just create a
temporary variable p three. This is going to be direction. Let's grab our player
that position, substract it with our
transform that position, and we can rotate
this missile by using the transform rotation and using the quaternion s For
the first rotation, we just put our rotation, just like the look
at script before. For the second rotation, we can use the quaternion and it's method called rotation, and let's put the
direction inside this parents for the
rotate speed here, we already prepared this,
type rotate speed multiply. But since this is
running at a delta time, which is this physi time step. Basically, this co
rooted is emulating our fixed update because we want to execute the code
every physic time step. We need to multiply this
by time fixed delta time. Okay. So once we have this. Now, we need to
move the the sorry, the missile. So we can just. Move it like this. Sorry city but
MRB, the velocity, and this should be the pratform forward of our missile
multiply by the speed value. If you're wondering, we haven't declared any
speed variable over here, but we have this
accessible because we are miss script from the bullet move script and
inside our bullet move, we have this public
speed variable and the protected rigid body. Whenever we use a public
or protected variable, then that variable
will be available to the derived class that
deriving from this class here. Okay. Now, as you can see here, we have this script,
I'm going to save this. But this rooting is
never get started, so we are going to
start this enable. Since we are using
pulling and we want to enable and
disable the game objects. So whenever the
missiles gets enable, we want to start
the movement again. And we don't use ontart start routine and run the
function, start flow. We are going to
create a variable that will hold the
follow duration. Just type comma here and follow duration and set
this value to one first. It will only follow the player
for 1 second and after it, it will only fly straight
away to the last direction. The missile is facing and copy this variable and
put it inside this here. That should do script. Let's try this and under
our missile game object, select the parent
missile game object. Let's add our missile
move here for speed, let's set its value. Just leave the
value here, because the speed we'll get passed by the shooter script here using the speed from
our profile here. Save this out and I'm going to delete this prefept here and the missile shooter, I'm going to add our prefep. Goo to the prefix folder
weapon and g the missile as a bullet prefpt if we see
this, we have a speed here. Let's check our o shoot script. Whenever we are shooting, do we set the speed? I'm not quite sure here. We are shooting. We need to set the speed here. Let's just grab its component, and grab the bullet move. And this is why we are
inheriting from move. We want to search only for the
bullet move and we want to set its speed value
to our shoot profile, speed here, something like this. We can change the speed of our bullet move here
using our profile. With different profile, we can have different bullet speed. For example, this one is
running at 50 units per second, and for the missiles is only running ten units per second. For the player it's running
30 units per second. Now this variable
this variable speed on the bullet moove
will get changed by the auto shoot script. Also the missile here. The speed will get changed. And if you're wondering, we are only searching for the script that has
bullet move component, bullet moove class here. But remember that missile move is derived from the
bullet moove class and the sorry where is
the speed variable, basically is based on the
bullet moof script, and Missile Move will have
all of the B variables. So whenever this script
code is running, then it will apply to our bulame object as well
as the missile game object. Okay. Let's try this. Is it shooting? Not yet. Somehow. There is an issue? Sorry, I forgot. Okay. I found the issues here,
just rename this. Okay. I thought it was the
file name issues, but it was basically
script issues over here. I apologize. Here, as you can see on
our auto shoot script, we only want you shoot whenever the shoot profile amount
is greater than zero. And this is wrong. This should be greater
or equal zero. Basically, we don't need we don't
need this line actually. So let's just delete this. And I'm going to push this back. Save the script and let's
see if it's working now. So, this is our
missile script over here and I'm going to direct
this back to our upper part. Okay. So I'm going
to save the scene, and let's try this again. There you go. We have a missile that follows our player only 1 second
and then goes straight, and it is shooting
every two second to make a better particle,
we need to fix it. Let's just go to our prefab
weapons and under missile. Let's fix our particle here. The flame smoke. We are going to
shorten our lifetime to a very short
value, maybe 0.8, for the flame also to 0.5 Okay. And we want to change its
emission to a bigger value. Maybe 35 should do the trick, and also for the flame smoke go to our emission and increase the value to 35,
let's press apply. So we will have a
much denser particle. There you go. Okay. Now it's shooting
missile every 2 seconds, which is quite intense, but we can fix this by
adjusting the weapon profiles. If you want to shoot two different Missile
from each side, we can just duplicate
this Missile suitor and push this site here somewhere like this and
change the profile first, not every 2 seconds, but
maybe every 6 seconds, and we can just rename
this interval 6 seconds. We know the characteristic
of this profile here. Let's save this and
let's try this again. The It's shooting two
missiles at the same time, but it waits for 6 seconds
and then shoot another one. Okay. This should do
our missile turn. Okay.
21. 21 World Moving: Okay. So now we are going to create another script for transform, and this is going
to be a local move. Let's just create a script, and let's call this or we
can just call this to move. And let's open the script. Basically, this is for moving stuff relative to its parent. Let's create a couple variables needed to build the script, and I'm going to paste a couple variable that
I've already prepared. Here, I'm going to
explain one by one. Basically, this is factor
the offset of our movement, the target the target position. And we have a two bullion
variables, which is on start, and this is for enabling the
movement from the start, or if we want to trigger the movement from
another script, we can just disable
this on start options. And reverse is for moving
on the reverse direction. The duration is how long does the movement will
take long in seconds. For the unity event, we can create should
be on start move. We can trigger another action from another script
via inspector using this unit event and we can enable whenever
we start moving, just put it inside
on start move. Or if we want to trigger the action when the
movement is plan, and we can use the
unmoved done here. Since this requires a library
from the unity event, so I'm going to type
on top here using Unity engine events and this should make the unity event class available right now. And we have two entries
of private variable, and the first one
is vector tree, and this is going
to be the holder of our target position and also the holder for
our initial position. And this is going to be the movement distance from our initial position to
the target position. So we can calculate the distance
using from the duration. Basically, we are going
to remove our update past and we are going
to use a co routine. Type enumerator, let's just call the
coroutine start move. We are going to need a
couple of variables. First, we are going to check
for the reverse options, and the other one
is the duration. Let's just type float time. So first, we're
going to check if the reverse option is true, then we are going to set our target position to
our initial position. If the reverse option is false, then we are going to set
the target position to be our carn transform
the local position, added with our move offset here. Our current position
added with the move offset that we get
our target position. And here we want to invoke
the star move unity event. Type just unity event invoke. Here we're going to
create a wild loop and we're going to check if our transform local position is not the same as our
target position. Then we want to move our
local position to be vector move towards our
carbon local position to our target position. For the max distance Delta, we are going to use
our move distance. Divided by our duration
or our time here, and we are going
to put this inside a parenthese then we are going to multiply
this by our time. I'm going to enter this line here so we can see
it more clearly. After that, we are going to look the code here by
using return no. Basically, we are telling
that whenever this is true, then we're going to
look this code here, and if this falls, we are going to skip the code
and we are going to invoke our move
the unity event. We can invoke
another method from the inspector using the
unity event variables. Basically, we have this
routine defined declared. Now we are going to create
a couple of method. The first one is going
to be the public move. Here we need also a
reverse function. I not a reverse funtion, we
need a reverse argument, and the type should be
b Inside this function, we can just run our coroutine by typing the start routine and The start to move
function. For the reverse, we are going to pass
this reverse value here. For the time, we are going
to use our variable from this public flow duration on top on the
variable declaration. On start, we need to fill
a couple of variable. The first one would be our
initial cost and this will be our transform local
position from the starting of the game, and for the move distance, this is going to be the
offset the magnitude. The length of our
move offset factor. Here we are going to execute our quotin If the start is true, then we are going
to run the move, but with our reverse pass
inside this function here. So whenever we design when
we use the script here. If we enable the
reverse bullion, then it will get past through
this function here and it will set the
movement in reverse. Let's save the script here. Let's test this out by perhaps I'm going
to disable the first, and let's just create new three dig object and I'm going to put the y
axis on the zero plate here. I'm going to duplicate the cube, and let's scale the second one, make it smaller, but like this. We can add theo move script
to this child object here, maybe we can move the
zx to a negative one. And set the start bulon here and type the duration
to 2 seconds, 2 seconds. Let's play this and
see if it is moving. There you go. It's moving, and then stop after it reach the offset that
we defined here. This will be very useful
for later if we want to create weapons on our
bus enemy, for example. Once we destroy
the first weapon, then we can move the second weapon to make it
like a mechanical movement, the bus will activate
the second weapon, and we're going to
set up this later. So let's test this out if we can use the reverse function. The reverse should work. The target is the initial pause. We need to fix this up. Target would be initial
p and then after that, the initial push ourse save this Okay. Oh, sorry. We can just make like this. The target local
position we move by itset we are offsetting
the local position. If it's reverse, then they should do the trick.
Let's just try this. Then if we play this, the small boxes should be
negative one on the z axis, and it moves slowly inwards
to the parent object. Let's see if it's
working. There you go. The movement is in reverse. But if we disable the reverse, then it will move normally. That should do with our tomove
22. 22 Designing Boss: Okay. Now, we are going to
design our bus movement, but our bus game object. I'm going to delete this
cube here that we have and I'm going to go to our models folder inside the model folder, we have this bus ship and we are going to
track this ship. This is our ship, and I'm going to rename
a couple of things. This is the ship. Let's rotate this 190 degrees on the y axis. It's facing our ship. It's going to be the
threat for the threat were going to also rotate this
190 degrees on the y axis. Okay. So we're going to
set up the bus ship first. Let's say this is
the first weapon, and I'm going to put on the
negative 1.4 on the x axis, and I'm going to duplicate this, and I'm going to put it
on 1.4 on the y axis. So it's irrod on the y position, and move both of these
threads to the front so we can see from
the top view here. And I'm going to create an empty game object and
let's call this first thread. I'm going to put
both of the thread inside this child game object. This first thread will have a box cider and it's going
to be box collider actually. I see it from the front here. I'm going to move this box collider. I'm going
to set this up. Okay. And I'm going to
make it big like this. So if we are shooting the bus andmy we're going
to make sure that our bullet is
hitting the turret. Like this, I'm going to enable its trigger
and I'm going to copy the component and paste this component values and
component values new component. I'm going to set this to a
positive value on the x axis. We have another glider that
covers the second tht here. We are going to add health system of we need
to also add that system. And I'm going to save
the s first here. So, we already set up
the first turret here. Now, we are going to create a couple more of antigve object. Let's just I'm going to rename this first Turret
for the second one, it's going to be tore
this is there left, this is the first
tore or can make it. It's easier to see that
this is the first one. Let's create an ant gave object and We want to point forward to the
front of the toured here. Let's just rotate
this on the x axis. I'm holding control, so it
snaps every 15 degrees. I want to rotate it to a
90 degree on the x axis. If we select the move gizmo, we can see here that forward is facing the same way
as our tore forward. Let's move this here, and this is going
to be the shooter. And we want you to plicate this shooter
here and I'm going to direct this to be the
child of the other threat. Let's zero out our position, so it aligns with its parent. For the shooter, we
can select both of this empty game object and
let's create an auto shoot. And we can see our
weapon profile, and let's create another
shooting profile, and let's name this bus first. Here, we can just
set some value. Let's set the speed to 15 and the damage to one
for the fire rate, we are going to set
a fire rate of 0.1, and it will have an interval
of let's say 4 seconds, and we want to destroy the bullet say 3
seconds or 2.5 seconds. After it gets
staniated the spread, I'm going to leave this
to zero for the amount, I want to set this to six. Every time the first
so the bullet, it will shoot six bullet
with a rate of 0.1, and then it will
pass for 4 seconds as in this value here
in the interval. And for the shooter, we select both of the shooter and we can drag this
weapon profile, put it on the shoot profile. And for the bullet
prefab, I'm going to choose our enemy bullet. So go to a set tab and
choose the enemy bullet. And for the fire point, I'm going to leave
it to, so it will pick the shoot transform. Okay. Let's set
the health to 25. I've already prepared effects. Sorry. I think we need to make it,
so let's just create it. So first, we are going to create a canvas to show the
health of our thread here. Let's just create
a new UI canvas. And this canvas, we are
going to change this to a world space and we
can pick our camera. But since we are not
using the event, we are not using this
UI or canvas for touch or for interaction. We don't need to
fill the camera. I'm going to make this size
around maybe 200 by 125. I'm going to zero
out its position, the xn I'm going to rotate
the rotation to 90 degrees. And now we have this world
canvas, and that is too big. We are going to scale
the scale 1-00 0.05, I'm going to scale
this on the axis or I think I'm going to make
this smaller even smaller. Then I'm going to put
this canvas on top here. Let's just rename this
to health Canvas. And we are going
to create a image, and this is going to
be our health bar. But this is the background. For the background,
we are going to set its value to around 75 and the run 20 maybe or less
ten should be enough. As long we can see,
we can see the bar, but I think this
is still too big so I'm going to make it smaller. Maybe five or five. We don't need this
canvas to be so big, so we can just kill it again. Like this and now
we can make this bigger 75 by five
should be enough. Basically we can change the
color to maybe gra color, and let's duplicate
this and this will be the health bar
d this health bar. For the head bar, we're going to use the initial
image from the image. We are not going to use
sprite for a while. Let's change this to red. For the child, I'm going
to change its center to the left and also its pivot. Whenever we scale
this value here, it will hold it pivot
on the right side. Okay. Let's save this. I'm going to create a new folder under
prefabs let's call this UI. I'm going to drag
this health canvas as a prefab if we need
a new health canvas, we can just drag it from
our prefabs here. Okay. Okay. So now I'm going to open our health system again
and you see the code of. Since we are using
the scale here, we can just drag our
health game object as our health bar here. Just drag our health bar and
put it as the health bar, and this will update whenever this value gets substracted
or whenever it gets hit, then the health bar
will decrease here. For the effect, we can
just grab our sparks from the assets. Going
to say the scene. Now we have this first
turret over here, and we need to create a
couple of explosions. So I'm going to select
this red R and turret L, and let's create object script, and we are going to
create an explosion. Here, this explosion. I think
we are going to destroy it after 2.5 seconds after the explosion is instantiated
for 2.5 seconds. Here inside the first to red, we can just spawn an object. But we don't want
to destroy this, so let's just disable destroy options for
the spawn object, we are going to
drag our first to red to the spawn object variable, and also
the second one. Now, basically, if we play this, we can see that we are
shooting the threat there and you can see that the health bar
is decreasing here. Quite small let me
make this bigger. Yeah. There you go. Okay. And it is shooting six
bullet every 4 seconds. Okay. Now, let's create
the second turret. Since we already have
the first red here, we can just modify this. I'm going to duplicate all of the first ret group here
by pressing Control D, and for the second, we are
going to rename this first. I'm going to add a
missile under the name, and we are going to
move the turret here. Let's just move the turret
to -2.7 here. Okay. And I'm going to lower the
y position to around 0.1, and I'm going to
move the z position to around this
position over here. For the second one, I'm going
to copy its value here, transform, and I'm going
to paste the value. But I'm going to set this
to a positive 2.7 here. I'm going to just to
remove the negative sign and it will get mirrored
to the other side. For the second to, we
can just leave settings here and just make sure that the canvas the health bar is actually pointing
to this one, the second one here,
so just change it. And for the shooter, we are
going to change its profile. So let's go to weapon profiles, and I'm going to duplicate
the bus turret here, but I'm going to rename the
profile to a missile turret. And we are going to only shoot every let's
say every 3 seconds, but just set the
fire right to zero, but we are going to
increase its damage because this is
basically a missile. So it should do greater damage
than the normal blaster. And for the speed,
set it to eight, for the amount, I'm
going to set this 21. We can change this
value if it becomes too easy to fight the bus later. For the second missile shooter, just direct the
missile treat here, and we can change the bullet to the missile here Save this. We are going to disable the second before we disable this, I'm going to move this to
one unit behind like that. So we can apply to move script, and we can move the y axis since we are
on a local transform, so we want to move the y
axis to a negative one. Put here negative one and enable on start
for the duration, we can set this
maybe 1.5 second. Okay. And here,
I'm going to make sure that we are referencing the tot inside this group here, and we want to disable this one. Save this. Now, we need to create
a couple of event. Whenever we destroy
the first toured, we want to enable
the second tot. We can just use the
death system here and add an event inside on
death event and drag our parent group object for the second tore and
drag to the object slot here and go to the
game object and we can choose the set active
function and set it to true. Whenever we succeeded
in destroying the first tret we want to enable the second turret.
Okay. Let's save this. I'm going to create a new
player profile level here. Change the speed to 25 and
damage to one is okay. But I want to lower
the interval to 0.25 and spread to three and the amount to I think three should be good. Save this. I'm going to use the
second profile here, direct the second player
shoot profile here, save this, it's easier
to try this out. There you go. I want to
destroy this. There you go. Oh, there is some
issue actually. Somehow it's still shooting. We already disable basically already destroy the first rate we need to disable
the shooter here. I'm going to add show event and direct the shooter game object
to the first one and also the second one
to the second slot here and also use the game object set active and we are going
to disable this. This will make the object to be game object and
we need to this. Okay. Whenever we succeeded
in destroying this one, we need to also do that. Let's just drag this
object, shooter. Object and stative falls, objective also to fall. I think there is an issue here. The movement somehow Let's
try this on the z axis. Let's try this again.
Sorry. Okay. There you go. You can see that once we
succeeded in destroying the first The first turret, we are enabling the second one. But there is still
some issue, actually. We need to make
sure that whenever the second turret is enabled, it's not going to shoot missile rightway we need
to disable the shooter. Here, when we move each
of the game object, we want to enable when
the move is done, so we can use the move
done event here and drag the shooter and we can
just enable this like this, for the second one, we
can just do that also. Like that. But I'm
going to increase the z value a bit so we
can see better the turret. For the health canvas, we want to move this to
a different position. So it doesn't show on top of the same position of
the first canvas, let's disable all of this here. I'm going to stop this
and under the game, I'm going to maximize on play
so we can see it better. That we can try to
destroy and destroy, it will show a new turret. But our collider is still
on the same position as the old but the first.
Let's just fix that. Basically, we need to move to the same
position of this one. Move its center to negative
2.7 align with our turret. For the second one, we are
going to change it to 2.7. And I think that
we can just move the z axis a bit to backwards. So maybe around 0.25, and value same here. Okay. And maybe we can just
disable the boxer first, so we can shoot it right away, and under our turret we can add new event for the R, the right, we can just drag the collide to to enable the lid how do
we do that actually. I'm going to drag second
tret missile here, it only reads one
of the totes Div. And enable this from
start. It should be okay. Later, we are going to add more explosions and also sounds. Sorry. We need to disable
the second to first. Let's just try to destroy this
one and it's get exploded, and the second one, we
can just destroy this. Now, let's continue
build our bus here. We have the first
tout and we can increase our max health later if it's two easy after
the second tout, we want to try to destroy
the bus ship here. For the bus ship, let's
add a box collider. And let's just increase
the size to maybe 1.5, and also maybe two under y axis, move on the y a bit and
scale under z x, y. We have a so we can
start hitting the bus, but we want to disable
the bus collidor from the start and add a health system
and also death system. We also need the health bar, so I'm going to go to
our prefab UI folder and dg the health f to be our child of the bus ship here and move maybe around
this position here. I'm going to disable the
health canvas first. Put it on top below the
ship game object here. For the shape object that
has the health system. I'm going to direct the
health bar, for the effect, I'm going to use the
same sparks particle that I've already provided. Yeah, we want to
make sure this is an enemy. We don't
want to destroy. And we want to add another
rotate, rotate script. And we want to use the
targeted rotation. We want to rotate on the z axis a bit around 20 degrees
and for the speed, maybe set this 25 here. We want to disable
the outo rotate. But on that event, we want to enable
this auto rotate. Direct the script to
the slot here and just choose the bull enable and just enable the auto rotate. We also want to
create a couple of explosion whenever the
bus ship is defeated, create a new antigam
object called this effect. For the bus ship, we want to
set the max maybe 25 first, we can change this
later for the effects. I'm going to create
antigam object again. This is basically our
explosion holder. I'm going to put
one explosion here. Okay. And I'm going to add a create object and choose
explosion from our assets. Yeah. So just start
this explosion and duplicate this a
couple of times and change position on each
of the game object. Okay. And I'm going to
add a flames object. But for the flame, I'm going to create
another empty gate object. And then I'm going to go
to our pre fax folder and direct the flame
smoke game object to our flames here. So, something like that, and change the
platform to global, so I can move it easily to
the position that I want to the flames to be and I
want to duplicate also the flame a couple
of times here. Put one here and another one
to this side here, maybe. Yeah. And we want you
to disable the flames. And we want to leave the
explosion activated, since this is a create
object and under the bus shape whenever we
destroy defeat the bus, we want to spun
discrete object here. I'm going to lock
this inspector, so we'll keep the inspector focused on the bus shape object, and I'm going to select all of the explosion here
and drag this to our span object slots and it will fill this
up automatically. It will spawn object with create object script refer
to this game object here, and we can release
the lock here. Yes. Enable this,
and I think that. But we need to enable
this box calder. Let's go to our
second tt missile and whenever we defeat
the second missile, we want to enable the box cider. D the best ship game object. For the box coder, we are
going to use the bull enabled, and we are going to enable
this component here. Save your scene often, and let's try this again. Now we are going to
try to destroy this. It's enable the second
one of the missile. Once we destroy the
missile, we can Okay. But the rotation somehow. There is an error actually
here. Let's check this. Which one is script game object. I'm going to check the
explosion have a script. Let's just remove this script here under explosion
and apply this. I think that is the audio script and we are going to
create that later. Okay. Let's try this again. There is one thing
we forgot here. Whenever the second
turret gets destroyed, we are enabling the bus coder, but we also need to
enable the canvas here. Let's just do that and drag this canvas and
enable the game object. Let's try this again. Now we are now we need to destroy
the main shape here. But the rotation is not working. Whenever it gets destroyed, we want to enable, we need to, but we need to enable
the ontart options here or we can just
on enable this, under the auto rotate, we can run the function rotate. So do better. Now, let's try to
destroy this one and destroy the second to
let's try to destroy. We can create these animations
like a falling animation. Now we need to make sure that whenever we defeat the bus ship, let's enable the
flame group here, this flames and been This
will make a burning effect. Okay. Okay. So there you go, we have a nice defeat effect
for the bus here. Okay. And the next thing we need
to do is to create movement. So we are going to do that
on the next video. Okay.
23. 23 Boss Movement: Okay. So let's continue
expanding our bus behavior. And now we need to
create the movement. So just select the
uppermost parent of the bus ship game
object here, this one. And let's add a new component,
the node move component. And as you can see here, we can just enable the loop move and I don't
want to rotate the object. I want to keep the bus ship facing to our ship
here like this. I've disabled the rotate object, and I'm going to
change the banging but I don't think we need
to change since we are disling the rotation
so it will not have an effect on our
bus ship game object. For the speed, I'm
going to first set it to two and increase
later if we need to. Yeah, I'm going to add
a couple of nodes. I'm going to add four nodes. Okay. And I'm going to move the game object and
also the notes. This is the third notes. This is the second,
and this is the first. Basically, I want to
create a looping movement. And the first
position would be in this and the second would be there and make notice that the movement is
basically is going to be the green line. It's not the yellow
line. So make sure you design the movement based
on its green pattern here. Let's create
something like this, or we can just move the fourth to be near
the first node here. The movement is going to be a bit circular or
elliptical like this, let's stretch it Okay. And, we are going to
enable from the first, but later we will need to create adjustment
on the behavior once we put it on our
scene, and let's play this. There you go. We have
a moving bus ship. It's quite nice actually. We need to destroy the
turret it a second turret, which is the missile and we
need to avoid the missile. Now, since we already
destroyed both of the turrets, we need to destroy
the bus enemy. But as you can see here,
after we destroy it, it's still moving,
it looks funny. Now we have this
death system and basically we want to add another event on
the death system on the main parent because this is the last help
that we need to destroy. This is the last sequence of
the death that we need to add and add a new event
and direct the node move. Under the script class here, select the bull enable. And just disabled. Save this let's make
things interesting. We can copy our flames here. I'm going to put this as a
child of our first turret. And I'm going to play
the fire effect, and I'm going to reset
its position like this. It's align with our td. I'm going to disable
this first and duplicate and make the duplicate the child
of the second toured, and I'm going to
zero the x value, it aligns with the second tot, whenever we destroy it, I want to activate those flames. I need to create two entries and the first flame and the second
flame here and set both of this event to the game class here and choose the
set active method and enable this. Yeah. And let's do the same to our second touret over
here. Just duplicate this. Open our touret and
the copy it flame, let's zero all of
the value here. Also for the second
one. And under the death system of the second the missile
toured at two new event, and let's enable this
sorry, flame smoke object. Give object set act to true and the second
one also to here. Give objective to true. So make sure that this flame
is disabled by default. So whenever we activate
the second toured, this won't get activated
automatically. Yeah. Okay. So we have disabled the yeah they have disabled the note move script
here after straight. So let's try this again. Okay. Yeah. You can see there is a nice flame effect
and the second one. But we need to change the world, the fla simulation space world. Let's go to our flame smoke
prefabs here and change the simulation space to
world and go to the flat, also change the simulation
space to world. So do the trick.
Another thing is we are going to need to add a health system to our player. Let's just do that. Health
system and death system. Let's create object, and this is going to
be our explosion whenever we get destroyed, go to the asset and choose
the explosion prefabs. Let's destroy the
explosion after 2.5 seconds and direct create object to the
spawn object here. Yeah. Because the son object is basically is a type of array
of create object instance. On that event, we are going
to leave this to empty. For the hit effect, let's get the spark prefabs The health bar we need
to direct our health bar. Go to the UI, health Canvas and direct this to our player. And zero out exposition, and I'm going to move to
the back of our ship here, expand our health
bear and we can wreck this health part game object to the health part of
our health system. Save this let's increase
the max health to 25. Now we can get hit from
our enemy like this. Whenever we get hit,
there seems to be an issue actually. Yeah. Oh, sorry. Because
it is enabled. So make sure this is disabled, and I'm going to increase our collide size on
the y axis make 1.5, so it's bigger, so
we need to make sure that if the bullet is being
spawned from this position, the bullet will
hit the collider. Let's play this again
and see if it's working. There you go. Decrease. Now whenever we get
hit by its missile, Yeah. And. So there you can see that whenever
we defeat the bus, the bus will stop moving. Okay. So once we set up this, I'm going to set this
buzz game object as a pref I'm going to create a new Ames folder
under this mates folder, I'm going to direct this bo
ship here to be a prefs. So we have this saved. I'm going to set a
couple of things here, but I'm going to change this
on the script, right away. Let's open the hell script. Basically, what we want
to do is to disable the health bar once the
health reaches zero. This is a minor adjustment. So here, whenever
our health is zero, then we are going to hide
our health bar game object. Basically, I'm going
to type health bar and get its transform
first and its parent. Why do we want to
get its parent? Because here, let me just
show you the health bar here, Our health bar is basically
the most child object here. Basically, if we hide this, then the gray background of the health bar
is still shown. We need to access its parent, and then we want
to disable all of the health also the health
bar background object. So we cannot see it
anymore on the game view. That's why we need to access the parent of the game object. Once we get the parent, we need to access its game
object and just type set active two falls and make sure that this is only happens when
the health bar is not now. If we don't assign for example, if we don't assign health bar in this health bar slot here, then this won't run. This is a minor adjustment should change all
of the behavior. Let's just destroy this
gun here. There you go. As you can see, the hear the
first head bar gets hidden. I'm going to try to
defeat myself here. I purposely colliding with
the missile over here. Yeah. I want to
see. There you go. So we can get destroyed. But here, as you
can see, we have an error for the missile move. Basically, I'm sorry, we cannot
find the player anymore. So we need to adjust this. Make sure if we found
the game object player, then we want to assign
it strong form. Like this. Let's
try this once more, but just set our help of our player to be
a very low value. Let's say eight and
clear this error, and let's play this again,
but we need to destroy the first to first. Let's just do that, be careful. We now let's try to get destroyed by the
missile. There you go. We don't have error anymore, so it will just
shoot straight away. Okay. So once we change, I'm not sure that
if we have changed, I don't think we
have changed it. We only change the scripts but just to be on the safe side. Let's press apply. So
it updates our my pre. After this, I think this
concludes with our bus ship, and we can continue
on the other topics.
24. 24 Human Rescue: In this video, let's create
the human rescue feature. And first, let's just
disable the boss shape here. And let's go to the models
further under the project, and let's just add the human
rescue model to the scene. And right now, it doesn't
have any materials. So let's just create a new one. We can expand the human
rescue game object and select the game
object called car, and we can go to the
materials folder here, and we already have
the human materials. We can just direct
that material into the material slot under the skin measure on
the car game object. And as you can see now, it
has a nice looking material. And as you can see
here, the character is quite big compared
to the ship. But if we see that from the
top view, it's not so big. So we can make the character
smaller, actually. But I think if we
make this smaller, it will be too small for the user to notice
and the screen. So I'm going to leave it
to this current size. And now with the human
rescue selected, let's create a box collider, and let's just adjust the
size of the box collider by pressing this edit collider and adjusting on the scene view. And I'm going to change the size on the
inspector here for the x component to two and also on the z component
with the same value of two. And let's increase
the y size here, and we need to make sure that the trigger component option is checked because we are going to use the trigger
event for triggering the human rescue
and let's rotate it 180 degrees on the y axis. So it face the player, And now let's go to
the script folder and inside the gameplay folder, let's create a new
C sharp script. And let's just call the script human rescue and then open it. And inside the human
rescue script, let's just delete the start
and the update method. And here, let's create
the trigger enter method. And we want to also create
the trigger it method. And now we want to
check if the other collider that enters the
trigger has the tag of player, And let's just copy
this statement block and paste it inside the
trigger exit method. And I'm going to also add the
UI namespace here on top. So let's just type using
Unity engine dot UI. So we can use the UI
objects inside the script. And we want to also use the
Unit engine event namespace. And we need to
declare a couple of variables here. So
I'm going to paste. And basically, this is all of the variable that we
need for this script, and the rescue time
will be the time, how long until the
human gets rescue. So we need to stay triggering this human for
5 seconds in this example, but we can change this value. And the image will
be the timer UI. In this case, it will be a circle stroke that will
get filled upon rescuing. So we know how much time
left to rescue this human. And the Unity event
is going to be the event once the
human gets rescued, so we can hook other method to this event whenever a
human gets rescued. Next, we need to
create a coroutine. So I'm going to type numerator, and we can call the
coroutine rescuing. And I'm going to also create
a local method called date UI for updating the TR UI. So now let's work on the
rescuing core routine. And for this core routine, we want to pass a
float variable, and we can just call it time. And here we want to
create a wile loop with condition if time
greater than zero. So as long the time
is greater than zero, then we want to run the
code inside this wile loop. And here, I'm going to add
a return null first to stop execution and to prevent from creating
an infinite loop. And now we can work on the
rescuing code And first, we need to decrease the time and we can use the
time that delta time. So it will decrease using the time that delta
time value every frame, and this will lead to a timer. It will decrease the value
by one on each second, and we are going to run
the update UI method. But we want to pass the time
value on the update UI. So I'm going to add a parameter with type of flout and I'm
going to call it value. And now we can pass
the time value. And if the while is over, then we want to destroy
the game object, so we can write the
method destroy here below and then pass the
game object as an argument, and we can delay by
one or 1.5 second. So it will play the audio first before completely
destroy the human game object. And before we destroy
the game object, let's invoke the n
rescue Unity event so we can hook another
method into it. And here we want to work
on the update UI method. So first, we need to check
if the timer UI is not new, then we want to
execute some code. This will make sure
that if the timer UI is null or doesn't
have any sprites, then it will skip the code, and it will prevent
from any errors. And here we want to create a temporary variable and
we can call it time. And we can pass on a time value. We can pass the value
divided by the rescue time. So we will have a
normalized value. And for the sake of clearness. Let's just change
the parameter name into time and the temporary
variable into value. And for the value that are going to be assigned
to the value variable, we can just set it to time divided by rescue
time. So it's clearer. So basically what we are doing here is that we are
passing the time value that gets modified
every frame by subtracting with the
value of time Delta time, and we pass this time into
the update UI method. And we need to normalize this
time value into 021 or 120, depending on the direction
of the countdown. So basically, we need to divide the value of time with the
maximum value of the time, which is the rescue time here. So this will return
as a value 1-0. So we can use that
float value as a percentage progress for
the time or UI fill amount. But instead of counting 1-20, we want to inverse this value, so we need to add a float value of one in front of it and then subtract this float value with the time divided by
the rescue time. So we will have the inverted
value, which is 0-1. And now we can use this value to update the timer UI fill amount. So let's just type timer
UI dot fill amount and then assign the value into
this fill amount variable. And now we need to
run the coroutine whenever the player
enters the human rescue, but we need to
stop the coroutine whenever the player exit. So basically, we can just add a start co routine method and then pass the
co routine name, which is rescuing and this rescuing co routine as
for a float parameter. So we can just pass
the rescue time as an argument for this
co routine here. And when the player
exit the human rescue, we can just stop all
co routines method, and this will make
sure that it will stop any previous running co routine, and then we need to also reset the timer I feel amount to zero. This will reset the timer
visual back to zero. I think this should do, and let's just give it a try. And now let's set up the
human rescue game object, and let's add the
human rescue component into the human
rescue game object. And for the timer UI, we need to create a Canvas and I've already provided
the prefabs for it, so we can just go to the pref
folder under the UI folder. Let's just direct the health canvas into the human rescue, and we are going to
modify this Canvas. Instead, using the
horizontal bar here, I'm going to change
the health bar here using a circle image. So let's just select
the health bar. And we can just delete
the health bar, and let's just use the
health bar background. And I'm going to rename this
game object to circle bar. And I'm going to assign a circle bar sprite into the source image of
the image component. And we can set the size of the rec transform with
and height both to 80, and I'm going to change
the color to red, and we can change the
image type to field. And for the field method, we can just leave
it to radial 360. And as you can see here,
we have fill amount, and we can scrub this
properties 0-1 to create a crop silker from
non to a full circle, and the script will modify
this value whenever the ship starts to rescue
the human game object. And let's just set the fill
amount default value to zero, so it's invincible on start. And let's just direct the
circle bar game object into the timer UI slot here under the human
rescue component. And later, we can use this unrescued event to play the sound whenever we
finish rescuing the human. Or we can just do that now, let's just add an
audio source component into the human
rescue game object. And let's add the human rescue
sound into the audio clip, and we need to disable play
on wake to make sure it's not going to get played
whenever the scene start. And we can add an entry
to the unrescue event here and then drag the audio source into
the object slot here. And under the
function hook here, we can just select
the audio source and we can run the play method. Or we can just execute
the play one shot method, and we don't need to sign the audio clip here
in the audio source. But instead, we can assign the audio clip on
the Unity event. And now let's give it a try. And here, as you can see here, if we move the ship and then hovers onto the human,
it starts rescuing. But if we leave the human
and it will stop the timer, and whenever we enters it again, it will reset the
timer from zero. And if we stay and try
to rescue the human. After finish rescuing, it
will wait for a while, play the sound, and then it will destroy the human game object. Hi, this is Rom in
from the future, and we need to create a slight modification on the
human rescue game object. So in order to fix this, let's go to the prefabs folder, and under the friendlies, we can just double click on the human rescue and it
will open the prefabs mode. And if you are still using
the older Unity version, you can always drag the human rescue game object
into the scene and then make changes and then apply the changes
on the prefabs. So the changes that we need to create is the
health canvas here. So basically, we need to
remove this graphic caster. Otherwise, if we have
this component here, whenever we are rescuing
the human rescue, it will slow down or it will
activate the bullet time because the bullet
time will gets activated whenever there
is no touch at all, or there is a touch
on top of a UI. So if we have this
graphic caster, it will register the
touch on top of a UI, and this will cause issue. So I'm going to right click
on this component here, and then just press
remove component, and I'm going to go back
to the scene in here, and this should fix the issue. So that concludes this lessons on creating the human rescue, and we can continue
to the next video.
25. 25 Finishing Pooling System: In this video, we
are going to start working on the pulling
manager system. First, let's open the
pulling manager script. And the basic concept of the pulling manager
is that we want to instantiate the object
that we are using often, such as a bullet hit
effects, or explosion, and then we want to
instantiate those objects on the start or on the
beginning of the level. And we want to instantiate for a couple amount or a couple
copy of the objects. So we can reuse those
objects and activate those objects and
then deactivate it when we are not
using it anymore. This way, we will
save CPU cycles, especially on mobile device. So it's really recommend
that we are using the pulling system for object that are being used repeatedly. And we are going to use a Q, which is a collection type
like an array or a list, but it is more efficient
compared to list. And how does the Q work? Let me show you
So with Q system, we can get the member from
the first of the order, we cannot get any
member using ID. We can only get the first one. And whenever we put an
object back to the Q, it will going to
be the last one. It's like a Q system, and it is last in, first out. So here, I have a
illustration of how Q works. So, for example, if
we have four objects, that are inserted to a Q, and whenever we want to retrieve an object
from this queue, it will automatically
retrieve the first one. Whenever we try to
the que an object, it will return the first
object in the queue, and we can get this by using the Q command from the Q object. Whenever we put another new
object to this que here, we are going to insert
this object to the less of the order in this que. And we can use the
NQ command for this. And compared to this, Q
performs much better. So this makes a Q object quite useful or one of the best
solution for polling system. Now, let's head back to unity, and let's open the polling
manager script again. So let's create a
new custom class for holding the p data
or the object data. And let's just type public class here outside
the pulling manager class. And we can call it pull item. And we don't want this class to inherit from mono behavior. We want to make this
as a custom class. And I'm going to add a
serializable attribute, which comes from the
system name space, so we can just type
system that serializable. And this will make
this class suizable and we can see this class
later in the inspector. And now let's declare
a couple of variable. The first one will be
a type of game object, and let's set the scope to public and we can call
this poll object. And this will be the prefabs of the object that
we want to pull. And the second one would be a scope of public
type of integer, and we can just call
this poll amount, and this will decide how many objects that we want to
incentiate on start. And the third one will
be a type of bullion, also scope of public. And we can just
call this growable. And this bully and
growable we'll decide whether the pool can
grow by itself or not. And we create this
custom class so we can easily use this custom class as a fields in the pulling
managers script. And we can create this
as an array here. As you can see, we can
just create a scope of public and then an
array of poll items. And later, we can look
through this array and then instantiate each of the
different game object inside of this pull
item array entry. And we can also use
the pull amount to decide how much object
that we want to instantiate, and we can call it pull items. And let's save this. And
if we now go back to unity and then select the pulling manager game
object once it's compiled. And now, as you can see, we have this pull items array and we can
increase its size. So let's say we want to have a three item
that we want to pull, we can just set the
size 23 or five. And as you can see here,
we can set each of the entry of the poll object
to a different game object. So we have a different
game object library pull on the start. And we can use this
poll object to instantiate it and deactivate
it in the gameplay. So, for example, if I want to set the first
one as a bullet, We can just click on the circle button here and
then browse the asset prefabs, and let's just pick bullet. And for the second one, let's say we want to put
the enemy bullet. Let's just pick
the enemy bullet. And for the third one, let's
just put Sparks effect. And the fourth one will
be for the explosion. And the fifth one, let's put the missile and make sure
that we pick the prefab one, not the FBX file, so we can see here down below. And now I'm selecting the pref The missile prefps. So now, whenever we want to
instantiate an object using the pulling manager dot instance
and then dot get object, we need to put the object
into this list here. Otherwise, it will return a
null reference exception. And now we need to set up
the pull amount number. And because we are going to
use this bullet quite often, we are going to shoot a lot of amount of bullet every frame, so I'm going to put 30 as
the pull amount value. For the bullet. And
for the enemy bullet, I'm going to also
set this to 30. And for the sparks, we can use less value than the bullet. For example, 20
should be enough. And I'm going to enable the grow ole options for the bullet, enemy bullet and the sparks. So whenever we runs out
of this pull object, the pull manager can
instantiate a new one, and it will put those instantiated object
into the q right away. So the que can grow in size, and for the explosion, a ten should be enough
for the pull amount. And let's just enable the
grow le options also. And for the missile, let's set the pull
amount also to ten and enable the
grow able option. And whenever we need to add a new object to this
pulling manager, we can always increase the size and then change the options of this newly created
element of the pull items. Now, let's set the pull
item size back to five. And here, back to the
pulling manager script, we need to declare a couple
dictionaries variable. And I'm going to
paste the code here, and I'm going to explain
this each of the dictionary. So basically, dictionary
is a collection with a type of key value pair. So each dictionary should have a key object and
its value object. And those key value pair
objects can be defined using the basic data types such as integer transform
factor three game object. You name basic object from
the Unity engine namespace. And for the first one, I'm going to declare
the key to integer, and for the value, it's going to be
another collection, which is a Q type
of game object. And we can call the
first dictionary pull Q. And like list, we need to initialize this dictionary
using a constructor. So we can just type
new dictionary and its key value types. And the second dictionary is a dictionary with the key
value types of integer and Boulan and this will hold the growable options from the custom class here
to this dictionary, so we can easily access
this growable Boulan value. And the est dictionary, it's going to be a type of integer and transform
for the key value types, and we can call this parent. And this will hold the
parent game object for each of the poll items. So we can organize the pull
items nicely in the scene. Otherwise, we will have so
many objects in the hierarchy. And with parents, we can always expand and collapse
the game object, so we can hide its
child in the hierarchy. And now let's create
a new private method. And I'm going to call this pull in it for
initializing the pull. And here we want to
create a new game object, and this new game
object will act as a parent for the pull group. And we can just initialize
this game object using the constructor new
game object and then pass the object
name as a string here, and I'm going to call
this a poll group. And here below, we want to loop the pull items
using a four loop. So for the length, I'm going to replace this with pull
items dot length. So basically, the
length will return the value of the array that we've defined
in the inspector. So, for example, if we have five member of poll
items in the inspector, then the poll items at length will return a value of five, and we can look through
all of those array member. And inside this
loop here, first, we want to create another
new empty game object, and I'm going to call
this unique pool, and this will be the patent
for each of the pool. And we need to construct this unique pool by using the new keyword
and then game object. And we want to
pass the name from the pull object name so we can just access the pull
items index of I, and then the pull
object and then name. But I'm going to
add a string to it. So I'm going to add a plus and then a new string with
an empty space here, and then a string of group. So this will create parent name. The parent game object
will be named based on the pull object name and
then add with a word group. So if the pull object
name is bullet, then it will be
called bullet group. And this will make it easier for us to organize and
manage the scene later. And we want to set this unique pull parent by accessing its
transform component, and then run the set
parent method and we can pass the pool group
game object transform. Next, we need to create an object ID with
a type of integer. So I've declared this integer. And for this value, we want to pass the instance ID of the pull object prefabs. So we can access the
pull items index of I. We can just copy paste from
this constructor here, the pull object, and then run
the get instance ID method. And this will return a unique ID from this object prefabs. And we want to also disable the game object before
we instantiate this. So let's just access
the pull items index of the pull object, and then run the
set active method, and then we can just
pass a false value. And now we want to populate
the pull Q dictionary. And if you take a look here, the dictionary have a
key type of integer, and we want to pass the object ID value to this integer key
of the dictionary. So this object ID will be
the identifier whenever we want to pull a certain
object from a certain Q. And here, we can just add
a new member to the P Q, and we can use the ad command, and for this ad command, it as for a key and value. And for the key, we can
just pass the object ID, and for the value, we can just initialize a
new Q type of game object. And we want to also populate
the growable dictionary. So we can just add
object ID as the key. And for the value,
we can just pass the pull items index of I, and we can pass the
growable bullion value to this dictionary value. And for the parents
dictionaries, we can just pass the
object ID as the key. And for the value,
we want to pass the transform from
this new game object called Unique pool here above. So now we have set up all
of these dictionaries. Next, we can create a four loop, and we want to replace
the length based on the poll items index
of I pull amount. So, for example, for
the first entry, the bullet game object, we have set the
pull amount to 30, and that loop will create 30 copies of this
bullet game object. So inside this four loop, I'm going to create
a new game object. We can just call it temporary, and we want to instantiate the pull object from the
pull items index of I. And for the parent, we can just pass the unique pull transform. And next, we want to pass this temporary game object into the Q game
object of the pull Q. And now we can just access the pull Q and using
a square brackets. We can just pass the object ID, just like when we are using a list or array,
we pass the index. But instead of
passing the index, we are passing the
object ID integer, which is the identifier
for the dictionaries. And then we can just
run the Q command and we can just pass
the time game object. As the argument for
the NQ comment. And this will make sure that this game object
that we have just instantiated will be inserted to this que collection
inside the pull queue, but with the key of this
certain identifier. And if we don't have
any previous member inside this pull Queue, Then this temporary
game object will be the first game object that's
being inserted to the queue. And for the next iteration, it will be the
second game object and so forth. Let's
save the script. And because this four loop
is inside another four loop, we need to change
this integer name. So let's just
highlight the letter, and I'm going to
change this to J. So I'm going to change all of the reference into J in
this second four loop. And for the pull items index, we want to change
this also to J. And next, we need
to run this pull in method inside
the wake method, and we need to put the pull init method
inside wake because we want to make sure
that the initialization happens before start. So any other script or
object that needs to access this pull game object
in their start method, the pulling manager
will make sure that the objects are
already available. Next, we want to modify the use object method and
the return object method. And first, inside the
use object method, we want to add a local
variable type of integer, and this is going
to be the object ID from the game object that we
pass in the argument here, so we can just type equal OBJ, and then we can run the
get incense ID method. So now we have this
identifier that we can use whenever we want to use the object from
the dictionary. And I've designed this
method to act exactly like instantiate method where we need to pass the game object, the position, and the
quaternion rotation. Now, once we have the incense ID inside the object ID variable, now we can get the game
object from the pool Q here. And here we can just replace
the instantiate method, and then we can just type
pull Q with a square bracket, and we can pass
the object ID into the pull Q key here inside
the square bracket, and then we can run
the Q command from the q that we are grabbing
from this pull Q dictionary. And this will grab the
first game object that is available inside the p q
with this identifier key, and it will return
that game object to this TM game object. But the problem with Q here, We need to make sure that
the object that we are queuing from the queue
is an unused object. And to check this, we need to check the active
state of that object. So here below, we
can check whenever if the T game object is active, then we need to grab a new one. So let's just add
an if statement and then if the
active hierarchy, that means that if
the TM game object, is active inside the
scene hierarchy, then we want to
instantiate a new object. And we want to check if this certain pull object
growable options is enabled using the growable poll and pass the object
ID to get its value. So here, whenever the
growable options is true, then we want to
instantiate a new one. But before we instantiating
the new game object, we want to put Caron active temporary game
object back to its poll, so we are not using that one. So let's just type pull Q here and then pass
the identifier, SAQ inside the square
bracket, using object ID, and we want to run the
NQ method and then pass the TMP game object
as the NQ argument. And then we want to replace the Tam game object with newly
instantiate game object, so we can just type Tam equal and then run
the incentiate method and we can just incentiate the object right away
using the object argument. And for the parents, we want to access the parents dictionary, and we can just pass the
object identifier as its key. And then we want to set the
temporary game transform that position to the
position that we are passing in the use
object method, which is pus and
also the rotation, we want to set the transform that rotation to
the rot argument. And here below, we already set the temporary game active state using the set active
method to true. So this will enable the temporary game object automatically whenever
we are using the object. And then last in this method, we want to return the
temporary game object. And basically this covers
only one condition, whenever the growable
options is true, and we want to add an L
statement here below. And basically, we want
to return a null value. If the growable plian
options is false, then we want to set the TM
game object back to null, and this will return
a null game object. And later, whenever we
use the object method, we can just check if the
game object is null or not. And here we want to also add an L condition from
the first statement, if the temporary game object
is active in hierarchy, then it means that the temporary game object is not
active in the scene. So if the temporary object
is not active in the scene, then we can just set
the transform position and transform rotation right
away in this block here. So we can just copy
these two lines here and then paste it
inside the L statement. And we want to move the t the set active method here to
be inside of the statement. Let's just cut this and
then paste it inside the L statement and then
inside the global bull here because we want to
make sure that we only activate the temporary game object whenever it's not null. And here before we are returning the
temporary game object, we want to put the
temporary game object back to the last order of the
Q using the n Q here. So basically, we are
shifting the position of the use game object
from the first order to the last one because we need to put this
back to the Q. Otherwise, we will run out of
object if we don't do this. And now we need to work on
the return object method. And basically, whenever we
are returning an object, we don't want to destroy it, but instead, we want to
deactivate the object. And here, first, we want
to add an if statement, and we want to check if
the delay value is zero, then we want to deactivate the game object right
away because we don't have any delay value. So we can just access
the object and then run the set active method and set its value to false. And we can just remove
the destroy line here and replace it with
an L statement. And here, if we have a su
value for the delay argument, then we want to delay the
object de activation. And for this, we can
use a co routine. And so now let's declare
the co routine first. So let's just type the
return type enumerator, and we can just call
it delay return. And for the argument, it should be the same
as the return object. So we can just
copy this line and then paste it inside
the co routine. And here we can just look the delay value using
the L statement, and we can check if the delay
value is greater than zero, Then we want to decrease the delay value using
the time Dotel time. So the delay value
will act as a timer. And here below, we want to
execute the yield return. So this will loop the coroutine inside this i loop before executing to the
next code below. And whenever the delay is
equal or less than zero, it will skip this while loop, and then it will execute
the line below here. So now we can just run the set active method
from the game object OBJ and then pass the false value as the
set active argument. Now, we have declared
this core routine. We can just run the co routine
inside the L statement of the return object
method by using the start co routine method and then pass the
co routine name, which is delay return, and we need to pass the argument
from the return object, so we can just pass
the OBJ argument. And then for the delay, we can just pass
the delay value. Okay. Now, let's
save the script. Now we have set up
the pulling manager. Let's go back to unity. And now let's try to
play this scene here. But there is an error here. So I'm going to check
the error first. Okay, so let's just
double click the error. And it points to this line here. Okay, so there is a mistakes with this
pull items index here. It should be the index
of i because we are basically looping the pull items from this first loop here. So we need to use this I integer from the first loop to look
through the pull items. And this is why it
throws an error. So let's just
replace this back to for the index of the pull
items and save the script, and let's go back to the T, and let's give another try. And now, as you can
see, it is working and the bullet are incentiated
from the pulling system. And let's just pause
the scene here. And as you can see
in the hierarchy, we have this game object
called poll group, and that game object is being
created by this code here, the first line of
the pull it method. And if we expand the
poll group game object, we have another anti game object based on the game object names, which is bullet enemy bullet
sparks explosion, and meso. And this game object is also created by the
pulling manager, but based on each of the pull items and three
game object names, but we are adding a
group behind the name. And if we expand one
of the group here, you can see that we have a
lot of child game object, which are basically the
game object that are being incenated on the wake
of the pulling manager, and basically we are
using this object. For shooting and for
creating the explosion. So instead of destroying
and intentiating, we are retrieving the
game object and then returning the game
to this group here. And as you can see here, somehow the blaster
or the bullet, the player bullet
never gets returned to the poll e here. So
let's just fix this. And as of now, it keeps growing, so we need
to fix this definitely. So let's go back to the script. And here, Let's go to the auto shoot script and below
in the void shoot method. As you can see, we
are instantiating the bullet using the
pulling manager, but we never disabled those
instantiated bullets. So it keeps growing the
object from the pool. So here below, let's just add the comment to return
from the pulling manager. So let's just access the
pulling manager instance, and then we can
just run the return object method and we can pass the game object that we are instantiating on start
of the method here, which is the TM game object. And for the delay, we can just pass the value from
the shoot profile. And get the destroyer rate
value. And let's save this. Hi, this is Rome
from the future, and there is a couple
of things that we need to fix in
the shooting script. So here under the shoot method. As you can see, whenever
we instantiate the bullet, we are using the
spawn point rotation, which is the far point rotation. This is all good, but whenever the
ship is banking, then we will introduce slight rotation on the
z axis to the bullet. So we need to zero out
the z rotation first. So to ignore the z rotation, let's just create a new
quaternion rocal variable inside the shoot method, and we can just call
it bullet rotation. And let's create
a new quaternion from a type of ular and here we can pass the value from
the four point ular values, which is the x value
and the y values. And for the z value, we can just pass zero. And now we have declared
this bullet rotation. Let's just use this value as the rotation whenever we
instantiating the bullet. And we have defined
this destroyer rate from the shoot profile
scriptable object. So let's take a look inside
the weapon profiles. And I'm going just to select the player level
two profile here. And as you can see here,
the destroyer rate is set to 2 seconds. So this will get this value, and it will delay the destroy of the bullet after 2 seconds
being instantiated. So let's give it a try. And as you can see here, let's post the game, and
let's take a look here. And if we expand the
bullet group game object, you see that I'm not sure, but I'm guessing that we have a fix a 30 game object
here, and it doesn't grow. Okay. As you can see here, if I select a couple
of game object, we have a couple ones
that are activated, and you can see here
in the inspector, it's actually the
activated, so it's working. And basically, the one
that are activated is the unused game
object from the pool. So whenever the player going
to shoot a new bullet, it will pick the
activated game object. But if the pooling
manager cannot find any the activated
game object, then it will automatically
growth this pool by incentiating a new
object and then put those new objects into
the Q collection, and also as the child of this
bullet group game object. So basically, pooling system is a good practice
whenever we are creating a game
for a device that with limited capabilities
such as mobile device, So it's really
recommended to set up pulling system to manage objects that are used very
often and very repeatedly. Now, let's give it a try for
the bus ship here because we already changed quite a lot of things inside the
pulling manager. So I want to make sure that it works fine with the bus ship. So let's just disable the
human rescue and then enable the bus ship, and
let's give it a try. Okay, so far, it's good. As you can see
here, the enemy bus shoots the bullets right away, and we have the sparks generated
and also the explosion. So it looks quite good so far. The missile also works. So yeah, that's conclude
the pulling manager script, and we can continue
to the next video.
26. 26 Level Designing part 1: Okay. So now we are going
to design the level. Okay. We can just disable
the bus ship first so we can see the scene clearly. Here, let's go to
the asset panel the project panel and
under the models folder. We are going to grab
our ground tile here. This one, the ground tile
and drag it to our scene. We are going to make sure
that our ground tile we're going to set its
layer to the ground object. I'm going to create
anti game object. I'm going to reset its transform and rename this
environment. Okay. Let's put the ground tile to be the child of
our environment, and I'm going to
also push our ground tile one unit or maybe
two units below. The value of the y axis
should be negative two. If you see it from
our game view, I'm going to push
this on the axis. And set the value of our
Z two negative five. If you want to move this
incrementally, every one unit, you can hold the control
button and just direct the object based on your selected gizmo and it will move the object in that access, every one unit, as you can
see here in the inspector. Now we have this ground
and I'm going to duplicate this a couple
of times and move this then duplicate this again. Move this duplicate
again and move it using the control button. We can see it snaps properly
with the other game object, the other ground, and we need to create this
a couple of times. I'm going to use to
select all of it and then duplicate all together and move it by
holding the control. Here, we can see that we have the position is negative six on the t this one will be
92 on the Z axis and. We will need to add
more ground later, but we are going to set
the world mover first. World mover is basically the parent object that are going to move our
camera and our player. The player will follow
that world object. I'm going to create a
new empty game object here below the environment and I'm going to
set this to ground. I'm going to drag all of the
ground to this t g object. All of the ground be the child of this
ground game object, so we can expand and collapse. Now, let's create
the world mover. I'm going to create
new my game object and we are going to reset the value of this
empty game object. And our camera. This camera will be the child
of our empty game object. Let's re empty game
object to mover. We also need to
parent our player to this world mover here. Okay. So now with
our road mover, let's add the to
move script. Okay. And we can set the
position, the move upset. For example, if we want to
move to this point here, then we need to set the
z value to let's say 90. And how long do we want to move? For example, we want to move for 62nd then put
62nd here and enable on start Safety and there
you go as you can see, environ ship is moving
across the environment, and we will Okay. Okay. We will arrive. I'm going
to push the game view here. We will arrive at the end of this ground here in
exactly 60 seconds. So we can calculate how long your level is going to be by inserting
a value in this duration. So if you want to set the level to be only 2 minutes long, then you can set the duration to 120 because the
duration is in second. Now set this up. Let's expand our level. I'm going to copy
all of this here and I'm going to
duplicate all of them together and move them also together by holding
the control point. Okay. Let's check this. This is 200 on the z axis. I'm going to change the
world mover here to 200, maybe 190 and set the duration to be longer
than this value here, 120. If we play this, it will move
the same speed as before, but we have a longer level. Okay. Now we can start
lay out our enemy. First, I'm going to enable the human rescue and I'm going to change the
layer to a ground object. I'm going to put
the human rescue below here on the ground. But I'm going to
make the collider bigger so our ships can hit
the collider, like that. We are going to save
this human rescue as a pre let's go to the prep I'm going to create a new folder and call this friendly and I'm going to direct this human rescue
to this friendly folder. Now we can move
the human rescue. We can create a couple of human rescue objects
by pressing control. Let's put the human
rescue inside the environment game
object and create another empty and re this rescue and put the human rescue
inside this rescue here. So we can organize
our hierarchy here. Let's duplicate this again. Okay. That should do. Now we are going to put trees
and rocks in the scene. Let's go to our models folder and we have a rock actually, so we can put it on
our environment here. Basically this rock
has two object. So I'm going to move
the first object. Yeah, to be here, and we can move so we can
see on the game view here. We can scale this up. And we can create
interesting layout. And I'm going to fast
forward the video here. Okay. Okay, save the scene, and we are going to
put the trees here. I'm going to sect the
rock and I'm going to change its layer
to ground object. For the human rescue, I'm also going to change
its to ground object. For the ground we can
change its object, and we can change
all of the children. Now we need to put
some trees here. Let's go to the models
again and Where is it? I put the coconut tree
here. There you go. We have the trees. I'm going to create a new empty
game object for organizing the trees.'s
name the trees and one of the
coconut tree here. And duplicate the
coconut tree and move it to another
position and we can rotate on the y axis to
create some random rotation. Duplicate again by pressing Control D, go to this position, and we can focus an object by double ting
its name on the hierarchy. And duplicate both of this
object and move this rotate it and duplicate it again and we can select
all of the coconut trees. Let's just duplicate
all of them together and move it to run
this position here and Let's select of the
trees and duplicates and move this around here and we can just
delete this tree here and select the three and change the layer to grow object and also
change the children. Now we have this tree here. If we play the scene, we can see that the
ship gets rendered on top of and we can
rescue the human. How the animation
is not playing. Let's check our human rescue. Let's pick the controller
and let's apply this. Once we apply this, it gets applied to the other
human rescue game object, since it's the same prefs
if we play this now, we can see the animation
of our human rescue. We can rescue the human. Human rescued. And like that. If it's too fast, if the world mover
movement is too fast, we can always increase
the duration. I'm going to set this to 240. I should take 4 minutes to travel to the end of the
map here of the level. I think this will
be better because we will facing a lot
of enemies and stuff. I think that will
be for designing the level and in the next video, we are going to
place the enemies.
27. 27 Level Designing part 2: Okay. So let's place
the enemies here. And we can just
enable the Tut A, and I'm going to name
this to be missile. And I'm going to move the
turret to the ground here. But we are going to expand this and for the missile shooter. I'm going to push, sorry, to push the
empty game object. The empty game object
aligns with our ship here. I'm going to move this
around to this point here. And I'm going to make this
turret missile as a pre. Let's go to the
pref folder under enemies and drag
the tret missile. Okay. And now I'm going to create another turret game object,
but it's not a missile. This will be the normal turret. Turret that are shooting the
normal MO normal bullet. So let's go to the model
and drag there a object. I'm going to set
this to zero, zero, zero, and move this here, and we are going to
set up we are going to the missile game object here, and we are going to
use this shooter here. I'm going to duplicate
the shooter and to change the position to
remove the negative sign, and we can scale the x
axis to negative one. So it should look like this. And we are going to create
a new empty game object. And this will be the upper part, just like the missile tot here. Let's put the upper body shooter to be the child
of the upper part here. Just like the missile
tret we are going to put a look at player component
in the upper part here. Just look at player, we're going to use the devolt
speed here and let's move the turret to the ground. I'm going to move this
thread around here. Yeah. And we can sorry, we can create an empty
game object that are going to shoot the MO here. So let's just create
empty game object. And make sure if we
change this to local, the z axis is pointing forward, or at least it so pointing
the same direction as our object shooter
rotation here. I'm going to make sure
that the position of this empty game object lies
the same of our shape here. So we're going to put it around this position here
or we can just s let's move this right there. And this will be the shooter
auto shoot and let's just use the circle turret
here for the profile, but later we can create a new
profile that we want you. I'm going to align
the exposition to align with our shooter
here from the top of. The bullet refers, I'm going
to choose the enemy bullet, we can just empty
the fire point here and rename this to shooter
L or shooter left, and I'm going to duplicate
this and this will be the shooter R
or shooter right. And I'm going just to
remove the negative sign, position lining with the
shooter mesh over here, let's just rename this shooter. And we are going to
set this as a prefab. Let's go to the enemy's
folder and direct the prefab. But with the Tt Mazzel here,
and the treat shooter, we need to create health system, death system, and
also create object. Okay. So basically,
what you do is, we want to create
a flame effect. So go to the x folder and
drag the flame smoke here, and we want to make sure that our flame particle
here is disabled. And whenever we defeated
the turret shooter, we want to enable that flame smoke
object to direct this on that event slot here. I'm going to make sure under the game object component here, choose the set active method
and set this to activate. We are going to create an
expert, choose explosion. Here, we are going to
de after 2.5 seconds. We want to destroy this
explosion after 2.5 seconds. And for the hit effect, we are going to grab
our sparks prefabs. And we don't want to
add health bar here. So yeah, it's okay if you
don't use health bar, and I'm going to
apply this prefabs also the same with
our threat missile. I'm going to add a
flame smoke over here. Then if I go to
that game object, as you can see, we have
a nice flaming effect, and I'm going to
reposition this a bit. Okay. Yeah, something like that. And I'm going to disable this first and let's
go to the tread missile. Add a couple of coponent just
like the shooter before. And the last one should
be create object. Okay. Okay. Sorry, with
the red shod here. I'm going to direct
create object to our spawn object slot here. So this explosion will get spawn whenever the enemies
get destroyed. Press apply again. Here, I'm going to direct
the create object to the span object here and
I'm going to set just like the other threat over
here, Explosion 2.5. Also on that event, I want to enable the flame
smoke over here. Go to the game object menu and choose set active and
subliF the hit effect, we want to go to the spark to the assets folder asset types
here and search for sparks. Okay. And then we want to
apply the settings here. So it gets applied
to the prefix and whenever we grab
the new object from the prefet it will have the
same settings like this one. Under environment, I'm going
to add a new game object. And I'm going to call
this ground enemies, and I'm going to put all of the turret to be the
ground enemies here. I'm going to enable our round
turret like this, yeah. And I'm going to put this down, negative two and maybe put this around here around
here, should be good. And Yeah, make sure that the
rotate is ground object. We set the layer to ground
object and the upper part. We have the shooter object,
and this is the circled. Basically, the one that are spinning is this
empty game object, and this is rotating
indefinitely. I'm going to move the
shooter object here to run the position of
our ship on the y axis, the same position. There. Now we have the setup. I'm going to. Another
thing is we need to create the box glider for collision. Let's just set up this. I'm
going to make this bigger on the x and also the z,
something like this. I'm going to enable Reger, and we are going to
also create the health, the death system, and the
create object script. So let's just quickly
set up this up. Drag this to the spawn
object on that event, we are going to enable
the flame effects later, but we haven't put as the
child of this run thread. Let's just set up
the sparks here and drag the flame object
and set it as a child, and I'm going to reposition this somewhere around
this position yet. Okay. And I'm going to disable
the flame smoke here. And whenever it gets destroyed, we are going to enable
this flame to smoke. Game object set active
and set this true. And this rod, we can
save this as a prefabs, also, and we are going to put the rod as a child of
this grow enemies. For this two missile here, we already set up
our health system, but I forgot to add a collider. We need to create
a new collider, and let's create a bigger
collider like this. Whenever our player shoots the bullets from our player
will hit this collider, and let's set the
size and the size to 1.5 and set the trigger to true, so we can just complete
this component press apply and go to our
treat shooter here, and we can paste component
as we can just press apply. Yeah. Let's save this
and let's try it. We have a but there is an
issue here, as you can see. The turret is shooting, even though the object
is still out frame, still off screen, and we want to create
some sort of trigger. So whenever an enemy is
outside of the screen, we want to disable it once the enemy enters our
screen, we want to activate it. So we need to create
some sort of trigger. And we will create that
on the next video.
28. 28 Enemy Activator: Now, let's create the trigger that we've been talking
about on the last video. Let's go to our script. Under the enemy script. We are going to create
a new activator script. Sorry. And let's open a script. Basically, the script is
very simple, actually. We are going to delete all of this built invest here and
we are going to us using the unit engine events
we are going to create two new
public unity event and this will be on screen, and the other one would
be on screen. Okay. Now, basically, we are going
to create trigger enter, this is going to be trigger enter and we
are going to check if the collider is have
a tag of activator. Then we want to invoke
the enter screen. Here. Invoke. For the exiting the screen, we want to create a private
void on trigger exit. Also, we want to check the tag, but it's going to be thevator and we want to
invoke the exit screen. We can save this
activator script. And now we need to set up a couple of things before
we are using that script. Under word mover, I'm going
to activate the game view, so we can see and
activate the gizmo, and I'm going to create
a new empty game object. And this empty game object, we have a box glider. And also a rigid body. But I'm going to set the
rigid body to kinematic, so we can just enable
the kinematic options. I'm going to scale the length, the size of our collider, to be around ten or maybe 12. So it covers the screen here and set the z
to very low value, let's say 0.25 here. I'm going to move this to be at the edge of
our top screen here. Let's just do that.
Okay, maybe around here. And I'm going to enable
the trigger options here. And I'm going to set this
object to a new tag. So let's create a new tag, and we are going to
create an activator tag, and the other one
is deactivator. So for this one, I'm
going to set this to activator and also
rename this to activator. And I'm going to round
the z value to 11. And I'm going to duplicate
this game object, and rename this to the activator and also change its
text, the activator, and maybe put the activator here around the bottom of our screen or negative
11 should do. Okay. Yeah. And I'm going to
increase the size of the collider of the activator.
Let's just direct this. Yeah, like this. Okay. Or we can just set is zero and the axis on the
size to a very big value, let's say seven and
for the activator, just change the y27 also. Let's save the scene first. And now we can enable
the enemy like this. We for example, for this I'm
going to move this bit here. Now we can disable
the upper part here also we can disable the boxer And let's
add the script. Sorry, at C, but and
type activator script. And on o screen, I want to enable the
box glider so first. I'm going to go to the box glider and I'm
going to enable this. Okay. So we can shoot the turret. I also want to enable the upper part of the
game object here. Game object and set
active to true, something like this,
whenever exit our screen, I want you to disable
the upper part again. If we fail to destroy this, I want to deactivate
the upper part, so it will stop
shooting at our ship. Let's just track
this upper part and set game object set
active to falls here, and let's just apply this tore the same with our round
turret over here, I'm going to add a activator
script we are going to set the upper part red to be disabled from the start
and also our bus collider. Whenever it enters our screen, I want to enable our collider first enable to true and I'm going also to
enable the upper part. And go to the game
object and choose the set active method
and check this. So whenever we exit the screen, we need to disable this again. Game object to falls like this, that should do the
trick and press apply save your scene often, and let's play this.
We can see it on. I'm going to disable
maximize on play here so we can see our
scene view here. Let's just destroy
the ship here. As you can see, the enemy
is still activated. There is some issue apparently. Since the boxer is disabled, and we cannot actually activator script
never gets triggered, so we need to enable this, but we need to disable
our health system. And whenever our player
enters the screen in here, we need to enable this
health system to drag this. Then go to the health system bullet b we are changing this. Also for the turret shooter. We are going to enable
the box colador again, but we are going to
change the health system to enable and we are going to disable
from the start here. You press to save the
headings and treat missile, the wrong tre I'm going
to press apply also. Let's say this and
let's try this again. Right now, we can destroy this. I'm sorry. There is an error. Under health system. An enable? Okay. Because this is
somehow it's empty, we need to fill a default value. We can just set this to
bullet. It's default value. So since most of the health
system are set to enemy, just make this default
to bullet and this will only apply if the health enemy
is on the player object. Okay. Let's try this again. There are some things
we need to edit also for all of this
enemy game object. We want to disable destroy the object does
not get destroyed. So it will create
explosion and then it will enable the flame game object. So, let's try this again. I'm going to disable
the gizmo here. There you go. Now, whenever it enters the game object
gets activated, but let's try this again. Okay. Yeah. There you go. There is
still an issue here. Oh, it says shooting. Now we need to set
a couple of things. Whenever we defeat
the treat here, we need to disable
a couple of things. Let's go to our
upper part d this to be the object of
the second event here. For the player, we
can disable this. Also for the shooter, we can drag the missile shooter one and the missile
shooter, two, and we can activate
this game object. Okay. Okay. Like this. Yeah. Press apply and this
should get saved, and we should do the same
to our other enemies. Whenever we destroy it, we need to disable the other
component that we have here. Basically, the upper part, the rotating script,
which is look at player, disable the player, and we can just disable the, the shooter game object
here by activating it. Go to the set act and the activated object by checking the set
active options here, and let's press apply the same goes with our
run to red here. T we can just disable the sorry. We can disable the rotation, the atto rotate here, able to falls, and we can also disable the
shooter objects here. So just select the
parent shooter object. Since all of the
shooter object is the out of the
shooter object here, and under active
and the activated, save and I'm going
to press supply. But I'm going to check
our rotate here. Script we already said
it's on disabled. We want to stop
all root. T should work nicely. Save our seal here. And let's play this again and I'm going to destroy
the first turret here. As you can see, once destroyed, it stop rotating and it
doesn't shoot anymore. And this other tret is
shooting at our plane here. Yeah, we can destroy this. Once the other turret is entering our scene here,
it gets activated. Okay. So all of
them work nicely. Later, we are going to create rewards or coins whenever
we destroy the enemy.
29. 29 Coin Setup: Okay. Now let's continue
to create our coins here. Basically, we need to
create a script first for creating the coins for
creating the coins movement. Let's just do that. Go to our scripts folder
and the transform, I'm going to create a
new movement script. Let's open the script. Test. So now, it's the loading. First, we need to declare a
couple of variables here. Let's just do that. I'm going to add a private and this is going to be
our magnet strength. But later, we are going
to change this and we are going to get the value of our magnet strength
from other script. We need to change the
start because we are going to utilize un enable and awake gets executed
before un enable, but start gets executed
after un enable. That's why I need to do the initialization inside
the awake function, and we are going to grab our
rigid body component first. So we are using the get
component just like before, and we are going to create
an un enabled function. So save this. For the unenable function, we are going to define
our movement values here, our factor three
movement values. Basically, we are going to set our move values to be
transform the position. So the position of
this coin here. But after that, we
are going to add a vector random random inside
inside unit sphere here. This is basically
returns a random point inside the sphere
with radius one. Random point 0-1 inside a
sphere from our position. That's why we need to define
our position first here. We copy the position
of our movement. We are adding our vector here with random
inside it sphere, but I'm going to
multiply this sorry, multiply this value
by our speed here. We can get a maximum random
value instead of only one, radius one, we can have
a radius of three. Well, it's depend
on our values here. And after that, I'm going
to set the y value to zero. We want to move only
on x and z plane. Since we are going to
move using rigid body, I'm going to change the
update to fix update. Sorry, I need to enter
this bracket here, we want to create a alert from our coin position to our
random position here, movement here, the
final movement value. We are going to feed
that inside our target variable, type target. We can use function
from the factor three class and let's put our transformed position
for the target, it will be our movement
for the float value here, we are going to use
the speed multiply by our time fix Delta time. We are going to use only
a value of one float one, and we multiply this with
our fixed data time. Yeah, we need a reference
to our player first. Let's just type transform
player a start method. Inside start, we are going to
first find our game object, but using fine objects with
tag and the tag player, and we are going to
grab it transform. We have reference to our player. Now we can compare our
distance to our player. I'm going to create a factor our player position
and substract with our transform position, we are going to check square magnitude distance
but in square value. So we are not going to operate square
root to the distance, so we are going to just to
compare the square distance. If it's less than
some value it's say met f power, for example, let's set this one here,
and the power is two, since we want to compare the square value with
our square magnitude, and if it's less
than less or equal, we want to move our coin. We can love our target, so we can just copy
this slide here. This will be the
starting position. This is whenever our player
come close to our coin, then we want to move to
its player position here. For the value, set
it at this moment to one or we can change the magnets two
and we can use this value. Temporarily, we are going
to use this value here. Okay. And after that, we are going
to move our position using the rigid body component
and we are going to set this to target
for the rotation, we are going to get our quaternion from
the ular value of our target vector here. This will create spinning
spinning movement on our coin. Let's save this. I'm going to create our coin. Let's go to the model. We
have this gear object. I'm going to direct
this to our scene. And we can use the coin material to this object or direct this to
the object here. Okay. And I'm going to
add a glowing texture. So where is it? I think it's under sprite and under bullet. We
have this glow here. We can just set it as a child game object and we can just set this rotation to zero. Let's just scale
the scale size and set the glow to the
color to be yellow. And we can decrease
our alpha value, so it's going to be
a bit transparent. For the material, I think
we have a sprite additive. Do we have it? Yeah, this
one, sprite additive. I'm going to use this,
so it glows better. For the color, I think we can just increase it brightness. So it stands out more and maybe decrease
the metallic value. That increases smoothness or also decrease it so
we can see it better. Now once we have set up our clo gear object and this will be the
rewards or the coin. We can use the coin
movement to our gears here. Okay. Now I'm going to put this under friendly and drag this
gear as a prefabs. Once I have set this as a prehab I'm going to delete our gears
object on our scenes. Aw as always, if we want to use the object via
the puling system, we need to select the manager, and we need to add new members, increase the size
for the last entry, I'm going to change this
to gear to our coin. And change the pull amount
maybe 220 should be enough. Now we can put on our enemies. For example, I'm going to select the ground enemies
and the tread missile here, and I can add create object. I'm going to move this up here. I'm going to create
the coin coin, but gears from the asset and this one here
that we have set up the prefabs and set the
create amount maybe five, and we don't need to
destroy this, create 25. We can drag create game object to our spawn
object here under that system, so it will also
spawn explosion and also a coin. Now
let's press apply. It will update our
prefet and save the scene and let's try this. Sorry. Let's destroy this. There is an error. There is no rigid body
attached to our gear, so we need to select
our prefabs here, and I forgot to
add a rigid body. I need to add rigid
body and disable the use gravity and
enable kinematic. And also, I need to add a box coder and set this
box lider to trigger. Also, we need to
set the tag here, create a new tag,
and we can just create a coin tag and
select the gears and And change the type
coin, save the project. Whenever you change the prefps
always save the project. The pref changes get safe, and let's try this again. Now when we destroy,
there is a coin, but the orientation is wrong. As you can see,
if we go near it, it will start moving
following our plane. But we have actually declare
the picking up script. But let's change this
rotation to zero, the pref and save this again and see if this fix the problem. Okay. Okay. No, it's still instantiating facing in
the wrong direction. I'm going to pass the scene first and under the pull group, I'm going to check the
gears and I'm going to check need to fix this. This is quite an
easy fix actually. Sorry, there's something
wrong with my mouse here. Now, we need to rotate we can just leave this
zero in the rotation, but I'm going to create
a new empty game object, and this will be the gears. Mesh, and we can add a mesh
filter and also mesh render. And for the mesh
filter, I'm going to search our game object. Is it gear or I'm going
to just to browse. This is the cylinder here. And I'm going to rotate this
90 degrees, so we have this. And for the materials,
I'm going to pick our coin material. And for the parent game object, I'm going to delete
our mesh filter and also our mesh render. For the box glider, I'm going to switch
the value from the y to z on the size here, so we can set we can copy
this and we can paste this on the y axis and set
the z axis to 0.6, so it fits fits our mesh here, and we are going
to rotate the glue to 90 degrees on the x axis. So it aligns and
now we are going to apply this pre updates, and let's delete this save. And let's try this again. Okay. There you go. We have a working coin, and whenever we get
near to the coin, it will follow our plane. Okay. Now let's continue
our coin set up here. And first, I'm going to go to our script and
under gameplay, I'm going to create
a new magnet script. And this script is
basically going just to hold a couple of variables. So where is it a magnet script? I'm just going to reopen this. And I'm going to paste a couple of variables that are provided. And we are going to delete
our update and start. Basically, we are going to
create a float variable, and the first one
is magnet power, and this will have
attribute a zero to five and also magnet range. And this will be the distance or the threshold when our ship are start to affect
the coin movement. Let's save this
this magnet script, we are going to put
it on our player. So under the word mover, choose our player and add component and type
magnet script, and we will have
something like this. Change this to a value, let's say of two, Okay, save the scene. And now we need to edit
our coin coin movement. Let's just open
the coin movement script from our left session. And now we are going to change
a couple of things here. First, we are going to
need our magnet script. I'm going to call this magnet. I'm going to find our magnet
script inside our start. This will change our
player reference. Type magnet, and
we're going to use a fine object of type method and just fill out our type here, just like a get component, which is the type
of the variable, which is script and it will found the one that
we put on our player. This is useful for finding other component that attached
to other game object. But if there are multiple script with the same class attached to a couple of different objects, it will pick one only. The best use for
this fine object is to find other component that only available one
instance in the scene. If there are more,
then we should not use this fine
object of type. Okay. So now since we already have reference to our player via our
magnet script, we can just grab the
position by typing the keyword magnet keyword here and add transform
and that position, then we will find we will grab the position of the magnet
holder, which is our player. So, just copy this keyword here. I'm going to replace
our player position. Okay. And for the magnet strength, we are going to get our magnet power for the
for comparing the distance, we are going to
get the value from our magnet and this will
be our magnet range. Now we can save the script and make sure this is also safe. Now we can try the script, right now, our value is
and the range is also. Let's play this and see if
there's any difference. Once we get near
it, as you can see, it moves, for example, if we increase range
here to four, let's say, and also the range to four
and the power to also four, we will see a much
stronger effect. It, it will There you go. Now we need to create a
pick up for this coin here. Now let's create the
coin pick up script, and let's put this
inside our gameplay. Create coin pick up. Let's open that coin
pick up script. Now we can just remove
this to using since we are not going to use any less or array or coroutine here. I'm going to add Unity engine the event and just delete
the start and update method. And I'm going to create
a new public Unity event and I'm going to name
this variable picked up, and we are going to use
the trigger method. Now, since we already set
our coin tags to coin, we can compare the
tech by refer to the other collider that came contact with
our player here. Since this coin pick up is going to be on our player game object, then we can type right away
using compare tag and check its tag if the other object that collides with
our player is coin, then we want to
destroy that coin. But we need to use our pulling
manager, that instance. And we can just return
the game object, the other game object. We want to we want to destroy, but we want to destroy using the pooling manager so we can use the return
object function. I'm going to add comment here
and we are going to create add some coin counter. But for this videos, we are going to leave
the script like this, but later we are going
to add some code in here and let's just put
the script on our player. So I'm going to add
our coin pick up. So add component, and I'm
going to type coin pick up. And for the coin pick
up, I'm going to add a podio source on our player. And we can add an event
here on our coin pick up, drag on our audio source and choose the audio
source component, and we can choose the play
one shot audio clip here. I think we have audio
here, the coin wave. And I'm going to save. We are going to choose that coin sound. Now if we play this, and
whenever we destroy the enemy, we can pick up the coin. None is actually the
sound that's not playing. It's play, but somehow
it's not play. Oh, sorry. I forgot to invoke
this event here. Whenever we pick up a coin, we need to invoke it type picked up and then we are
going to invoke this. Let's save the script again
and let's try it again. Troy and pick up the coin. Okay. There you go. Whenever
we pick up the coin, we have the sound of
the coin playing. So, the sound will be a audio feedback
whenever we pick up a coin. So it will give nice feedback to the player whenever
we pick up the coin. Okay, I think that concludes our coins head and we can
move onto the next video.
30. 30 Camera Movement: Okay. So now we are
going to create a camera script to create a slight movement whenever a player moves to the
left to the right. We want to move the
camera slide to the left or to the right
following the player. So adds more dynamic to it. First, under the world mover, I'm going to select
our camera here and I'm going to
check the length, the maximum and
the minimum value. If I move the x to
the left side here, the maximum should
be negative 1.4, the minimum position
on the x axis and then the maximum
should be 1.3. It's not centered actually. 1.4 still okay. Yeah, 1.4 should be okay. Okay. So we have those
values. Let's create our script and go to the script, transform and let's
create our camera script. I'm going to open our
camera script here, and we are going to create
a couple of variables. Basically, we are going
to create a transform for storing our player
and a float to define our minimum exposition and maximum exposition
and the speed of our camera and a private
factor tree of position, and this is for
calculating our movement. We are going to do all of
this inside our late update, so I'm going to change our
update to late update, and let's save this rip and I'm going to delete
our start method. And I think the file is is
not opened correctly here. As you can see
here, the amount of behavior text is colored
black and it should be blue. So I'm going to go
to our assets here inside the solution
and c transform. I'm going to add
an existing item. This happened often
with official studio, so you can skip this process
if it's okay on your end, transform and I'm going
to add the camera script. Once we add the camera script, it be fixed in a moment. Now the bono behavior
already turns to blue. I have late update function and the late update function
also colored blue here. I'm going to check if
our player is null, then I'm going to
return the method here. I'm going to skip doing the
code below is return here. But if we have player assigned, then we will do all of
the code below here. First, I'm going to
set the position to our transform the
local position. The local position
of our camera, this position will be the
same position as our camera, but we are going to
change the x values. And these values will be received or we are
getting the x value from our player position or I think player local
position X. Okay. Okay. Yeah. I think
it's local position, and then we want to
clam our position x. I'm going to overwrite our position x using the
math clam, for the value, I'm going to change
the position dot x, so it's previous position, but we want to clamp it using the minimum x value and
also the maximum x value. For the minimum value, we are going to get from
our minimum x here, and the maximum, we
are going to get it from our float value here. Once we calculate our position, then we want to apply
this to our camera. This type transform the local position
equal vector three, l from our transform local
position to our position. For the speed, we are going
to use this speed here, but we're going to multiply
this by time delta time. Save this. Once we save this, we can just put
this on our camera. Select our object camera, and we only need to apply
this to the parent camera. We don't need to put it
on our ground object and direct our camera script, and we can set the minimum
x to negative 1.4, the value that we try before. For the maximum speed,
we are going to change it to 1.4 and set the direct the
player game object to the player
planform over here, and we can save
the scene project. Now let's try this. I'm going to maximize
the screen on play so we can see it clear
better and there you go. Whenever our player
moves to the right, you can see that
the camera follows, but only to a certain
position and then it stops. So we can create a nice
dynamic behavior like this. That concludes our
camera script and we can move onto the next video. Okay.
31. 31 Boss Integration: Okay. Hello. In this video, we are going to
enable the bus in our level that we have
already designed before. So let's just start and we have the bus ship
here disabled since the last time we
set up the bus and let's just enable this
so we can see the bus. And sorry, let's move the Z position first to
maybe around this area here. Okay. Okay. Now we can
redesign the nodes movement. I'm going to move the
first nodes here, and the second
nodes and the third one and actually the
fourth one here. Like this, I want to create a new ant game object
first and add a box glider. And this will be
our bus activator. Let's just rename
this object activator and set the y position to zero. Let's move a bit here, maybe around this area here. Now we can just parent this bus, so this move here to. So I'm going to move
this slightly here. So this tigame object should be around the
starting nodes here. Now we can just direct this as a child of this bus activator. Okay. The next thing we need to do is to
create activator. Sorry, I'm going to check
the script first, enemies. Activate script. Sorry,
I forgot the name. Let's just add script. And whenever it's
enter the screen, we want to activate
this bus ship. Let's just disable this and drag this and set the game Sect true and we want to also parent this bus
activator to our world mover. Let's just drag
this world mover. Or, drag this game object
here, the transform. Then we can just go
to the game object and transform and we
can change its parent by using the set parent method here and drag the world mover
as the parent transform. Let's say this. The next
thing we need to do is whenever our bus is destroyed
or on death event here. We need to detach children. Just drag this game object here, the transform the bus ship, the transform, we can use the
detached children method. Basically, whenever
the bus gets defeated, it will stop following
the world mover and it will stay behind
on the scene here. Let's save the scene
and let's try this. First of all, I'm going
to check if there are any Tag are needed to
define the activator. No. We don't have tag over here, so I think this should
work right away. Let's try and play this. Okay. Okay. You can rescue human rescued. Let's just wait for a
while. I think we put the bus game object too far off the screen,
but it is okay. Let's just wait until we
can see the bus here. I'm going to minimize the
screen first so we can see on our scene what
is actually happening. We actually already entered the area where we
have the bus here. Okay. Oh, yeah, there you go. We have the bus activated. Yeah. There you go. Okay, there seems to be an
issue with the bus. It's actually moving to the So let's check this out. What? Okay. Okay. So
somehow this note is reset, so I'm just going to remove
all of the notes here. And add notes. Let's just readjust
the notes here. Let the This is the node four
and this is the third one. Is the second one and this
should be the first one. Let's check our bus activators over there if we see it on top. I'm going to move
all of this slightly forward so we can
encounter the bus quicker. I'm sorry. Somehow it's
reset to this position. And I'm going to inspect what
is the issue in it, yeah. Okay. So yeah, figure
out the issues. And basically, we need to edit our note
move editor script. We need to add an entry that to mark whenever
there is changes, we need to mark the s d. Let's just open our script
our note move editor here. And I'm going to make this bigger K probably a bit bigger. Yeah. So here, basically, we need to check if
the Gangs changed. So let's just create a statement and then
type GI and then change. And this is actually
a bullion that the unity provides whenever
there is changes on the GI. Now we need to use
the editor utility and set for the target, this is going to be our source. Yeah. And we need to also mark the mark the dirty but we
need to use a library first, so we need to use this
editor scene management. So make sure you type this and we can use this
editor scene manager, and we can use the method, mark dirty and let's get our scene by accessing
our source script, and the game object and scene. T or we'll get the scene that the game
object is a part of it. For example, it will be
our game scene here. Save this and we can just copy this entry and paste it here also on the
CI and save this. Now, It's going
to compile first, and when for example, if I move this nodes
here, as you can see, mark the scene dirty
and we can see that by this asterc sign
in the head here. So, let's just
adjust our position, and I'm going to check
where is the activator? If the activator here, I want the bus to enter our
screen here because once the activator gets triggered
by this activator, activator is on the top
of our screen here. The bus activator
will start following. We'll get parented right
away to this activator. We need to make sure
that the movement of our bus ship has some sort of distance around let's say eight or ten units
from this glider here, it will move around
in the middle of the screen here, the bus. Let's just select the bus ship. And I'm going to move this here here and I'm going to
create a loop movement. So first note will be at the almost exact same
position of our less notes, and the third one is
going to be around here. Okay. So yeah. And
then save this. And under the note movement, I want to make sure that it will look to note to the first note. So change this sorry, one here. Let's save the scene again. Now, let's try this. I'm sorry. Okay. First. Sorry, we forgot to
disable the bus. We need to disable
the bus first. Say the scene again and
let's try this again. Okay. Let's rescue some people. Human rescued. Let's destroy this one first and rescue human. Okay. Okay. Now we can see that we
have this bus here. Start showing and it
should follow the screen as it moves. There you go. We have a bus but it goes
back to the first node. Maybe we probably
need to change. They look to note to the
second one, the first one. It's okay. Since now the
movement is already working, we can fix that easily. Let's just try to defeat
this bus first and see if the death
event is working. Okay. Now we can defeat the bus. Yeah. Once the bus gets
defeated, it will stop. And it will stays on the scene and we can
get passed through him. We are going to also need
a couple of things here. I'm going to add new event, that event, and we are going
to expand our bus ship here, pen the second and basically
our It has a atom and on it enabled the shooter
child objects it starts shooting missiles But
the problem is if we destroy right away, if we destroy the second toured before it finished where is it? Sorry, not here. This is
wrong. I need to disable this. So if we destroy the second turret before
this finish moving, then when it finish moves, it will shoot
missile right away. We need to make sure that we
disable the auto move here. Let's just create new
and drag the turret R. Okay. And go to the automov and
set this to disabled. So by checking the togal box on the automov
enabled properties, and also direct the
tore the left turret and choose also the
same component, which tomo move and
check the toggle box. The next thing we need
is we need to modify our automov script. So
I'm going to open this. And what we want to do
is basically we start the coroutine here when
we trigger this move, but we need to make
sure that on disable, we need to stop all coroutines in this mono behavior component. So we need to run. So it
will stop this coroutine if somehow the tomove
components get disabled by this death event on our second ritive if
it gets disabled, then it will stop
coroutine and it will not invoke this move done, which is we have set on our tomove it will enable
the shooter moved. So this will cancel
out this action, and it will not
shoot any missile.
32. 32 Enemy Waves Integration: In this video, we are going to integrate the enemy waves into the scene and set up an activator for activating
the enemy waves. And now by expanding
the enemy waves, we want to enable the
enemy plane so we can see the child object instance
and its paths movement. And this is the curve that we have defined in the
previous video. And if we select
the world mover, you can see that we
have two box collider, one in front and
one on the rear. This is for and
disling the enemy. And here, I'm going to adjust the position
of the enemy wave. So it lies before the
activator collider, and we can just move
this back on the z axis, and this should be a
good starting position. I'm going to rearrange
the curve a bit. And now we want to disable
the enemy waves and then add a box collider to the
enemy waves game object. Okay. And for the box collidor, we want to offset the
position of the box collator. So in order to do that, we can just scrub
the z component on the center properties here, and by holding the left click mouse and dragging
on the z ladder, we can scrub the value and we can see the changes
in the editor. And this should be a good
position for the trigger. And basically, we want to
offset the box collidor so when the enemy activator
trigger this collider, it will enable this enemy here. So we can see that the enemy
will enter the screen. Otherwise, if it's too close
to the enemy game object, once the enemy gets activated, we will see that the enemy
planes appear out of nowhere. So we want to add this
offset to prevent that. And we need to also enable the trigger options under
the box Colder component. And then we need to also
add an activator script. And we want to add an entry on the enter screen
event and then direct the enim script to
this object slot here. And under the no
function drop down, we want to pick the my waves and then select the bull
enabled properties, and we want to activate
it by checking the box. And there are a couple
of things that we need to modify before
testing this out. So let's go to the SO Studio and open the enemy wave script. And basically, I want to change the yield return value to a longer value here inside
the check combo core routine. And for this, probably
we can just use the disabled after wait for
second object here. And basically disabled after is being set by the
remove after variable, and we have set this to
2 seconds by default, and this is quite
short actually. But if we go back
to unity and select the enemy waves here under
the enemy waves component. You see that we
have set the remove after value to 10 seconds. This is quite long, actually. So if we use the disable
wait for second object, then it will delay
the check combo for 10 seconds before
executing the code. Inside the check
combo C routine, we can just delete the
new wait for seconds and replace it with the
disabled after variable. And the thing is that
we are relying on the transform child count to check whether we kill
all of the enemy or not, and we need to also create a modification
on the death system. But now we can just
try this first. And now in order to test this, make sure that the
enemy game object or the child object of the
enemy wave is disabled, and we need to also
make sure that the enemy wave script component also disabled on the
enemy wave game object. And let's just save the
scene, and let's try this. Yeah, another thing
that we need to modify here, it's
the enemy plane. Make sure that the
max health is set to three because the
default value is ten, and with a health of ten, it's quite hard to
kill the enemy. So I decrease it to three
to make the test easier. So let's test this again
and let's just destroy this ground turn both
of the ground turret, and now you see that we have
the enemy waves entering. Let's just try to destroy
all of the enemy waves. And here, as you can see that we kill all of the enemy waves, but we still have the
chain loss message under the bug console. And here, because whenever
we kill the enemy plane, we are not destroying it, but we are just
disling it or we are returning the game object
back to the enemy pool. So the child count
never equals zero, and previously it works because we are destroying
the game object. And with the destroy changes,
it doesn't work anymore. So we need to modify
the enemy wave script. So we need to create
a slight modification in the death system script. And let's just add a new a public bullion on
the death system here, and I can just add it
beside the destroy bullion, and let's just call
this back to pull. And we want to set the
default value to true. And with this
bullion set to true, we don't need to change all of the other game objects that are using this de system script, and it will behave
like it should be. Whenever it gets destroyed, it will automatically
back to pool. But we can disable these options for the object that we want
to destroy right away. And here, inside the
if destroy statement, we want to add
another if statement, and we want to check for
the beg to pull value. If the beg to pull
value is true, then we want to execute
this return object, and we want to add
an L condition, that means that if the
beg to pull is false, then we want to
destroy the object right away using
the destroy method. We can just pass the game object keyword and also the duration, which is the destroy
after variables. Let's just save the script, and let's head back to unity. Once the script is compiled, if you select the
enemy plane here, you see that the
death system will have a new field
called B to pull. And it's enabled by default. And for the enemy plane, the child of the enemy waves.
We want to disable this. So whenever this plane or this game object gets destroyed, it will destroy right away, and it will remove itself from the child of
the enemy waves, and we can have the chain or the check combo
working as expected. And for other objects that are using the
death system such as bullet or the human rescue
or the ground turret, we can just leave the back to
pull options to be enabled. Now let's try this. Okay, now the enemy waves enters
and we can just destroy. And as you can see here, under the enemy waves, we
don't have any child left. And you see that in the console, we have the enemy
combo kill print out. So now the enemy wave
script works as expected. And now I'm going
to test this again, but this time, let's try
to not kill them all. So I'm just going to destroy one of them
and leave the other to finish their movement until they are all
gets disabled. As you can see here,
because we still have a child object under
the enemy waves. We have this chain loss
message on the console. And this is how we set up the
enemy waves in the level. And basically, if we want to create another
instance of it, we can just copy the enemy waves here and move it to
another position, and we can just readjust
the game object movement. And now we are done with integrating the enemy
waves into the level. And we can continue
to the next lesson.
33. 33 Laser Power Ups: Okay, so now in this video, we are going to create
the laser weapon. Yeah. Well, I've prepared
the art for the laser, and this is also included on the package for the
starting projects that you can download
on this course. And here we have
set this sprites to a multiple on the
Sprite mode and also the mesh type
to be full rec. So we can pile this using the nine slice features that
comes with the Unit 2017. Okay. So now let's go to the top view here,
go to the top view, and I'm going to
make sure that this is autographic for
a moment here. And I'm going to direct
this laser here. And I'm going to direct also
this game to be on top here. And for this laser game object. I'm going to create
a parent first, so this is our
laser game object, basically, and I'm going
to reset its value. And I'm going to parent
this laser zero sprites, and I'm going to rotate
the lasers underscore zero game object to 90 degrees or negative 90 degrees
on the x axis. So if I move this laser
here, we can see the art, and I'm going to rotate
the valley to 180 degrees, so we are going
to make sure that the rounded part is at the
bottom of the laser part here. Let's scale first, we are going to change
the do to sliced. And with this, we can
increase its size like this, go to the game view, and I'm going to We are going to move to the zero
on the z axis here. So we can approximate
the length of our laser. The length of our laser should be as long as our screen here. Yeah. Like this, it should be around 19 and it should be maybe around
two or two is too big. I think 1.25 should be good. Here we are going to change the material to sprite additive. Let's change the color to ranges a bit yellow
like this here. We are going to decrease
the alpha size, we can duplicate this laser and we can decrease it with
size on the sprite render, make it maybe run 0.6 here. Yeah. And increase the alpha value? Okay. We can also duplicate
this one again. But this time we are going
to make the width larger, but it will also have the
different sprite I'm going to pick the sprite
and we are going to choose the laser one here. I'm going to make
the size bigger. This should be the glowing edge, and I'm going to
decrease it alpha. It won't be that harsh, this can decrease
the value here also. This is somehow still
strong, I think. Let's use the tile version
of tile is good slice or I'm going to
change the value to the material to and increase color material should be this and lower the opacity. I think we should
use the additive, so I'm going to
choose the additive, but I'm just going to load
the alpha value here. Now we have this laser object. Basically, this laser object, if I set the fit. Our laser should be starting
from this point here. I'm going to move this axis, but I'm going to set
its value to 9.5. If we go to the laser here, start really at the beginning, make sure since
the length is 19, so I divide it by half
the z axis is 9.5. And we are going to add
a new particle system, where is it? This
is our particle. We want to create some sort of sparks from the starting here. So this should do the trick, and let's change
the view to three. I should do the direction
is already correct. We are going to change
No, it's emision. It should be emission,
but we are going to set the angle to
a wer value here, 45, for example, Lifetime, we are going to make
this very short around 0.17 75 seconds. And start speed. It should be a very high speed. But if we change the speed and we need
to lower the lifetime also make this we can
increase the emissions to 25. It's bursting. Raise here and let's
change its value, start color to also
arranges color here. But I'm going to
decrease its Okay. And another thing we should do is to enable
size over lifetime. So we want to make
sure that the particle is getting smaller,
like this. Yeah. And we want to go to the renderer and change it render mode to a
stretch billboard. So we have something like this. Okay. So we have bursting
effect like that. But let's change the angle to a larger value should do and let's just increase
the emission to 50. The last thing we need is to change its material
to something that is additive additive this circle. We need to create
a new material. So let's go to the material. And I'm going to go
to the explosion here and change and
create a new material. And this will be
the laser burst. And change the ser
birds material type to shader to the
particles additive, and I'm going to pick the
default particle here. Something like this. And let's drag this material to
our particle here. We have a smooth particle but
with an additive behavior, and we are going to
disable play on. But we are going to keep the looping options and just
set the duration to one. Okay. So I'm going to rename
the particle to stirs. Now we have this part laser. Now we want to parent this
laser to our game object here. Sorry, our player game object. Let's go direct to the
child of our game object. Let's zero out its position, and I'm going to
move this player. Our player is zero, zero, zero, I'm parenting this
to our player here. I think I'm going
to move this here. But actually, it's
align with our player. I don't know why
it's doing this, I'm going to move our laser
to be on front of our player. And the center. We need to add a box
glider to our laser here. Let's just add that box, a normal box glider
and set the trigger. I'm going to add also a a body, but this at body, we are going to set this to ischematic and
disable use gravity, so it won't do anything. Let's resize our glider, so it fits with our laser. And I'm going to drag this until at the end of our laser line there,
something like that. I'm going to save
the scene here. Now we need to create scripts to create the behavior that
we want to with this laser. Go to script on the weapons. I'm going to create a new script and let's call the
script laser script. Now let's open it script. I'm going to increase
the size first. I can see clearly. Now we need to create a
couple of variables and I've already provide
I'ady copy paste from the previous script and I'm going to paste this here. Basically, we need a
couple of float here. We have two float and basically, the first one is the
laser duration and how long the laser stays
whenever we shoot it and the animation speed and
this animation speed is for the scaling speed from
zero to the normal value, the scale to the Here, you can see the value of
one on the scale here. So we are going to scale the laser and we need
a bulon variable, and this is for a toggling whenever we are
shooting the laser and we want this bulon to be true. And for the last variable that we need to use is the
weight for second type. We are going to use
for orotine duration. Okay. Inside start, we are going to define our
coroutine laser duration, and this will be a new
weight for seconds, but the value we will get the value from
the laser duration. And safety and now
we are going to create a coroutine
for firing a laser. Let's just type able, but it should be enumerator and just call this
method fire laser. Whenever we are
firing the laser, we want to set the
laser fire true And we are going to loop the
scale of the laser, we are going to check
whenever the scale is already equal or greater than the target scale,
then we want to stop. So as long our
transform local scale. Magnitude or we can just
use square magnitude, which is more performance
is less than one, our target value, which
is one scale of one. We want to scale the
laser game object. We want to set a local scale to use the vector
tree move towards. The animation should be
linear or we can try using, see if this works better. I we can use the
moward we are going to transition from our local
scale to the target scale. The target sales should be
vector 31 and the speed will be our M speed
multiply by time time. And we're going to turn no. Before we want to scale this, we want to set the transform
local scale to a vector 30. Okay. And now we have this
animation scaling animation. Now we want to return I
think to laser duration. So if the laser
duration is three, then it will hold this state for 3 seconds and continue to the
next line here. And we want to make whenever we are we are out
of this loop here. This file loop, we want to
make sure that the scale of our object is vector 31. So we are snapping to one if the value is less or
more than vector 31. And we're going to compete
this line here after delaying the code for how many second of tin laser
door is being set up, we are going to paste
this while here and we want to make
sure that this should be greater than 0.01. If the square maggot is still greater than
zero, let's say zero, then we want to scale this
back to our zero value here. Switch the factor
one to zero here. And once it's finished, we want to set
this back to zero, and we want to set the
laser fire to false. Yeah. And now we need to create
an unrigger enter function. Let's just do that. Here, we are going to check if other compared tag is
or health tag of enemy, then we want to do damage
to this game object. Since we know that most of the enemy or all
of the enemy does have health system script attached to it, we
are going to create A temporary variable type of health system
and we are going to grab this from the
other get component, which is the class that we are
looking for health system. We are going to
make sure that if health is not or is true, then we are going
to take damage. Let's just take damage. For this example, let's just
set this value to 100 so is a very strong value here. Later we are going to
change this value. Now, since we already have this core routine
and this trigger, we need to trigger
on the update. For this testing purpose, we are going to use a keyboard, but later we are going to
create interface for it. For this case here, let's just use key down, and I'm going to use the
key code L for laser. I'm going to make sure that also fire laser, not the fire laser. Laser fire is false. Whenever the laser
file is false and if we press L on the keyboard, then we want to fire or start the fire
laser coroutine here. Okay. For starting the courtin
just like the usual rail, type start routine and type the method that
we want to run here, fire fire laser, fire
laser and say this. Now we can just put this
onto our laser game object. Laser script. And we are going to set its
scale value to zero. Okay. Let's say this
and let's just try. I'm going to move the ship here and let's try to fire
laser. There you go. We have laser firing and destroy all of
the game object that came encounter with our laser and is there any enemy left? Here. Okay. There is an enemy. I'm
going to fire laser again. There you go. For the animation, it doesn't look really good. Let's change the MP
to a higher value. Let's say ten and see
if this works better. Yeah. Okay, then. There you go. Yeah. This is our laser system. Sorry. One thing we
need to do is I forgot. We need to create a new particle
system, reference to it. Let's just create a system. This should be the
verse effects. Save this Inside our routine, whenever we start the laser, we want to particle effect here. Shore should be okay. Just type the verse effects, play Then here, just
stop the verse effects. Type the verse effect and stop. We are starting to
play here and start the animation stuff and then we want to stop the
particle effects. We also need to create another
private collider variable. And this will be call it. We need to grab this collider
because we need to disable the collider whenever
the laser is inactive, so we need to get the
component of collider first. And here inside
our core routine, on start, we want
you to disable it. So just type call that enabled, and this will set
the enabled status. And if we set this to false, it will disable it, and I'm
going to copy this line here. And let's paste this
here and set it t for at the end here,
we want to set it false. Okay. So this way, it won't accidentally kill any enemies that came in
contact with our collider. Even though probably
our scale is zero, but the collide it
will still be there, and it will destroy the
enemy unintentionally. So we need to disable
whenever we are not firing and only enable
when we are firing. And now we need to expand
our particle game object. And once the script is updated, we need to put the
game object into the dverse particle system slots here and save this again, and let's play it again and
see the effect that sorry, I pressed the wrong
keyboard and there you go. We have a verse effect in the front of our
particle system. Okay. And we are going to try to
shoot the other enemy here. Rescue first. Human rescued. Let's just try. Yeah. Okay. But we can shoot
limited numbers of laser, but we are going
to fix this later. Okay. I think that should do
for our lasership Of course, we are going to
modify this script later to have a limits and also a level of strength
depending on our laser upgrades. Okay, we can continue
on the next video.
34. 34 Mega Bomb Power Ups: Okay, so yeah, in this video, we are going to continue
our weapon system, and this time we
are going to create the mega bomb features. So, let's just start doing it. So now we are going
to go to our player. And here we have
the laser system, and I'm going to create
a new empty game object. And this time it will
be the mega bomb. So, The first thing we need to do is to
create a particle system. So I'm going to create
a new particle system, and this particle
system is going to be the child of
this megabom here, and we need to adjust
this particle system. First, we need to
change the emission, I think to zero, and we
are going to use a burst, and maybe the count set
to five would be enough. Also for the shape, we are going to change
this to a sphere, and I want to change the
radius to a very small radius. And the thickness also
to a very small one, 20. And so we have particles start emitting from
the middle here. And I want to disable
the speed also. So here, under our start
speed set this zero, so the particle doesn't move. It just stays If you can see there is a slight
glowing white things, that is a particle. Currently the lifetime
it sets to five. I want you to set this
to a very small value, and perhaps we can set
this to 2 seconds. And for the durations,
I'm going to also decrease the size
here around 2 seconds to maybe 3 seconds, so we can see the
blinking things. And let's set the start
size to a very big value. So if I go this from top here, I'm going to set the start
size to a very basically, I want to see our radius here, you can see here we have a grid and I want
to make sure that our basic particle has the size around two by
two from this grid here. Let's change the two to
four and or maybe two. Yeah, like this. And we will drive the start
size from the script, depending on how
strong our mega bom, but I think the starting
value four should be good. So yeah, we can use this. And now we are going to
create an animation. Uh I'm going to put the
particle below here. So if we see it from top. Yeah, it should be
below our ship, and now we can
create an animation. So I'm going to use this
size over lifetime. And with this size
over lifetime, we can create an animation
using curve like this. And now it starts from zero, the size to our maximum size, our start size that we
assign here, which is four. I'm going to change
this value to 02, so I'm going to select the nodes here and set the time to one, but the value to zero, so it will the curve
will look like this, and I'm going to
add new key here. And for this key here,
I'm going to set the time 20.5 and the value one. I'm going to adjust the
tangent that we have here. Something like this. So if we play this,
we can see that our bomb is the blast is
expanding and then shrinking. But I think life the age or the lifetime of
the particle is too slow, so I'm going to set this
to one, and let's see it. Okay, this is better. So now we are going to
disable the looping, so it doesn't loops and we want to disable also
the play on wake, and maybe we can
adjust the color, so. We can use gradient, I think,
let's just use gradient. For the gradient, we
want to start from a bright color and
fade right color. So if we play this. Okay. We This doesn't affect that. Let's just change
this petro color. The one we want to change is actually the color
over lifetime. I'm going to use
this or this one. I'm going to add a new
alpha in the middle. This top collor here is
actually the Alpha values, and the one the
below is the color. Here we are going
to set the Alpha 20 and add a new Alpha here
and set this 120 again. If we play this, we should have a nice fading effect like that. Of course, you can go crazy with the particle settings,
if you want to. It's not quite hard. Just
check out the parameters. But for this purpose,
we are going to use this settings here. And also, I'm going
to change the alpha, the base alpha to a lower
value, for example, 200. So we have a slight
transparency. Okay, something like that. Okay. So now let's
create the script. And I'm going to rename
this particle object. So let's create a
new CSO script, and let's call this mega script. And let's open this up. So basically, we need to
define a couple of variables and I'm going to paste the code that
I've already prepared. Basically, we need to
declare two float variables. The first one is the radius, and the second one is the
damage. And for the damage. Later, we are going to change this whenever we
are doing upgrades. Currently, we are going to
set this as a default value, which is two for the radius
and five for the damage. And the last variable
is a particle system, and we are going to hook our particle system into this variable slot
here in the inspector. And whenever we start, we want to adjust
the particle size. So this would be our
particle variable here, the Box, and this will
be the main rollout. So if I roll it like this, then it means that we are
accessing this main rollout. And if we want to access
the emission here, the emission rollout, we
need to type emission. And if we roll over,
you can see that the hit showing that we are accessing the particle
system emission model. So if we want to access
the color over a lifetime, then we are accessing the particle system color of
a lifetime modle we can put this module into a arbitrary
or a generic variable, just using the far keyword and particle main and
we can put it here. I'm going to access
the main and I'm going to change the size by accessing our newly created
variable in start, and here we have the start size. And the star size I'm going. Since we have I think
it's four by default. So I'm going to make sure
our radius we have the size of our radius multiplied
by our default value here. Oh I think or we can just get the I think we can get the value the constant. I think maybe we can
use this constant here. Basically, this will return
the value that we have now. Since we are using
constant, you can see here. If you're using curve,
we need to access the other properties
in the script, but we're using constant. Later, if we change the
default value here, it will get applied
to this line here. This will always follow
our particle size. Let's save this. Now I'm going to create a new public variable
called deploy bomb. And let's save this
particle first. Sorry. Let's save the script.
So what we want to do is basically we want you to
print out a debug first. So let's just put message bomb deployed
here under the print. And we are going to play
the particle effects. So I'm going to type the
particle variable here. We have on the
variable declaration and just type that play, so we are triggering the
particle two play one whenever this method
gets executed. And now we are going to
create a collider array. And let's name this colliders. And we are going to
use a physics method, which is the overlap spear. Overlap spell returns
an array with all the colliders
touching inside of the spear that
we declare here. So with overlap sphere method, we need to insert
our origin position, which is going to be
our ship position or this game object that we have this megabbscri since the game object is
attached to the player, so we can use the
position right away. And the next one is
going to be a radius. Now we have this
default radius of Q, and let's use that radius. But I think is very small
because this is in units. We can change this in
the inspector later. So this will grab all
of the game object that came or inside this
overlap sphere when we execute this code here. If the game object
have colliders and it is inside
our overlap sphere, it will be grabbed
by this array. And now we can loop the array. So I'm going to create
a four statement. And in case you
are not aware how to type the four statement right away automatically
like that, type four and press tap
twice in physical Studio, and I think it also works
for the moto develop. Tape press tap twice, and we have this default
four loop statement, and I'm going to lo
our colliders array, and we are going to access its member size by accessing
the length properties. So and Now, we are going to do all of the damage calculation
inside this loop here. First, we are going to create a new temporary health system. So let's just name
this health system, we are going to check if the
if one of the colliders, which is the index of, and we are going to look this value here from zero to the maximum
length of our colliders, we want to get the
component health system. Okay. And we want to check if
health system is not null, and we want to
make sure that our gliders that current index
have the tag of enemy. So if the game object it's an enemy and
it has the health system, then we want to do
damage to them, let's check the tag
that we have here for the enemy Enemy waves
and Enemy plane. Okay, sorry, we have this tag. So let's just set the
enemy plane to enemy, and I'm going to check the other ground
enemies that we have here. Okay. Most of them that
have box glider are currently set on tech. So I'm going to select all of the ground enemy and
change the tech to enemy. Or is there any other. Yeah, I think that should do. And for the bus, this is the activator
and the bus ship. Okay, so they should
have tags of enemy. The main bus. And for each of the tout that
has the collider, should also set as enemy and the second turret also
set this enemy. Yeah. Okay. This is the ship model and the base collidor is
in the bus ship object. Now we can apply damage to them. Just access the health
system and then take damage, and for the damage, we can
apply this damage value here. And we can create a
debugging system, which we can check
which one is getting hit by our bomb and
access the name and concatenate the string is being hit by the bomb. K. Save this. And now
we need to wait to trigger this bomb and right
now we can just use a input. But later, we are going
to create UI for this, just like the one in Sky Force. Press key down. And I'm going for sorry, for the key code, I'm going to use letter B on our keyboard to trigger this and just run the
deploy bomb here. Okay. Save this scrip,
and I'm going to delete this two library that we are not using to
make it more optimized. Let's go back to unity.
Now, if we expand the world mover again
and select our player, add the mega bobcrip to our mega bomb game
object child here. Add that and add
the bomb effects. But I think the reduce
is too small currently, so we can just change this probably I'm going to
check the grid here. Okay. Maybe five or one, two, three, four, five, six. Let's just set seven first, and for the damage, let's set this to a much
higher value, which is 25. Let's try this. Okay. Okay. I'm going to try to deploy them. As
you can see there. Okay. We destroy the enemy directly, but somehow our particle
doesn't change the size. The start size is changed to 28. So we actually should have a big as you can see on the scene, we have a very big,
but on the game view, we don't have a big explosion. So I think that is related
to the renderer here, and here we have the
maximum particle size 20.5, let's just change this
let's say Maybe one, and I'm going to move the
order on layer to 100. Okay, now we have a
much bigger particle, but still we cannot
cover the screen. So I'm going to increase
this max particle size. Let's say 24 and see how it works and we can spam
the bomb right now, this is much better,
as you can see here, if I deploy the bomb
again, we destroy Yeah. So I believe we need to increase the radius and also
the damage value. But yeah, we need
to destroy twice. And let's just check how many health do we have for
the ground enemy, the run. It's ten. Well,
maybe the first one, it doesn't come in contact
with our overlap sphere here. Okay, of course, we are
going to tweak this bomb later when we incorporate the UI menu for triggering
this bomb here. But yeah, I think they should do for our mega bomb system.
35. 35 Shield Power Ups: In this video, we are going
to work on the shield system, and we have created lasers and the megabm in the
previous video before. So now let's select the
player game object. And then let's create the
new empty game object by right clicking on
the player game object. And we can rename this
game object to shield. And for the shield game object, let's create a spear as a child object of this
shield game object. And now, as you can see, we have this white sphere in the
middle of our plane. And for the spear, let's change
the layer to air object, so it gets rendered on top. And if you set the
spear to default, you see that in the game few, the spear is rendered
below the plane, so we don't want that, and let's set the spear layer
back to a object. And next, we need to scale
the spear game object. And I test this before, so I'm going to set the scale 24 on all of the three axis. And then next, we want
to create a material. So inside the materials folder, let's create a new material. And let's just rename
the material to shield. And for the albedo or the color, we can select a texture, and I'm going to pick
a noise texture here. And let's apply this material to the spear game object by dragging to the game
object in the scene. And let's just adjust the
tiling to three by three. So we have a more smaller
noise on the game object. And let's change the rendering
mode to transparent. And then I want to also tint the color of the albedo
to light orange. And let's decrease the
alpha value to 75. We have a transparent material. Next, we want to enable
the emission option, and I'm going to change
the emission color to a darker ornge
something like this. I think this should do for the shield game object
and its material, next, we need to create the
script to handle the shield. Let's go to the script folder and go to the weapons folder, and let's create a
new shop script, and we can just call
it shield script. And then let's open the script. And inside this script, we need to declare a
couple of variables. And the first one will
be a type of float, and we can just call
it shield duration. And the next one will be a type of game object and we can just call it hit effects. And we are going to
put the sparks prefs under this hit effect
game object variable. And inside the start method, we want to scale the spear
game object into vector 30. So it gets hidden. So in order to do
that, let's just transform the local
scale equal vector 30. And vector 30 is a
shorthand version, and it returns value of zero, zero, zero on three
x y and z axis. And next, we can
create a new method, a public method with
return type of void, and we can just call
this shield up. And we are going to
use this method to activate the shield
using the UI later. And then we need to
create a core routine. So let's type enumerator, and we can just call
this engaged shield. And I'm going to pass a float parameter into
this core routine, and we can just
call it duration, and that will be the
duration for our shield. And inside the core routine, we need to create a
temporary float variable. And let's just call the
first one M duration, and let's just set
its value to 0.5. And we need to create
another one type of float, and we can call it
out M duration, and we can just set
the value to also 0.5. So we need both of
this value to create duration for scaling up
the shield animation and then scaling down the spear animation when
we activating the shield. And let's add a wild loop here. And with the condition, if in an duration is
greater than zero. So if we still have value left in the in
animation duration, then we are going to look
through this wild code. And basically, we need to create a three while loop here
inside the co routine. So let's just copy and paste it. And for the second
one, we want to change the condition to duration
greater than zero. On a second tout, for
the second while, we can just remove
this altogether and then using a yield return
new weight for a second, and then pass the duration. So this will hold the coroutine in seconds with
the value of the duration. But in order to optimize this, we can cash the wait for
seconds into a variable because we are going to use
this repeatedly over and over in the gameplay. So let's just add a
new private variable with type of wait for seconds. And we can just call
this shield delay. And in the start method, we need to initialize
this variable. So we can just type shield delay equal new weight for seconds and then pass the
shield duration value into this constructor. And this will be much more optimized and
less garbage collecting. And we can reuse this shield delay variable as the yield value
inside our co routine. And then inside the in
nim duration while, we want to substract the
in animation duration with the time delta time, so it will get substract
by one in every second, so we can create some
sort of a timer. And we need to insert a
yield return null here. Otherwise, it will
create an infinite loop, and we want to stop
the execution up to this point here and it
will loop the while. And if the condition inside
this while is false, then we will go to the
next line below here. It will execute the next
yield return shield delay. And then once the
shield delay is up, it will go to execute the
wi out named duration. So let's just copy the coat from the first will
into the second while. And for the second
while, we need to change the float variable to
the out named duration. So I'm going to
change both the one that inside the coat and
also on the condition. And next inside the while in
duration greater than zero, we want to scale the local
scale of the transform. And for the value, we can use the vector three class and
then use the b function. And for the vector A value, we can use the
previous local scale. So let's just type
transform that local scale. And then we want to
scale into a vector 31. So it will interpolate from the previous to a scale of one, and we want to scale
to the maximum size, and it's not four because the script will lies on
the shield game object, and as you can see
on the unity here, the shield game object has a scale value of one
instead of four. So we want to scale this shield object instead
of the spear game object. And for the interpolation value, we can just put some value. I'm going to put 0.1. And let's just copy this line here and paste it into
the second while. But in the second while, we want to change the target
vector or the vector be inside the function to be vector three dot zero. So
let's just change that. So it will scale the shield from previous value to a zero value, and it will create a
scaling down effect. And now we want to create a debug input inside
the update method. So let's just create
an if statement, and for the condition,
we can just use the input dot get key down. And for the key, I'm
going to use a key dot s, so we need to press the S
letter to trigger the shield. And inside this statement, we want to execute
the shield up method. And inside the shield up method, we want to call the co routine. So let's just type start
coroutine and then pass the engage shield coroutine inside this start
coroutine method. And we don't need this
flow duration anymore, so we can just remove the argument or the
parameter because we already used this
shield delay weight for second variable, so we don't need that
duration anymore. And next, we need to create an trigger enter method.
So let's create one. And then we want to
check the other object collider using
compared tag method. And if it's the enemy, and we want to add an R open and we want to
check for other tag here on the second condition. And for the tag, we want to change
it to enemy bullet. So basically, this shield will destroy both the enemy game
object and the bullet. So the player will be infeasible for a
certain amount of time. And inside the statement, we want to grab
the health system of the other game object. So let's create a new temporary variable type of health system, and if it's an enemy, then it will have this health
system attached to it. And we can just call this temporary
variable enemy health, and we need to get component
from the other object. So let's just type AGT component and set the
type two health system, and we want to check if this
variable is null or not. So by typing with
condition of enemy health, this will check if the
enemy health is not null, and we want to run
the enemy health take damage method and pass
a very big value. For this example, I'm going
to pass a value of thousand, so it will destroy
the enemy right away. On second thought, I'm going
to increase this to 10,000, and we want to add
an L condition, and on the L statement, we want to return
the game object into the pulling manager. So we can just use the
return object method from the pulling manager, and we can just pass the other game object
as an argument, and this will return the bullet right away to the pull manager. And we need to access
the game object because other is a
type of collider. And now we want to
generate the hat effect. So in order to do that, we can just copy the code
from the health system here. So let's just go to
the health system, and I'm going to
select this part of the code. And then copy it. And I'm going to paste
this code inside the n trigger before the
health system declaration. And it works right away. As you can see, we
don't have any error because we are using the same name for the hit effect variable
or game object pf this part that I highlight
is for calculating the hit effect position and also the direction based on the part of the context
of the collider, or the part where the enemy or the bullet contacts
the shield collider. And now let's save the script. And now let's head
back to unity and attach the shield script
into the shield game object. And let's just set the shield
duration to five for now. And for the hit effect, we can just browse
here and go to the At tab and pick
the sparks prefabs. And we want to add a spear collider in the
shield game object. So we can just delete the spear collider from
the child game object. So the child will only
handle the visualization, and we can disable both
of the cast shadows and the received shadow by setting the cast shadow to off and
uncheck the received shadow. And for the shield game object. Let's add a spear collider. But you can see here
in the sin view, the radius is smaller than
the pysalGame object. So we need to change
the radius to two, so it fits the
spear game object. And as you can see if
I increase the radius, it's larger than the
spear game object. Let's set this back to two, and we need to enable
the trigger option. But this will not trigger
the trigger enter method. And here on the
player game object, we have a rigid body
component attached to it. So this child collider
will be regarded as a collider of that
parent game object, which is the player. And this will cause issue
because whenever we activate the shield and we get hit
by a bullet or an enemy, then the health system on trigger enter will
get triggered and it will subtract our health right away with
this collider here. So in order to fix this, we need to add a rigid
body component to the shield game object and make sure that the use
gravity is disabled, and the kinematic
option is enabled, so it won't do any
dynamic calculation. And this will prevent
the player game object, register this collider
as its own collider. So this will behave as a separate or a
standalone collider, and it will only receive trigger from this
shield script. Okay. So now let's save the
scene, and let's try this. And as you can see
here, if we press S, it will enable the shield, and as you can see the bullet, the enemy bullet
cannot hit at all. And we also have this
knife spark effects outside or on the
shield surface. But there is an issue here. The shield never comes down. So let's top this. And let's go back to the shield script. And there is an
issue. I forgot to change the second
while condition, and we are still using
the in duration float. So let's change this to
the out duration float. And let's save the script, and let's get back to Unity, and let's test this again. And I'm going to press
S to enable the shield. And as you can see,
after five second, the shield goes away. But probably 5 seconds is a bit too long for the
lower tier shield. Okay. So basically,
the shield script, the shield duration
value will be changed depending on the upgrade
that we are using later. So we can upgrade to
a longer duration. But probably for starting point, we can just set this
to three second. And we also need to add a collider variable
on the shield script, and let's just call this call, and let's cache it on the start method
using get component, and we want to
enable and disable the collider based on
the shield engagement. So I start, we want to
disable the collider first using the
enabled properties and then set the value to false. And we can just copy the
line here and paste it on the start of the coroutine and on the start
of the coroutine, we can just set this to true And at the end of the routine, we can just paste this code here and then set the
value back to falls. So let's save the script. Because if we don't
disable the collider, even though the scale
of our shield is zero, we might accidentally destroy
the enemy because it will trigger take damage
to the enemy with a very large value
upon trigger enter. I have also add a code to force the local shield value to be zero before disling
the collider. This is to make sure the shield fiscal gets hidden after
the second while loop. In this part, we
are going to create a code so the enemy ships
can damage the player. So inside the script folder, go to the enemy scripts folder, and inside the Enemy
scripts folder. Let's create a new
C sharp script. And we can call
it damage player. And let's open the scripts. And this is actually quite
simple script to do. So let's just delete the
start and the update method, and let's declare a
new public integer and we can call it
the damage value. And this will hold the damage value that are going to be
applied to the player, and we need to create an
untrigger enter method. And we want to check if the other object
tag is the player, we can use the
compared tag method. And this script is going to be attached onto the
enemy ship object. And if the tag is indeed player, Then we want to grab the health system of
that player game object. So we can use the other dot get component and health
system for the type. And we want to run the
take damage method to apply the damage, and we can pass the
damage value that we declare here in the script. And we want to also
destroy the enemy ship, so we can just access the health system
script using get component and then run
the take damage method. And we can pass a large
value to make sure that the enemy will get destroyed on instant hit with the player. And we want to also
make sure that this untrigger enter
only happens once. So I'm going to create a new
private bullion variable, and we can just
call it destroyed. And we want to enable
the bullion to true whenever the
enemy hits the player. And on the beginning
of the method, we can add an if statement to check if the destroyed
bulon is true, then we can return the method. So if it's destroyed,
then the code below will never gets executed. This way, we are going to
make sure that the collision between the enemy and the
player only happens once. Now we can save the script, but we need to modify the
health system script. So let's open the
health system script. And basically, I'm
going to move all of the code related
to the hit effect inside the trigger enter, and I'm going to put this
inside the take damage method. So let's just copy
the line here and then paste it inside
the take damage method. And we will have an error
here as you can see that the collider is not
defined here inside the method. So we can just pass the collider as the parameter for the method. So let's just type collider. We can just call it, and now the take damage as for
another argument or parameter. So we need to pass the collider here inside the trigger enter. Now, we've modified
this code here, we can just remove the
hit effects related code inside the untrigger
enter and save the script. Another thing that we
want to do is we can just move the code
if it's not enemy. Let's just move the code
into the take damage method. And this line below here. We don't want to move it to
the take damage because we want to disable the bullet
that hits the game object. So this is for
disling the bullet. Otherwise, if we remove this
line to the take damage, then it will also
remove the enemy that hit us instantly using
the damage player script. So we don't want to
move this code here. Let's go back to unity, and let's just give it a try. And here in the console,
as you can see, we have a couple of
errors because there are some other scripts that relies on this take damage method, so we need to fix those code to add the collider argument. So let's just double click
on the error message. And here under the
damage player script, we can just pass the other collider to the
take damage method, and also for the second
take damage method, pass the other collider. And the other script
that we need to fix is the laser
and the megabum and the shield script because all of those scripts are calling
the take damage method. So let's just open
them one by one, and we can safely pass the other collider as an argument and don't forget to
save the script. And inside the megabom script, since it's not an
untrigger enter method, we can just pass the collider from the colliders array here. So we can just pass the
colliders array and then pass the index of
and save the script. And the last one is
the shield script. So let's just double click on the error message
and open the script. And we can just simply pass the other collider and
save the script. And basically, we need
those other collider to determine the sparks position
or the hit effx position. And in the health system, now the hit particles are generated inside
the take damage method. So back inside unit, we need to open the enemy waves and then select the enemy plane, and we need to add
the damage player scripts onto the enemy
plane game object. We need to define
the damage value, and I'm going to
set this to five. So that concludes the
shield system setup and we can continue
to the next video.
36. 36 Player Missile: So, in this video, we are going to create a missile
for our player. So yeah. For starter, we
are going to open the missile script here, so we can go to our
script folder weapons and open our missile
move script, and we are going to
modify the script here. So instead of using name player, we are going to
change the variable transform here to target. And before I'm going to
recite the script few. Yeah. So we have changed the
player variable to target, and we can just copy
this name here and paste this here and
also paste this here. Okay. And the next step would be we need to add
a bullion variable, and let's call this player. And this will be disabled or
will be false by default. And we need to add
a condition here. If player is true, then we want to search
for this tag here. We want to search this
tag here, and enable, we want to do a different thing, which we want to check
if player is false, then we want to find the enemy. Find the nearest enemy here. And to find a nearest enemy, we need to create a separate
function to do that. So under the routine
start follow here, I'm going to create a void. I'm going to create a new method and it will return
type transform, and we can call this
method find enemy. Okay, so this is a method that will return type transform. So we need to return something at the end of this code here. And first, we are going
to create a new array, a game object array,
array of game objects, and let's call this enemies, and we are going to use the game object class and a method from the
game object class, which is fine game
objects with tag and make sure that it has the
letter behind the object. So it means plural,
it's not singular, and we can search
for the tag enemy. Okay. So this is basically, we'll grab all of the objects in the scene that has tagged enemy, not only one object,
but many objects, and it will start those objects
into the enemies array. And the next we can sort
this array based on the distance between
the enemies and our missile that has
just been insaniated. So we need to use the system keyword in order
to use the sort function. So I'm going to add
this using system and we can create
using the array class. It has a sort function
and we can use this and there are
many ways to use this, as you can see, it
has 17 combination. But the one we want to
use is we want to put the array first that we want to modify,
which is the enemies. And then we are going to
use the keyword delegate. And this will grab the first
index and the next index. Sorry, the current index,
the current member, sorry, the current
index of member in the enemies and the next one. So since mis has
type of game object, we are going to use the
class of game object A and then ma game object B. So we are grabbing the
first and the next, and it will iterate to all of the members of our enemies
inside this game object. And after that, we can just press enter and open
a curly bracket. And here we can type return. So we will return
the nearest object by comparing its distance, so we can use the
factor three class, and then use the function, which is the method,
which is called distance, and we are going to compare our transform our
missile transform, which is transformed position, the position of our
missile and the position of our first game object,
the a game object. We are going to
check this. And this basically will return
a float value. And we need to compare
it to another member, which is the second one. So I'm going just to copy this code here and paste this
inside this compared to. But instead of comparing
to the A game object, we are going to compare
it to the game object B. So to make this easier to read, we can just press enter
on the dot compare. So we have two lines here. And I'm going to end
this with the semicln. So basically what this line is doing is we want to compare the position of the distance of the game object A
with our missile, and we want to compare
it with the distance between game object B
with our missile also. And whichever Oh, whichever this
method returns the smallest value
inflow in terms it means that it has the most
nearest distance between the enemy
object and our missile. It will return that one. So
it will shift that one to the first index and the second one to the
next index, and so forth. Whenever it tries to compare the next index with
the index after, I will sort and then it will
shift the position again. So it will keep
doing that until it finish iterating our mis array, and at the end, we will have the nearest
enemy at index zero. The first index will be the nearest one because
the first index will have the nearest distance, the lowest value in terms of float value that has been returned by the factor
three distance, and it will be shift
to the first position. Or need to close
this parenthesis since we have this curly bracket after this delegate here,
so we need to close it. And basically, after the
delegate, there is no coma. Make sure that there's
no coma in your code. Otherwise, it will give
it will throws an error. Yeah. After this delegate
to execute this code here. Okay, so now we have
this array, that sort. If we want to check
this, we can create a loop and we can loop
our enemies array. Dot length, so we want to grab how many enemies
we have currently grab. And then we can just print the distance from our
transform position, our missile position
to themes index of transform that position. Since the enemies
are give object, and we can print
and we can see that the first index will always
have the lowest value. And then, And after this, we need to return the first
member of our enemies. But since it returns
type of transform, it needs a type of
transform to be returned. We need to type
transform like this. And yeah, that should
do, and let's save this. And now we have this function. Basically, we don't
need this for loop. We just want to show
this in our console, but we can check
this application. Editor. So we can use
this bulon and we check, are we running
inside the editor? So once we build
this game later, this code won't be executed. So yeah. I'm just going to cut this for loop and
put it inside this. So we don't need to
disable it later. It will be disabled automatically by this
check here. I won't run. And once we have
this fine enemy, we can grab we can
copy this line here. But we're going to
change this enemy. And basically, we want
to make sure that if our scene have at
least one object that have tags of enemy. If we have this, we want to
return, get the nearest one. Since we already create
a method to do that, we just need to run the method. And because this method
returns type of transform, I can put it assigned
this to a variable. So whatever this method return, it will be set to this target variable
that we have here. Okay. So yeah. Now we
have changed this. We need to go to
our prefix folder. And sorry prefix folder and
under the weapons foolder. I'm going to duplicate
our missile game object. But this one is the my missile, so I'm going to rename
this to player missile. And I'm going to change the
tag to the normal bullet, so it will hit the enemy, hit us, not hit the player. And for the missile move script, I'm going to check
the player bulon. So this will differentiate
the behavior. This one is for
the enemy missile, and we need just to
disable the player. And this one is for,
for the player missile. And perhaps we need to
create a new weapon profile. So I'm going to duplicate the player level
two, but this one, I'm going to rename
this level two missile and just add a suffix of one. So probably this is probably
for the missile level one. And yeah, for the speed, I'm going to change
this to eight because as you can see here, in the bus meselt
or the enemy mette, we have speed of low speed. So missile should
have a low speed, but a greater damage. So for the damage, I'm going
to increase it to five. And the interval, I'm going
to make this not too often, so I'm going to make
this every 3 seconds. And for the resto rate, six would be enough. I think Okay. We have plenty of time to make sure
that this missile is going out frame and
then it destroys itself. For the spread, I'm
going to set this 20, and for am I'm going
to set this 21. Okay. And we can create different profiles for this
later for upgrade system. And also, we are going to set our player to
shoot this missile, we need to use the
Auto shoot script add the shoot script. Okay. And for the shoot profile, we can direct this
player missile. And for the bullet
prehep we can use the players prehep
that we have created. And for the fire point, we can just direct the
shoot point here. And now we have this
missile shooting. One thing we need
to make sure is whenever we destroy an enemy, the object or the game object
is not always destroyed, but it is left on
the scene and we add some particle
burning particles to create a enemy's effect, and that will cause
an issue because our new missile will
always consider that as an enemy because it
has tags of enemy. So we need to change a couple of things under
the health system. So under the health system, sorry, I've already
tried this before. What we need to do is
we need to check if the health system belongs
to the game object, then we need to change it text whenever
it gets destroyed. And basically, this
function here only gets executed if
the current health is zero or less than zero. So it means the enemy
has been destroyed. So whenever the enemy
has been destroyed, we want to change the game
tag to something else, and we can use maybe the tag. And this is case sensitive. So we need to make
sure that what we have type here is correct. So let's go back to unity, and I'm going to choose another object and
take as you can see, we have a capital U, and the rest is a
lower case, yeah. Save this and a thing
that should do. So let's just try this first. Okay. To try this,
I'm going to disable our default bullet
here, the auto shoot. So it will only shoot the missile, so we
can test this out. And I'm going to expand
our ground enemies, and I want you to
select this one here. And I want to see the t does the tag change
whenever we destroy this? So let's just try this. Okay. Okay, sorry. There
is an issue here. I forgot to put the game the game object in
our polling system. So, we need to add this. So basically, less setting of our polling
measure is like this. And whenever we
create a new item, I need to put the item
in the pooling measure. So I'm going to
expand the size here. Maybe for the pull
amount, I don't need that many missile, so I'm going to set this to ten, and for the game
object, we can go to our assets and choose the
player missile, where is it? Ah, there you go.
This is Player Mel. Let's save the scene, and
let's try this again. Yeah, there you go.
We have this enemy. But it doesn't. I think there's some issue here. Okay. It gets the nearest one, but we need to check, it has tags of enemy and enemy. Let's check our code here
under the missile move here. So, basically, we are
collecting our enemies and we are sing and we are
getting the nearest one. Okay, so if it's not player. Oh, sorry. This is where we're
wrong, where we are wrong. For the default one,
for the start one, we need to make sure
that this is not player because if the missile
are searching the player, then this is belonged
to the enemy and if the missile are searching for the enemy, this
belong to the player. So we need to make sure that the player is true
in this case here. Okay. I got that mixed up, and let's try this again. Yeah, there you go. It
destroyed the first one. And if it will try to follow that shipping.
Okay, I got destroyed. Let's try this again. Okay, yeah, maybe the rotation
speed is too slow, so that's why it's having a
hard time to hit our enemy. Okay. At a certain distance, it can hit our enemy. And it still find
the nearest one, and now it tried to
destroy that one. Okay. So as you can see, we have a very nice
working missile system. And to fix that rotation thing, we can go to our prefs and go to the weapons folder and
under the player missile, we can increase the rotate speed so we can also increase the follow
duration to 1.5 seconds. And for the rotation speed, let's set this 25
and test this out, see if we will
behave better. Yeah. Yeah, it hits the enemy, and it's followed
the nearest one. As you can see, before
we have this plane, it hits this thred
but once we have this enemy waves,
it hits that one. So it will always grabs
the nearest enemy. Yeah. Okay, so, there you go. We have a player missile system, and of course we can
extend this one later. We need to also include this
in the upgrade system later. Okay. Okay
37. 37 Level Manager: In this video, we are going to create a level
manager script. The script will
keep track all of the achievement on the
current session of the level. So the script will
count the enemy kill, also the number of human rescue. So at the end of the gameplay, the script will be
able to evaluate those values and unlock the
achievement accordingly. Now, let's open the
scripts folder. Inside the folder, let's
create a new folder. And we're going to call
this data scripts. Inside the new folder, let's create a new script
and call it level manager. Now let's open a script. First, I'm going to declare a static variable to be used as a static reference to make this script easier to be
accessed from other scripts. And since there will be only one instance of the
script in the scene, this makes the script suitable for using aesthetic reference. Let's mark it static. For a type, let's
type level manager, and let's just call it instance. And let's initialize
it inside wake. So I'm going to declare
the awake method. We can initialize it by passing this keyword to
the instance variable. This will make sure
the script occupy the static reference so other scripts can have access
to the script right away. Next, I'm going to create a custom serializable class to hold or contains
the achievement data. So let's set up here outside
the level manager class, and let's call it metals. We will also need to add a
serializable attribute so the values of this class can be serialized and shown
in the inspector, and we can add it by accessing
the system name space. Since this class is
just for holding data, we don't need to inherit
from mono behavior. So let's declare a couple
of public bullion variable. For the first one, I'm
going to call it rescue. And then keel and the last
one will be untouched. And now we can
instantiate this class as a variable inside the
level manager script. So let's declare it here
with a public scope, and let's just call it
metals with lower case, and to initialize it, we can type equal
new metal keyword and then open and
enclosed parentheses. Now, if we save the script
and head back to unity, let's create a new
empty game object, reset its transform, and I'm going to reorder the hierarchy. So this new game object stack
below the pulling manager. Let's also rename the game
object into level manager. And next, let's attach the
level manager scripts to it. Once it's attached,
we will be able to see the three bullions from the middle class
filled on the inspector. And this is possible because we have declared the bullions
inside the middle class. So whenever the class are being declared as a variable
on other script, we will be able to see it in the inspector because this
realizable attribute. Next, let's delete the start
and the update method, and then we will also need to declare a couple of
integer variables. I'm going to call it
total enemy enemy killed. Total rescue and human rescue. Next, we need to create a new public method
with a return of void, let's just call it
register Enemy. Add another one method for
registering the human rescue. Another one called at
my keel for counting the Enemy keel and also another one called Ad rescue for counting
the human rescue. Inside the registered
enemy method, we want to increment the
total enemy variable, and I'm going to also
change the names of the variables to start with a lower case letter for
the sake of convention. And for the register
rescue method, we need to increment the
total rescue variable. For both at my kel
and add rescue, we need to add or
increment both of the enemy kel and the human rescue
variables respectively. And with all the variables calculated throughout
the gameplay, we can compare it at the
end of the level and unlock the related achievement
based on that comparison. And then we need to also
create a new public method. And I'm going to call it game. And before defining this method, we need to create a
co routine first. So let's create one by typing enumerator and
call it count delay. And in the beginning
of the core routine, I'm going to delay the
code using yield return, wait for seconds, and
delay it by 0.25 seconds. After the delay, let's
first compare if the enemy killed value is equal
to the total enemy value. And if it is, then we want to set the kill bullion on the metals variable to true. And next, we want to check if the human rescue is also
equal to the total rescue. And if it is, then we
want to set the value of the rescue bullion on the
metals variable to true. And we need to create
another public method for detecting whenever
the player got hit, and we can call it
player hit. Okay. Inside the method,
we need to set the untouched Bullen values from the metals
variable to false. So in order to unlock
this achievement, the player should not go
hit throughout the level. For untouched, we need to set its value to true on the
beginning of the level, so we can just set its value
inside the awake method. So the default
value will be true. But once the player got hit, it will become false right away. Next, we want to
run the count delay co routine from inside
the game method. So let's type start co routine
to execute a co routine and pass the coroutine name and also a sets of parentheses. Another thing I want to
add is an Unity event. But before using it,
we need to import the Unity engine event namespace here above.
So let's just do that. And let's declare
a public variable with a type of unity event. And let's just call it on game. We want to invoke this unity
event whenever the game. So let's add it inside the co routine by calling
the invoke method. This way, we can add custom
actions from other classes or objects that we want to
invoke via the inspector, similar to the onclick event
under the button component. So now let's save the script. Next, we need to modify
the health system. Basically, we need to register an enemy whenever the
start method gets invoked. So let's call the register
enemy method from the level manager script by assessing its static
reference like so. Hi, this is Rome
from the future. It seems as of currently, this code will cause
an issue because the health system
script is being used by both player and enemies. The total number of
enemies on the scene will always be the real
number of enemies plus one. Since the player will also
register as an enemy on start. And we can easily fix this because we have
declared a bullion to mark whether the
health system is attached to an enemy or not. Using this bullion,
we can add an I check before running the
registered enemy method. So let's add if open parentheses is enemy
and close parentheses. Then we want to run the
registered enemy method. Next, inside the
check health method, whenever the enemy is defeated, we want to call the add
enemy kill method from the level manager script to
record the enemy k value. So let's modify the enemy is true blog and call the method
inside this if statement. This way, the enemy
kill variable, and the total enemy will have a certain values at
the end of the level. So when calculating the result, we can unlock the
kill achievement by comparing both of this value. And next, we want to register the total amount human
that needs to be rescue and also the amount
human that has been rescued. So let's open the
human rescue script, and we want to trigger the register rescue method
on the start method and call the AD rescue method whenever the human gets
rescued by the player. And it seems we need to
define the start method here. So let's just create the method and we can call the
register rescue method by accessing the level
manager instance and then call the method. And once the rescue
time is finished here, inside the core routine, we can call the
add rescue method. So let's add the
method and we can add it above the
unrescue invoke line. This way, we can also compare
the human rescue with the total human on the
scene at the end of the level to unlock the
human rescue achievement. I've noticed a bug
during testing where the timer continues even if
the player gets destroyed. So we need to check if the player has been
destroyed or not. We can do that by creating a private variable type of game object for grabbing
the player game object. And inside the start method, let's check if there is any game object with
the tag of player. Then we want to grab
that game object and cash it into the
player variable. And next, inside the
rescue co routine, inside the while statement, when the time is still
greater than zero, we want to check if the
player is null or not. And if it is, then we
want to stop the co routine and set the timer
UI fill amount to zero. This way, as soon the
player gets destroyed, it will stop the timer
and clear the timer UI. Another thing that
we need to set up is for the
untouched achievement. So going back to
the health system inside the untrigger
enter method, whenever the script owner
get hits by a bullet, we want to add a check
if this is a player. By checking if the
enemy value is false. Using the shorthand version, then we can call the player hit method from
the level manager. This will disable the
untouched achievement as soon when the player
get hits by a bullet. Let's save the script, and
let's head back to unity. And if we select the level
manager game object, you'll see we have a couple of new integer fields as well as
a new game and unity event. And let's test this again. As soon as we enter
the play mood, you'll see the total enemy
and the total rescue values change depending
on the amount of the enemies and human
rescue on the scene. It seems my plan gets destroyed, so I'm going to
replay this again. Now we have killed one enemy. And I missed killing all
of these enemy waves. But it's okay. And I've
destroyed another enemy. And if we inspect the inspector, we have total seven enemies, and we have killed
five enemies so far. And we need to call
the game and method inside the afo managers script whenever we killed the boss. And let's try to
rescue the human. And once we have
rescued the human, the human rescue
variable increase. And let's check a couple of things before
we finish this up. First, we need to
make sure to run the game method from the
level manager script whenever we have killed the bus. And to do this, let's select the bus ship object on the
scene under the bus activator. If you remember, the bus object consists of a couple of parts. And on the main game object, we can see the collider
is disabled when it first appeared because we need to
destroy the turrets first. So when we destroy
the first turret, it will activate the
second turret collider. So we can destroy it, and
after it gets destroyed, it will activate the
main body collider. So to run the game method, we can add a new entry
on the death event field under the death
system component of the B ship game object. Next, let's drag the
level manager game object into the new entry object, and then let's run the
method by going to the level manager component on the drop down and select game. This will trigger the method whenever the bus
ship is defeated. Now before we test this, let's select the player game object. And enable the shooting
script, the default bullet, and don't forget to
highlight the level manager, so we can see the value
changes for the achievement. And as of now, there is
a bug where the enemy killed is currently
much bigger than the total enemy. But it's okay. We will take a look at it in a moment and let's
fast forward to the boss Now we have
killed the boss, but because of this bug and we didn't achieve
the other medals, none of them gets activated. So let's fix this. So in
the level manager script, instead of comparing the
value with an equal comparer, let's change it to a greater or equal to be on the safe side. Back to unity. Let's
give it one more try, and I'm going to fast
forward the video. And for the enemy
killed value bug, we need to add a check if the enemy is already
been destroyed. I need to also readjust the human rescue position so we can rescue it before
engaging the bus. Now we have defeated the bus, and as you can see, we have unlocked the
kill achievement. I'm going to past the game. Then highlight and
focus to the player. And as you can see the plane got hit somewhere in the level. And if we check
the level manager, we have failed to get the untouched achievement
because of this. Another thing that we need
to do is to also invoke the level manager game
method when the player dies. So if we select the player, let's add a new entry on
the death event field under the death system and direct the level manager game
object to the object slot. And under the drop down menu, select level manager and
select the game method, just like what we did
with the box ship. This way, whenever the player
win or lose the level, the game gets invoked
and the player can go back to the menu or
level selection screen. To fix the box issue
where the enemy killed value gets much
bigger than the total enemy, we need to make sure that the add enemy kill
method only gets executed once when
the enemy killed. So inside the health
system script, we need to add a
bullion variable that will act as a safeguard
for this issue. Let's just call it
that. And inside the check health method
under the if is enemy block. Let's add a second condition
for the statement with operator and check for if the dead bullion
value is false. So the code inside
this I will only gets executed if both of
the conditions are true. And let's set the
dead bullion to true. This will prevent
the bullet collision to trigger this
part of the code, and thus we'll make sure the ad enemy kill
only called once.
38. 38 Stats & Upgrades part 1: Okay, so now we have done the level
manager on the last video. And now we are going to create the stats manager or the
upgrade system and how we are going to handle the ability of our play in shooters such as
health and maybe the laser, shield, mega bom, and stuff. So I've created a small
presentation here. Let me just show you Okay, so now we are going to create a stat manager
component or a class. And this tax manager, it will handle item profiles. So we will create some sort
of list that will hold the data for weapons
weapons in each level. And in this project, we are going to
create five levels of weapons and also five levels of missile and then five level of health and five
level of shield, five level of laser, and the last is five
level of megabon. And this tech manager will also handle safe loading stuff, and we are going to
use binary formatter. So it's going to be a very versatile
technique compared to player preps
and you'll see y. And also after this tax manager, we also handle or manage
the upgrade item. So upgrade item is basically
a component that will be attached to a item
to be upgraded. It's going to be a UI prefs this will handle the upgrading
system, the weighting system. And stats manager will
only provide data after it's finished updated
or whenever we load, it will load the profiles
that we needed or sorry, the profiles that we have
saved in the previous session. So yeah that's more or less
about the stats manager, and let's jump to unity. Okay. So now in unity, I'm going to create
first a new scene, and this will be our menu scene. So let's just save
the scene here, save scene and go to
our scenes folder, and this will be the menu. Now in this menu here, we
are going to create a UI, and for the UI, I'm going
to create a tax object. And if we go to view,
we can see the UI here. Now we need to change the va scalar under the
canvas object to a scale with screen size and make
sure it sets to a ratio of nine by 16, so we can just insert
900 by 1,600 like this, and we want to match the height The next thing we need to do
is to modify the text here. Let's just select this. And if we go to our game view, we can see the text object, but it is very small, so we can increase the size. So, if we select the text here, we can see it has
width and height. So I'm going to do that
to change this value, maybe to ru 300 and
for the height, I'm going to make this 90. And I'm going to position
this on the top left of our canvas screen here
sorry, top left top right. In order to do that, we can just access this anchor presets, and by holding keyword
on the keyword, we are changing the anchor and the position of the object. If we release the alt, it will only change the anchor. And as you can see, the object stays in the middle
here, the icon, and if I press alt, it shows that the model snap to the edge of this anchor here. I'm going to choose
this one and it will snap our text here. And this will be
the money display. So I'm going to rename
this to money display. And for the money
display, I'm going to change the color
here to an orange. For example, like this one. And if we want to
save this, we can just press the preset here at new preset and we have
this orange color. So we can just select this. And for later UI, we can just select this color from the
presets right away, so it will have the same
values as our tax here. And we want to change the f
I've included the f here, a visitor f. So whenever you import the SA project, it
will have this f here. So let's use this, and I'm
going to enable the best fit. I'm going to set
the maximum size to around 80 and the minimum
size to around 50. Sorry, we need to
change this one. I'm going to change
the phone size to 60 and the minimum size to 50. So I will have ranged 50-80. And if we see it on the game view, we can
see that we have this. And we can just
align the text to middle and also
justify to middle. And I'm going to add a offset. So I'm going to
choose this move for the rectangle tool
or for the UI or the sprite and I'm going to move this slightly off
from the screen. So we have distance between
the text and the edges. It's not Okay. Now I'm going to set this
value to zero, zero, 00. So this will be our money. Okay, so now we have done this. We are going to create
a couple script. But the first one, it will
be our stats manager. So let's create a Cb script, and this will be stats manager. And this video, upgrades system, it will be breakdown of two
couple videos because there are a lot of topics
that we need to cover. Okay. So first thing,
first, stats manager, this will be a static, and it will persist
from scene to scene. So we need to create a Singleton method
Singleton pattern. And I'm going to create
a static variable, and this will be the type of statch manager, which
is our class here. And I'm going to give
it a name of incense. And I'm going to create
a void wake method. And inside this void, I want to check if the
instance variable is null. So for example, if it's null, then we want you to
destroy this one. Destroy this game object. Oh, sorry, not destroyed. We want to assign this. Sorry. We want to assign the instance to
this script here. So if there are no other
stats manager component that have claimed this
instance keyword, then we want to set
this instance keyword to our this component here. We want to claim it, and we want to mark this object to
don't destroy on note. So this game object will not be destroyed if we change scenes. And if that new scenes have another game object
that has stats manager, then this won't be true, and we want to execute the
other block of code here. So if instance is already claimed as in L's
condition here, then we want to destroy this
game object right away. So this pattern will make sure that the game object that has the status manager
component on the scene, will always be one, always only be one in the scene. So there will be no
more than one instance of stat manager in the scene. So let's just add a comment. This is Singleton pattern.
The initialization. Okay. And the next thing we need to do is we need to create a couple of custom classes just like
the one we've created, I think in the level
manager, this metals here. So, let's just do
the custom classes. First, we want to
create a public void and this will be the stats info. And this class here, it will hold an upgrade info for each stats that
we have saved, and this will consist
of name Okay, yeah, we need a string name, and we also need an integer. I think I made a mistake here, it should not be a public void, but it should be a public class, so we are creating
a custom class. And this will be our level. And this will be
array of float This will be the upgrade
time that we define. The other thing we need to
do is we need to create a class for our mega bomb. So this will all
be serializable. And this will be the mega data. And I'm going to duplicate
this a couple of times. And this will be the shield
data and the laser data. Now we need to check
out our megab data. So let's go with Megabuscrip and it has radius and damage. We want to change this value
here whenever we upgrade it, so let's create a compatible
variable copy this. Yeah, and we can just
remove the default value. So we are going to save
and load this data. And for the laser, we
have the laser duration, and probably we want to create. But I think laser duration
should be enough, so I'm going to just
to copy it this. And for the shield, where
is the shield component. For the shield that we have
is the shield duration. So let's just copy it this.
And put it here. Yeah. Now we have this data. The other thing we need is
the health and the weapon. Weapon, it's going to be
our scriptable object. Both for the weapons, the
normal bullet and the missile bullet's going to use the scriptable object that
we have created before. Now let's create an entry
for our update system. This basically is going
to be a list of a, I think we had shoot profile
this is the standard Sorry. Standard blaster, standard blaster list or
yeah, standard laser list. And we're going to declare this. The second one is going
to be our missile. This is also a shot profile, but this will be our missile
list missile upgrade list. And the third one is going
to be a list of float and this would be our
health health upgrade list. I'm going to change
this to blaster list, and this will be a
missile upgrades it's much clearer when we see the name and this
will be type float, another three of them,
it will be the list of I think this can be the
megaba Mega UPG list, abbreviation from
upgrade this thing here, it's going to be a
list of Sid sorry, Shield dad UPG list. And the last list would be our laser and this would
be the UP upgrade list. And we need to create a
couple of dictionary. Dictionary is basically some
sort of list, but with list, when we want to access
one of the member, we need to access by
its index number. With dictionary, we will access each of the
member by its key. So it's have two values, basically a key and a value. And this key can be anything, and the value can
also be anything. So for example, I'm going
to create the dictionary. And for the key here, I'm going to type string, and for the value,
it's going to be the metal data
that we have here. Let's say let's call this achievement list
and type new dictionary. So why I use strings? Because I want to
save the scene name. Whenever we are
saving the metals, we are going to use the
scene name as its keys. So whenever we want to
load the metals data, we can just refer it by the
current scene that we are on. And it will be much
clearer when we come to utilizing when we come to defining declaring or doing
the achievement later. The other thing we need to
do is we need to create a dictionary of type string, and this would be
type date time. But we don't have that
because we haven't set using the system
keyword here, so we need to add
this using system, and now we can use the class, and this would be the
stats grade time. Or we can use a better name. Yeah, this should be timer. And whenever we do upgrades, we want to set the finished time inside this day time value here, and string will be the name of the item that we are upgrading. Okay, let's just declare
the new dictionary. Yeah.
39. 39 Stats & Upgrades part 2: Let's continue working on
the status Manager script. And inside the script,
I have deleted the update method since we
are not going to be using it. And I've also created a new
empty game object called Game Manager in the scene and attach the status
Manager scripts onto it. And as you can see, we have a couple of array
or less variables in the inspector here based on what we have
declared in the script. And I have also populate the fields with the
related scriptable object. For example, I've populated the blaster profile with
the shoot profile I've created here in the
project ranging from the first level up
to the highest level. Feel free to define
your own profile, and if you haven't, please
pause the video and do so now. Also, don't forget to make
sure the profile gets stronger or better on
each level increments. I have also prepared the
profiles for the missile weapon. Once we have prepared
all of the profiles, we can just start populating the fields on the
status manager script. A tip when doing this is
to lock the inspector by clicking the lock icon on the top right of the inspector. This way, the inspector will not lose focus on the
status manager. For the health upgrade list, because the type is
a list of float, we can just fill
each health tier with a number value right away. Feel free to customize
the value to your liking. And for the megabum
upgrade list, on each tier entry, we have two values,
a radius and damage. For the first one, probably
would be best to set it with the default value of the
megabum which are seven and 25. I've memorized those value
from the gameplay scene. For the first radius, instead of seven, I'm going to use a smaller value instead. I think four would be good. A seven would be too powerful, and it is more suitable
for the higher tier ones. So for the radius on next tier, I'm going to set it in
order with the values of five, six, seven, eight. As for the damages, I'm going
to increase it by five, so it should be 30, 35, 40, 45, and I'm going to collapse all of the other
properties that has been set, so we have a much tightier few. And now let's set up the
shield upgrade values. I'm going to set the first
one to three and then four, five, six, and seven. Unless, we need to assign
values to the laser upgrade. And I'm going to set it with the values similar to
the shield duration, so it should be three, four, five, six, seven. And if the values are
not well balanced, we can always adjust it later. And here, if we take a look
at the status manager script, the last two
dictionary variables is not visible on the inspector, because currently Unity unable
to display this data type. But we can still
erilize it and save it to this later for
saving the progress. Now, let's continue working
on the status manager. Next, we need to declare a new public variable
with a type of integer, and this will be used as
the lives or tries counter, and I'm going to set the
default value to five. Then we also need to declare a new public integer variable
for the in game money. And we need to create
a public method to add or modify the amount
of money the player have. So here below, I'm going
to define one with the scope of public and
return type of void, and let's call it add money. We want to pass an
integer as the parameter, and we can call it value. Inside the method,
we want to modify the money variable value by incrementing with the
parameter name value. And we can pass a negative value if we want to
substract the money. And below, I'm going to add a command for a
two do task later when we have implemented
the money display UI for updating the money UI. And we need to also update
the coin pick up script. And if we open the script, we can see that we have this to do notes from
the earlier lesson. Now that we have implemented
the method to add money. Let's update this script by accessing status
Manager dot instance My method and pass
one as its argument. And back to the status
Manager script, we need to create a new
variable with the type of stats upgrade info that we
have declared here below. But before that,
I'm going to add a header attribute so we can organize the inspector
a little bit better. And I'm going to call the
group upgrade options. And below here, let's
add another header, and let's just call it
upgrade timer Data. And create the
variable with the type of list of stats upgrade info. Let's call it stats. As usual with list, we need to initialize
it like so. Now, if we go back to Unity, after the scripts gets compiled, we can update the inspector. Let's set up the
upgrade timer data because we have six items
that can be upgraded. Let's set the size of
the stats to also six, and I'm going to also rename
the first one to Blaster. The level will be the current
player blasters level. And then for the upgrade time, let's set the size 25 to accommodate the
tiers of the upgrades, and we can set the highest tier to be the longest upgrade. In this case, I'm going
to set it to ten, and the weaker ones
should be faster. So let's set it to eight, six, four, and then two. And we want to also
set the base level 21. The next one would
be the missile, and we want to also
set the base level 21. And let's set the
upgrade time size 25, and we can just set it the
same as the blaster values, which are two, four, six, eight, and ten. Okay. Onto the next one, this one is for the health. So let's just call it so. And on a second though, since we are going to use
the same values for now, let's just set the
size of the stats here on the top to two and
then set it back to six. This way, the new entries will copies values from
the missile entries, and then we need to
only rename the names. So the next one will be the, the one after will be mega bom. And then shield, And then
the last one would be laser. So these fields
are going to hold the upgrade Typer values for
each of the upgradables. And these values are going to be used by the upgrade
item object later. I'm going to collect all of the fields and save both
the scene and the project, just to be on the safe side. Now, let's go back to the
stat managers script, and here we need to create
a couple more methods. The first one would be a
method for getting the stats. So let's just type public
and returns a generics, usually written with P. Generic means it's a
parameterized types. So using generics, this method can returns
different data types, similar to get component usage. And we can call the
method get stats value. We will need two parameters. The first one will
be a type of string, and let's just
call it stat name, and the second one will be a
list of type generics or T, and let's just call
it stats list. This is going to be the list of the stats that are going
to be searched through. There is an error
because we need to add a generic signature to the
GT stats value method. So let's add one using an angled bracket and then type t. This should
fix the error. So this method can be used with a similar fashion
to get component. And here, if we take a look, the get component method here are searching a rigid
body component, but the signature can be any
other class or component. Get stats value will be used
exactly like get component, and we can also insert a list of different types as the
stat list parameter. Since we are also
using generics there, so we can search through
from many lists here, such as shoot profile, mega Bom data, or other list. Inside the method, we want
to create a four loop first, and we want to look through
the stat list here. And to access the length, since this is a list, we can use the co property. So let's just type
stats do co. Next, we want to check if the name
of the stats member index of I is equal to the string
that we've searched for. That is passed as
an argument here. If it's equal, then we can
use the level value as the index of the statls member that we want to return
to this method. Let's type return and then stat. The list we pass as second argument and use the
status level as the index. But we need to
substract it by one. Be collection, be
it list or array, it starts from zero. But the level values
starts from one. The method still gives an error
because inside this code, not all of the outcomes
return something. So we need to make sure
it returns something, even though the stats name was not found from
the stats list. So to fix this, we can put a code outside the four
loop here and we can return a default value of t.
We need to return with a default value because not all of object or data
types are nullable, and because this is a generic. Next, let's create
another method for getting the upgrade
time of an upgradable. Let's set it to public, and then it should
return array of fluid. And we can call it
get upgrade time. Let's add a string parameter. Just call it S name. This will be the name that
we'll be searched for. And then add a four
loop inside the method. We want to look
through the stat list, so we can type the
stats dot count here. And we can just
copy from the above here because we want to do
the exact same thing here. But instead of returning
the stat list member, we want to return the
stats upgrade time, so we can just get it from
the stlist member index of, and then do upgrade time to
grab the upgrade time value. And here below, if
the loop didn't found the stat name that is
equal to the stat name, then we can just return
the null value and just check if the value is null or not later when
using this method. For the next method, we want to return the stats
upgrade info object, which would be the member
of the status list. Let's just type public
and then stats upgrade info as the return type and
call the method at stats. Like the other method,
we will require a string and let's just
call it stat name. Then let's look through
the status list. We can just copy
from the code above. But instead of returning
the upgrade time value, we can just return the
status member index of I. And here below, if none
of the names are matched, then return n. Let's save the script and
head back to unity. In unity, let's go to the scripts folder and inside
the data scripts folder, create a new C sharp script, and we can call it upgrade item. Then let's open the script. Once it is opened, let's just delete
the update method. Now we need to declare
a couple of variables. But before that, let's import the system namespace here
above by typing using system. We need to also import
the UI namespace. And here below, before
declaring the variables, I'm going to create
a header attribute with title string
upgrade menu objects. And then I'm going to
paste the variables. First, we need a string
variables called state name, and the second one is a
string called item name. This will be the component
name shown in the upgrade UI. And the stat name
will be the stats ID that we can use to grab the
stats from stats manager. And here below, we need this integer array to hold the prices of the
component on each tier. And this private variable type should be the stats
Upgrade info, so we can cash the upgrade info for this upgrade item
upgradable component. Let's save the script, and we will continue
this on the next video.
40. 40 Stats & Upgrades part 3: Okay, so we need
to create a couple of methods with
this upgrade item. The first one would
be by upgrade. And then we need to also create the check for grade status. And here in the start,
we are going to grab our stat this
upgrade items stat, for example, if let's say, we are going to put Snam
held on the inspector later, then we are going to grab the stat from our stats manager. Sorry, states managers get stats and we are going
to fill the step name. So we are going to
get this that name. And with this step name,
we can check the price. So for example, currently, we are on level one, I think. Yeah. So when we buy the
upgrade, we can check this. If our money If
our current money, instance that money
is greater or equal than the price that we have
here, the price level. But it's the index
from our level. So if we have enough money, then we do the upgrade. And here, else, we should show message,
not enough money. And we will create
a dialogue window or model panel to show yes or no or a message
whenever we need to. So when we do the upgrade, we need to subtract the money, S manager, that
instance add money, and this time, we need
to substrate it with a negative value of
our price level. So basically, we are adding with this negative value here. So it will substrate our money. And then we need to add timer. So for example, we can
grab the Tr, I think, Str, and we can add
the state name, our current state name. And the value of our date time. So we need to add date time now, I think. Yeah, correct. The time now, it's a method, but we need to add this. Sorry, without the parents. Apparently, this is a
properties at I think it is at minutes and this we need the value
from our stats upgrade. So let's just grab the stats upgrade from the set
manager instance, and we already prepare the
method called get upgrade time and put the name inside of it. But since this returned
a float array, if you remember here, as we can see here, it
returns the float array. We need to get which index. So in order to get which index, we simply use the stat level. Because we are also using the
level for our price level, and we are using the level
for our upgrade time also. It will always use the same value for our
prices and our upgrade time. Once we update, we need to
start the routine here. But we haven't declared
this routine, so it's okay, and we can just add a log upgrading the stat
name that we have here. Okay. And if we don't
have enough money, we can just show
not enough money. Okay, let's save this. The next thing we
need to do, probably, we need to create the
core routine first. Let's type numerator and
let's call this upgrade. And for this do first, we want to set the
upgrading bullion, true. And whenever we finish it later, we want to set this
back to falls. So here below, we want to
create a time span object. And this will only available if we using the system
collection system library here. So make sure you do that and do only be available if
we are using this. And I'm going to name
this time remaining. And this will be day time
from our stats manager. Sr, but we are going to grab our step name from using
our state name state timer, and we want to substract
this with our date time now. We have this time
span remaining, and now we can calculate this. We need to create a while here. If time remaining is
greater than zero, and we want to keep doing this. I'm going to update our
time remaining here. And once it's finished, it will print it will debug finish upgrading
our set name here. Of course, we want to do
the upgrade to the upgrade. Now we need to create a function
that we do the upgrade. But right now we
have an error here. We need to return at least once, return as always with routine. For the time
remaining, we need to check its total seconds. As long the total second
is greater than zero, and we want to keep
doing this look this. Once it's finished,
then we are going to go to this block
of code here. Now we need to create a method that will increase our stat. So we are going to
increase our stat level. Now we are going to call
this increased stat here. But there is a possibility. We are going to finish
or we are going to accelerate the increasing start while the coroutine is running.
We want to check that. Luckily, we have created this boulon and
this bulon is for marking our coroutine.
Is it running or not? So we can check this by using
the I upgrading is true, then we want to stop
all coroutine currently are running inside this
upgrade item class. And this will be not localized
but only on that instance, so it won't affect the
other instance coroutine that is running on
leper instance, and When we stop upgrading here, we want to set this upgrading
also to false again. Now, we already did that here. Let's save this and we can
start the coroutine here. Let's just start
routine. Do upgrade. Okay. So like this. Let's say this and we still
need to expand this script, of course, but let's
see how it works. I see we have an error here. So let's just check
this. So we need more parent because we have two opening as
you can see here, we have three openings,
so we need to close this three times as
you can see here. Now, we are going to create
safety and go back to Unit. Okay. We are going to create
the button for upgrading. So first, we are going to
create an empty game object, and this will be the menu area. And I'm going to set
the anchor to the edges here and leave gaps
150 on the east side, and for the top probably
200 or 250 by 250. Okay. So this will
be the shop panel. And the shop panel, we have a ertallayout group. So what this component
is actually doing is arrange our child object
ertically automatically. So for example, if I create
some let's say a button area, let's say this is
the upgrade item. And I'm going to change this
600240 should be enough. And I create let's
say, an image, and I'm going to extend this to the bottom part
and change this to a smaller value like this
and put it right below here. As you can see if I
duplicate this item, it will automatically lay
out below this first one, and if I put it more, it will fill up the
screen like this. That is what vertical layout do. Now we are going to create
the menu item here. First, we need to
create a tax and this text would
be our item name. So let's just put it here. But first, I want to
create a empty area. I'm going to create an
empty and I'm going to put this on our site here. Like this, but I'm going to
set the width to maybe around 125 or perhaps longer than that, 250, and this will
be the icon area. And this would be the name here for the but I think
the icon is two big, so let's just make this
smaller 200 should be enough. Let's position on
100 and let's drag this image that we have
created as a child of this game object and we fill
it like this using this key. But I'm going to
tap at the bottom, I think, 50 pixels, like that. And we are going to
create a button, button. And this would be the button. Oh, this is the toggle, sorry, I think I click the wrong item. So der the gate item, I
want to create a C UI, and this should be the button. And this would be the button. Can we put it below here, and we can increase the tax
size under the button here. Using the best fit,
we can increase it and just rename this two
by for this moment here. For the text, we are going to we're going to use
the visitor font here, best fit, and let's just
increase the size here. And put it on top
or top left top left top right and
change the color to the orange color that
we already have as a prefabs and we can
increase the maximum size. It's okay by 60, for example, a, this would be our upgrade item, and we can add the upgrade item script
to this game object here. Perhaps the first one
we can set to health and the item should
be the health also. The item name text would
be our game object here, and the by text would be the
text from the boy button. And for the by
button, it would be the parent of the text
here. So the button object. And this level bar would be the slider to show on which
level currently we are. And this is the price level,
I think we should add to 52. And since we already
have the first one, we already have the first level, so we can just leave
the first level 20, and we can change
the second one, perhaps maybe 200, and
then the third one, 250, the fourth one, 300 and the less one, 250. But of course we can change
this and with this setup, we can have independent
prices on each item. Okay. Okay. Now let's go to
our script again. And on the start, after
we get the stats here, we want you to
update our tax here. So let's just update the item name text
item name text and we can insert the item
name as the upm name. And for the buy text, we can get the price. Here is the neat
thing we have here. We can get this price
level, the st level. The prices level here. And since I think is an integer, we need to convert this
to a string so we can use this string To string
method and it will convert this and now we need to assign a
listener to our by button, so we can access the by
button listener by accessing the click event here
and add listener. And for this ad listener, we can input an action
It's basically a method. Action is a method
without parameter, and we can just use
this upgrade here. Okay, save it. Now
if we start this, the buy button
will automatically execute this whenever
we clicked it. Let's just do this
here. Let's play this. And here, if we go to our game manager, we
don't have any money. So if we click this, it will tell us we don't
have enough money. But for example, if I
increase this money to 500 and then I press this, Now it's upgrading health and our money is get substracted
by the amount of this. And you can see here, if I go to our upgrade item and I
enable the bug here, we can see currently
we are upgrading. And I forgot we need
to check the health. The first one, I
think is 4 minutes. So it will take 4 minutes
to finish this upgrade, which is too long. So to test this, I
want to stop this. And there is a thing we can do. We can change our by tax here. So Copy this by text here, and we can use the string data. I think it's this string format. And here we need to type a string data, but
we can use a format. For example, we can use this
0.00 with curly bracket. And we can add a full Caln the other one is one
point full Colon 00. And this is actually formating, and it will shows
the date and time or the minutes and
seconds we have left in this upgrade time. And we simply need to type here the time remaining. Sorry. We can get the remaining data, the time span, and this time span actually have a lot
of information in it. It has the minutes. And also the time remaining
for the second format, and this would be the seconds. With this set, whenever
now we upgrade something, we can see it in
progress in our button. Now let's try to do that. I'm going to set this back
to normal, the inspector, let's try to play this again and we can expand our game manager here
and add some money. And press this button, and it
will show the upgrade left. And since our help to go to the next level,
it needs 4 minutes. So it shows that we have four minute left, and
it's still upgrading. And once we finish upgrade this, it will increase our
level here because we are calling the increase and increase is increasing
our level here. So we can just try it like this. I'm going to change the
money first here to 500 and we can set
the first element, for example, to half second
half minutes 30 seconds. So let's just try to play this and press the button again. And as you can see,
we have 30 seconds, and I'm going to
lift this running, so we can see when it's done, it will increase our
state level here. And once we increase
the state level, it will pick our second entries
from the held up greatly. So we'll have a
greater held amount. Three, two, one, zero. When it's done, as
you can see here, our level is increase. But our by button
doesn't go back to the prices that we have for the next
level, so we can fix that. So to fix that whenever we finish or whenever we
increase the stat, we need to reset our button
text to the next price level. So let's just copy
this line here, and we can just put it
inside the increased stats. Why do we put it here? Because here we
increase our level. And then once we increase, when we update the price level, it will use the new level
that has just been upgraded. So we will get the new
prices to string and it will set back to
the buyer tax here. So if we want to
test this again, we can just make this
to a very small value. For example, or and if we try to play
this, we can see it. Now we have 200. If we go
to our upgrade system, the first one is 200,
but the next one should be 250. So let's
just try to do that. After five second, we can
see this will change you. We finished upgraded now in
order to upgrade within 250 in terms of coins. And
now we have level two. We still have more money
than our price here, so we can just upgrade it
again. There is an error. There is an element
with the same key exists in addition area. Another thing we need to do
whenever we finish upgrading, we need to remove our date
time entry from our Satter. Whenever we upgrade, it
will create a new one and it cannot have a two entry
with same state name. So, we can just copy
this Satter here. And once we finish finish upgrading, we
can just remove this. By using the remove and need the string key so
we can use the set name. Let's try to simulate
this one again. Let's set this to 0.2
for the second one. Okay, let's play this again. I'm going to upgrade
this and it needs 5 seconds to upgrade
and once finished, it should upgrade our level. Yeah, I upgraded our level
and upgraded the price also. And if I press play again, as you can see now,
it needs 11 seconds. And once this
finished, this will upgrade our level again. Now we need 300
coins to upgrade it, and if we press this, it will tell us that we don't
have enough money. So yeah, this is the
basic upgrade system, and still we need to
expand more on our script. We need to add a
dialogue to offer the user whether the user
wants to upgrade or not, and we would need also
to add some sort of accelerate the upgrade the
user can spend more money. And make the upgrade
faster process by skipping the time here. And we will need to also
create a saving system. Okay.
41. 41 Upgrade Item Continued: Now let's continue
our upgrade items, and I think we can change the bi button to look more in
line with our design here. I'm going to go to
the baton object, and for the source image, let's have the U
bar, the UI frame. This one here, we can
pick the color that we have saved this as
a pref for the text, we can change the font
style to the visitor one and change the color to also the same orange
that we have here. Maybe we can change the size
of our button to make this slightly bigger and also increase the size
of our text here. Like this, so we
can read it better. And now we need to create
some sort of slider effect to show on which level are
currently our stats here. So select the upgrade item, and I'm going to
create a new UI, and this would be a slider. But here, we are going to
change a couple of things here. Basically, I'm going to
delete the background. I'm going to delete
the handle slid area, and we are going just to
use the field area here. And for the slider, we are going to change
the minimum value, sorry, the maximum value to five since we
have five level. And as you can see,
if I move this, we have a nice slider effect. So I'm going to increase
this size here. So I'm going to put
this perhaps around here and make it quite long, and we can increase
the bar here. And I'm going to create
a new image below here. And first, I'm going to change the value of our slider
to the maximum value, so we can see the position, and I'm going to set our image to the same position
as our slider. And I'm going to set this image to I think it should
be our bar here. Yeah. The UI five bar. As you can see, we have some
sort of box five boxes, and we are going to
use this as a mask. This would be our slider mask. In order to set this as a mask, we need to add a component, the mask component, and we can drag our slider to be the
child of our mask here. And we can also hide our mass object by unchecking
the show mass graphic here. And if you can see here, if I change the value, let's say to one, Sorry, this is two, one. We have one and two, and three and four and five. But you can see here
if I set this 21, we don't have the
exact position. So I'm going to change our fill object art
here to a normal. I think we should have that one. Okay, Carly, we have this, but we need to change
our masking object here. So let's just move
this a bit here. And now we can we can
just scale our mask, so it cuts perfectly, and we can try to change
our value here to. It looks fine. Three also looks okay for We can change the scale of our slider mask from
the right side here, as you can see to cut the rounded shape on the
end here and go to slider, and I'm going to set this 25. Okay. Yeah. So now we need to make the masking smaller
than our child object, so we don't see the rounded
shape on the edges. And for the field area, I'm going to change the color to an orange value here,
the present we have. And now we can reposition our slider mass parent it
aligns with our text here. And for the slider here, we can set this to one first. Now if we select
our upgrade time, we already declare
our item level bar and it's a type of slider, as you can see here
in our script. We already set that. Now I'm going to direct the slider object and make sure you direct
the child object, the mass slider, but
our child object here, the slider and direct this
to our item level bar. And save the scene. Now
if we go to our script, we can just update
the value here, and whenever we set
this by text, sorry, we can also set the value of our slider here
to our state level. And we can just copy
this line here, and whenever we increase, we can update our
item level bar also. So now if we try to If we try to upgrade this and we can check our game manager that we
still have 500 money, and also we change the timer in our health system,
so let's just try this. In five second, this
should be updated. Okay. Yep. Now we have the second level of our
health, stronger health. And if we update this again, it will increase our
level once more. Okay, there you go. And now we don't have
enough money to upgrade. So if we press this, it
will show not enough money. Okay. And I think that should do with
our upgrade options. The next thing we need to do is actually the model window to show an option whenever we
want to upgrade or not. And if we don't have money, we should have a feedback
in our game view here using that model
window or the message box.
42. 42 Dialog Systems: So now let's create
our model window. Here, under our canvas, we are going to
create a new area, create an empty area, and under our scene here, I'm going to create a window, maybe not too big
around 400 in width or 500 in width should be enough
and around 300 in height. Or make it bigger,
600400 and we are going to add an image here
and make this maybe a darker, black color, but with
a slight transparency. Set to transpate to 75, so we will have
something like this. And for the other
thing we need to do is actually we need to rename it's much more
clear dialog window. Sorry. What we need to do is we need to
duplicate this first, and this will be our
dialogue window here, the child object,
and the child object should fill our parent size. For the parent size, we want
to remove the image script, and let's just rename
this dialogue system. This will the one who holds
the dialog window script, and we will need to enable or
disable this child object. Another thing we need to
do is we need to create a tax child under the
dialog window game object. So I'm going to create that and just type some placeholder. And I'm going to
also scale this to the size of our window object, but I'm going to change
a couple of things. The bottom I'm going
to set it to 100 and for the top size is going
to be 15 left also 15, also 15 or perhaps
a bigger value, 25. And I'm going to change this to visitor and change the color to orange and set best fit to enable the best fit
and set the maximum 5250. And also, I'm going to change
the alignment to middle and also the vertical
alignment to also middle. And this will be
our message window. And another thing we
need to create an empty and this will
be our button holder. So I'm going to align this to the bottom part of our
dialog window here. So I'm going to hold
the button while we browsing our anchor presets
here and choose this one. So it will fit nicely
to our buttom area, and it has height of 100, it won't overlap with
our text because our text also have cap of
100 on the buttom area. So it will fill this
anti area here, and we can add a
horizontal layout group. And horizontal la group behaves exactly the same like
vertical layout group. But in this case,
it will align or it will lay out the group
in horizontal axis. So, this would be
our button group. And for our button group, I'm going to create
a new button, or I'm going to copy the
button from our upgrade here, so I'm going to press control
D from our by button, and I'm going to
make this child of our button group here,
so it will fill this. And this will be the button A. And we are going to
change the alignment of our horizontalit group
to middle center. So it will default on
the middle and center. And if we duplicate
this buttern, it will fill nicely even less space on our
dialog window here. So let's change the
second one to button B. Okay, so now we have this
dialog window setup. We need to create
a script for it. So let's go to our script
folder, and our data scripts, I'm going to create
a new CHO script, and I'm going to call
this dialogue manager. Okay. And I'm going to open
this dialogue manager. And the first thing we
need to do is actually, we need to change
sorry, not change. We need to add a static
public variable, and this will be the type
of dialogue manager itself. So we are going to set an instance a static
instance of the script. So it's going to be easier to be accessed from another script. And I'm going to remove
our built in method here, and I'm going to use
the weak method, and I'm going to set the
instance to the script here. So this would work like our lefl manager, as
you can see here. And the difference between
the level manager, the dial manager and between
versus the stats manager. The states manager, it will be Singleton and it will
persist between scenes. As with the level manager
or the dialect manager, it will not persist
between scenes. So now we need to create
a couple of things here. First, we need to using
the Unity engine UI, so I'm going to
just to add that. And now we need a couple of
references to our UI system. So the first one we need
to have access is to the text message and the button text or
tax and for the text. And we also need reference
to our button and no button. And this will be
the type of button. Okay. So now we can create
two different methods. And the first one will
be show dialogue. And for the show dialogue, we will need a
couple of variable. So the first one, we will
need the message parameter. And also, we need an
action reference. So unity actions. But if I type unit action, we don't have that
because we need to import the Unity
engine dot event. So let's just import
that it engine event. And once we have import this, we will have access
to Unity action, and this would be
the Yes action. And the second one would be the Unity action
to our no action. And I'm going to
set this default, so we won't have to set the actions every time we are calling this dialogue,
it will set to. And so I'm going to
create a string, sorry string for the tax and
this will default to yes. So if we create a
parameter and we add a equal sign with a value
after the parameter names, it will assign this
to a default value. So if we call this method without specifying
this parameters, it won't give us an error. Instead, it will use
this default value here. Okay. Thing I'm going to
do is the string no tax, and it will default to no. But if you want to, you can
overwrite this by specifying a new string in this parameter when you are
calling this show dialogue. Okay, now once we have declared this now if you have declared
this all of the parameters, I think I'm going to enter this. So we have two line
of method here, so we can see it
clearly and we can close this method definition. And now we are going
to show our panel. Another thing we
need a reference to is to the game
object panel itself. And on Awake, I'm going to
set the panel to disabled. So I'm going to set panel
to false set active. And now we need to assign the message
to our text message. So first, I'm going to update
our message to Seth Okay. Oh, sorry, because we are
using the same name here. So it shows a properties
that we don't have. We should be using this one. So I'm going to just to
rename this dialogue message. And I think this would
cause an issue also. So let's just capitalize
the parameter here. Yes, text and the no text. Yeah. So now I'm going to access our dialogue message object here,
the text message, and I'm going to change
the text and set this to our message that we are
passing via the method here. And for the text, we are going to also set this to our text from
the parameter here, and I'm going to copy this
line here and duplicate this, and this will be our text, and we can get this from our
text from the parameter. And first, we are
going to assign the button actions or method that we can pass
from another script. And I'm going to check if
no action equals null, then I'm going to pass
a button, sorry, click. A Listener, just by
button here, that one. I think it is this one. If
you check our upgrade item, we are assigning method
to our by button, and we are going to do
the same with this. But in this case, we are going to create
a private method, and this will be only
to disable our panel. And inside this, we are
going to access our panel, set active and set
this two falls. And we are going to
disable panel here. And of course, we want to want to we want to add an action to the no
button if action is not. No. Then we want to Okay, I think it will be
easier if we do this. So let's just copy this. I'm going to add this here
and we don't need this. But if it's not null, then we want to add that action also. So I'm going to add
the listener and use the no action parameter that we have passed from
our method here, so it will fill
whatever method that we put it inside this unity
action, no action here. And the other thing we need to do is we need to
access our yes button. Sorry, button on click, we need to add Listener to our button using
the action here. So these two parameters, we need to use this dial up. But With the no button, we don't have to actually put a no action because if
we don't have no action, it will only add listener
this disabled here. And we want to make
sure that we clear all of previous listener before we assigning new listener here. So let's just type the
new button on click, and let's use the remove
all listeners method. And for the no button, we
would also do the same. Remove all listener here. And we need to create
another method, which is for showing message. So I'm going to copy this here and paste this and this
will be a show message. And for so message, we
don't need the parameter, we only need to
show the message. So we are going to set
the text to k here, and we are going to
remove the listener here. And for the add listener, I'm going to just to
add disabled panel. Basically, this show
message is only for showing the message,
and when we press okay, it will close the panel, and we need to hide our no button, so we can access that by
accessing the no button here, game object because
this button component surely will be attached
to some game objects. So we can access its game object and set this active two falls. And here, we need to
set the button to set activate because we might just show message before
and it's set to false. It's hidden. And when we're
showing this dialogue, if we don't set this to true and the no button
will stays hidden, so we need to reset
that value here, lastly, we need to
activate our panel. So type set active
T for our panel, and the same goes to
our show message. We need to set active Tro. So now we pretty much done
with our dialogue manager, and this is quite neat function, and then we are going
to re use often, and you can also use this
for your other project. Of course. Now if I go to our upgrade system,
as you can see here, whenever we don't
have enough money, we can just show the message by using the
dialogue manager instance, and we can show message. And we can type you don't
have enough, sorry, enough money to upgrade space, and then you can add your
state name here like this. And another thing
we can do is here, when we finish upgrade, we can just using
this show message. Yeah, something like
this? Yeah. And we are going to need a lot of more this dialogue manager here. For example, for upgrading, we can we can ask if
we have enough money. Do we want to do the
upgrade, and this time, we are going to use
the dialogue manager, instance show dialogue. And for the message, we can add, do you really want to
upgrade your stat name here, and this is the string, and
we need to assign the action. And for the actions, we need
all of this to execute it. But as you can see
it as for an action. So we can create some sort of delegates and how
to create this, you need to create a set of
parenthes equal sign and the right arrow sign and with bracket opening
and closing bracket. So we can put all
of the codes here, and this will act as an action
as a one action together. So, let's just Cut this out and paste this here and I'm going to comment
out this de log here. Now all of our blocks
of upgrading code, we are putting inside
our yes actions using this delegate here. This is alma expressions, and you need to put equal sign, parents, open close, and
then and then right arrow, and then opening sets and
closing of curly bracket. And then as usual,
at the end of line, you need to close this
because this is actually still one line from this
show dialogue here. We just expand this
so we can read it much better, and
we can save this. Okay. So now let's go
to our scene here, go back and we need to set
up our dialogue system. In our dialog system,
select the parent object, which is the dig system,
not the dialog window and drag our dialog
manager here. And now we need to fill this
For the panel variable, we can just drag
our dialog window. And for the dialogue message, we can drag our main tax here. And for the S text, we
need to open our button, and the will be on the left
one and no on the right. So I'm going to drag the
button B text to the no text. And for the S
button, we can drag the button object and the
button B to the button here. Okay. Let's save the scene here and let's try to run this. Now if I run this, it will
get hidden because we are hiding the dial up window
panel on start or on a wake. And if I press the button here, it will as first
before upgrading. Do you really want
to upgrade health? And if you set no, it will disable our dial
up window panel, just like the one
we set it here. And if we press and then it will do the upgrade,
as you can see here. But we have an issue.
After we press yes, it doesn't hide our window, but it stays, so we
need to fix that. So there is one thing I forgot. After we add the action
to our yes button, we need to also add the
disabled panel function. So you can add as many listener. And basically, if you do this, it will fill our button
on click event here. Just like if you assign
a function manually so here so you can set as many functions as
you want to here, and this is what actually is being done when
we add Listener. But it doesn't show
on the inspector. So I'm going to remove all
of the onclick event here. So save the scene
here and since I've already add the sable panel, this should fix the issue. Let's try this again and if
upgrade it asks for upgrade, if I press, it will Okay. Why have I saved this? Oh, sorry. I haven't saved
our dialogue manager. So saved this, and Unity will compile the update
on the script. And once it's finished, it should fix the issue. You want to upgrade?
Yes, it hides our panel, and once it's finished,
it will show a message. And with message, it will
only show one button on the middle because we are using this horizontal
layout group. Finish upgrading held, and if we press this,
it will ask again. If I press no, it
will not update it. So yeah, that is pretty much
with our dialog system. And in the next video, we are going to refine
our UI and also create a safe system and
loading system. Okay.
43. 43 Save Systems: In this video, we are going
to continue working on the upgrade system and we will also implement
the safe system. Before we continue, there
are a couple of things we need to add inside the
upgrade item script. First, we need to
start implement the check for upgrade
status method. This method is going
to be used to check the upgrade progress after
we load the safe progress. First, we need to check if we have an upgrade in progress. By checking the
content of the Satter dictionary using
contains key method, we can check if Sattimer
have a key with this item in it by passing
the stat name variable. If it is, then it means we have an upgrade for this
item in progress. Inside the statement,
we need to also check whether the accurate
time has passed or not. I'm going to add
another statement, and it's going to check if the current date time
using the now property is less or has not reached the completed time from the
status manager stats timer. We can pass the stat name using a square bracket to get the correct completed
time from the dictionary. If that is the
case, then we want to run the due upgrade routine. But we don't need to run the by upgrade method because
at this point, if there is an
upgrade in progress, it means we already paid for it, and if the upgrade is finished, the timer entry gets
removed as shown here. If there are no upgrades in progress or if it's
already completed, the timer entry
wouldn't be found. I'm going to copy the
start coroutine do upgrade line here and paste it
into the statement. And on LS, it means
the time has passed, but we still have timer
entry inside the stat timer. Then we want to run the
increased stat method, and we will only
run this check for upgrade status method when
we load the safe progress. Okay. And the other
thing we need to implement is a method for
updating the UI display. We can call it
update item display. And this method
will be called by the stats manager upon
loading the safe progress. So first, we need to get
stat data from stats manager do instance stats method
and pass the stat name. The next thing that we
need to do is to update the item level bar slider value to be equal to the
current stat level. And then we need to check if the stat level is equal to
the length of the price. If it is, then it
means the item has already reached its
maximum status or level. We can copy the by tax
assigning line here down below and paste it inside the
update item display method. One outside the if statement
and the other inside. Then we need to change the
one inside the block to max, and if we reach
the maximum level, we want to return the method. This way, the
method will exit at this point and it won't
execute this line below. Because this method will be called when the player
loads the progress, we will also need to check for any upgrade progress by running the check
for upgrade status. Hey, this is Romy
from the future, and there are some
bugs in the future. Let's fix it. Inside the
upgrade item script, we need to run the update
item display method inside the start method. This way, when the
menu seen initialize, all of the item will update its display on start based
on the latest progress. Because the check for
upgrade status gets called inside the update
item display method. This will make the item
automatically continue its upgrade if there are timer left for
each of the items. That will be it for
the upgrade system. Now let's start working
on the safe system. Create a new script inside the data scripts folder and
rename it to save system. Let's open the script.
Inside the script, because we are going to
use the binary formatter, we need to import the
binary name space. But first, let's just delete
the start and update method. We can also delete the
mono behavior inheritance. As I'm going to make this
class static class by adding static keyword after
the public scope modifier. This way, we don't need to attach the script
onto an object, but we can access
the method inside just by accessing
the class because a static class are
shared through the projects and cannot
have any instances. Now, just below the
using Unity engine line. Let's add using system time
serialization formatters and then dot binary. This is a mass when using
binary formatter class. We will also need to add a
system dot O namespaces to write the resulting binary from the safe progress to
a file or to load it. Now, let's define
the first method, which would be a public
static void safe, and we need to add a signature
to the method with t, which is a keyword
for generate type. Then we want to pass this T type as the parameter and
call it safe data. By using generate, we can pass whatever class we have
defined for the safe data. First, we need to declare a temporary variable and the type would be a
binary formatter. Let's call it BF. Then we need to initialize it. Then another temporary
variable type of file stream, Binary formatter will be available if we use
this name space, and file stream will also be available if we use system
that IO name space. For the file stream,
let's call it file, and we need to initialize
it with a parameter. The first would be the
path and the file name. We can also use
persistent data path from application class. This will make sure the
file are being safe into the application folder
that are persistent, such as installation
folder or something else, but not the cache folder because cache folder usually
are not persistent. Then we want to combine the
file name in format string. We can just add plus sign and
then the string file name. But we need to add forward
slash before the file name, and let's just call
the file safe game. But the file name and extension
can be anything else. For the second argument, let's access the file
mode and select create. This basically will tell
the file stream to create a new file with the path and file name from
the first argument. Then we want to
serialize the save data into the binary and save
it to the file stream. Using the binary
formatter object, we can call the serialized
method and then pass the file stream object called file for the
first argument, and for the second
argument would be the save data variable
from the method parameter. This will convert
the save data object into binary and then
save it into a file. Then we need to close
the file stream by calling the closed method, and last we can add
a debug log here. For the load method, we need to also declare
a public static method. But this time it will return
a type of T or generics that can be cast into the class that has been saved by
the safe method. We can call this method load, but we need to add a signature
with this angled bracket, and we don't need a
parameter for this method. Because this method
should return something, now we have this error as there are no return code yet in it. First, we need to check
if the save file exists. We can do that using the
statement and then check the file using exist method
from the file class, and we need to pass the file and its path in a string format. We can copy this directly from the first argument
of the file stream inside the safe method. And I'm going to also
add an L statement. Inside it, I'm going to add a debug log error with message, S file not found. And for loading the data, inside the if statement, we need to create temporary
binary formatter variable. Let's call it BF
and initialize it. Then we need to also create a new file stream and we can just copy it from
the safe method, paste it here below. But instead of using the file mode create M
on the second argument, let's change it to
file mode open. This way, it will tell to open the safe file in
the first argument. I also wanted to throw a load
success message here below. After the debug, we
need to deserialize and cast the loaded data back
into its class or type. For that, let's create a
new temporary variable with type of t and
call it loaded. Then we can deserialize
the loaded file using the method from the
binary formatter object called deserialize, and then pass the
file into the method. Because the serialized
method returns an object, it doesn't know what was
the object class before. And the variable
type is genericx. We need to cast the Deralze
object into a genericx by adding a sets of parenthesis
and the t keyword in it. After that, we need to close the file just like we
did in the safe method. Then return the loaded object. But because we only return something inside
the If statement, there is still a probability we are not returning something. We need to add a
return default value of t outside the If statement. If there are no safe file found, then the method will
return a default value. Usually, it will be null, but it depends on
the class type. This is the end of the
safe system class, and I will just delete this two namespace code
because we don't need it. And to modify the status manager for saving and
loading the stats, we need to create
another custom class and we can create here below. First, let's add
serializable attribute for the class and we can
call it save data. Inside the class, we need a couple of variables
and we need to match it with some
of the variables from the status
manager such as lives, money and the list of
type status upgrade info because we need to save
the status of the upgrades, and we need to also save the achievement list
and the status timer. Let's just copy all of the fields and then paste
it inside the safe data. But we are going to remove the variables that
are not needed. Let's also delete this header because this class would
only act as a safe data, and it's not going to be
shown in the inspector. For the lives variable, we can remove the devult value. Next, we need to
create two new methods inside the stats manager
for saving and loading. Let's create a new
public method called safe progress. And
load progress. Inside safe progress method, we need to create a new
instance of the safe data, so let's create it, and
then we need to copy all of the needed fields from the stats manager to the
newly created safe data. First, let's save the lives by typing the safe
data object and then type lives to access the field and set it to value two lives. Then for the money,
let's do the same. Save data dot money and
set its value to money. Next, let's save the
medals or achievement. We want to save all
the fields from the stats manager with the same name into the
save data instance. Let's just finish this up. Once we already copy all of the needed fields or variables
into the safe data object. Then we want to save it to
the dis using the safe system safe method we've created before and pass the
safe data object. This method will
create a safe object to contains all the
needed data to be safe. After all, of the data
have been copied, we then pass the object into the safe method
and this will save the object into a file
called safe For loading, we are going to create the exact reverse
of the safe method. First, let's create an
object of type safe data, and let's call it load data, we can load it right away by
accessing the load method from the safe system and pass the save data
as the signature, similar to get component method. This will load the object from the save data and then cast it to the type
in the signature. In this case, it will
be the save data. Now we can grab the values from the low data and load it into the stats
manager variables. Lives can get values from lives, and the same goes with
the other variables. Next after loading the progress, we need to update all of
the items UI on the menu. Let's create a new method. We can call it
update item display. Inside the method, we want to create an array of upgrade item. Then we can just use the
method called fine objects of type and pass the upgrade
item class as the signature. This method will search
through the scene for game objects that has the
class attached to it. Next, we want to look through the items collection
using for loop. On each item, we want to run the update item
display method. Each items, we'll show an
updated information based on the loaded progress and we'll check for any upgrade
in the progress. Now let's go back to Unity
and give this a try. To test this, we need to create a button to save and
load the progress. Let's create an
empty and position it on the buttom using
the anchor preset. Let's rename the object
to the But button and let's create two new button
as the child object. The first button will be for saving and the second
would be for loading. Let's reposition
both of the buttons. Set the exposition of the
first button to negative 120 and the second
one to positive 120. Now we need to set
the buttons to run the safe progress
and load progress method from the status manager that is attached to the
game manager object. But because the game
manager is a single ton, this can cause issue with missing reference when re
entering the menu scene. Let's create a the
bug script for these buttons, and
let's open it. Inside this debug script, we can delete both start
and update method, and let's create a new public
method called safe load. And both of the
methods needs to be public because we are going to call them
from the buttons. Inside the safe method, let's call the safe
progress method from the stats manager
Singleton reference. Inside the load method, let's call the load
progress method. Now let's switch back
to unity and let's attach the debug script onto
the debug button game field, and let's rename the objects. First one, should
be the safe button. And the second one should
be the load button. On the safe button, let's wreck the debug button
game object into the click event
in the inspector, and let's call the safe
method from the Buck Script. And we want to do the same
with the load button. But instead, let's call the load button from
the Buck script. So safe button should
run the safe method, and load button shod run the load method.
Now, let's try it. But on a second thought, there are some things we need to modify to make the
task more convenient. Let's select the game manager
and on the inspector, let's change the element
one and two upgrade time of the health stats to 0.3 and 0.4. It's a bit longer.
Now let's test this. As you can see, we have
500 credits of money. If I try to upgrade, now it's running the upgrade
timer, and let's save this. If the console prints
out safe success, then we have successfully
saved the progress. Now let's stop this and
play it again quick. Let's try to load it. But it seems there
is an issue with the code because the
progress doesn't continue. Let's take a look at the issue. The issue is quite
simple actually. On the stats manager class inside the load progress method, we never call the update
item display method. The load was
successfully loaded, but the UI didn't get updated. Let's call it here. After all, of the safe progress
has been loaded. And before testing, let's make sure the upgrade time a bit longer to 0.6 and 0.7,
and let's play it. Now, let's upgrade it again
and we have 30 seconds. I'm going to save
it, stop the game. And run it again and
then press load. Now you can see after loading, the timer continues and let's wait a while until
the upgrade finishes. Now it's finished and the
health has been upgraded. Now let's save it again, stop the game, and let's
play it again and load it. Now you can see the
health is upgraded and the price text also changed to reflect the next tier
of the health price. Next, let's try to
upgrade it again, and now the upgrade time
is around 40 seconds. I'm going to save this
and let's stop it. Now let's wait a bit until
the upgrade is done. I'm going to open my clock. Okay, now 40 seconds
have passed. Let's test this again. Let's press. Now you can see the UI is updated
automatically. This is basically how the safe and load system is
going to work in this game. But there is another
thing we can do. We can add a notification. And we're already showing the notification inside
the due upgrade routine, let's just cut the
line and paste it in the increased stat method. This way, the notification will always be shown
whether we finish the upgrade or if the progress loaded and the stat gets
upgraded upon load. The notification won't be shown though if the upgrade
has been done because the timer will already be removed and this whole
code won't even run. So let's test this again by the upgrade and
then save it again. I'm going to wait a bit until
the upgrade time passes. If we try it again after
loading the progress, we can see the
notification pops up. This concludes the
safe and load lessons. With this safe system script, we can save any type of
class as long it consists only sterilizable fields. Okay.
44. 44 Scene Loader: Okay, so now we are
going to create a scene loading progress system. So whenever we change scene, we can see the progress
that's currently loading. And first of all, I'm going to create a new
folder in our prefabs folder, and this is going
to be our managers. And as site manager,
I'm going to direct our game manager to be a prefs also for
the dialog system, I want to also set this as
a prefex we have a copy, and whenever we mess things up, we can just direct
this from our prefs. Okay, now we need to create
a new canvas for this. So let's just create
a new canvas. Sorry. I'm going to
delete this here. We can just quick create
UI and choose Canvas. So now we have this
new canvas here. And I'm going to copy
this setting here, so I'm going to copy
component here, and I'm going to paste
this onto our new canvas. So it has the same value. And for the sorting order, I'm going to make sure
that our new canvas stays in front of
the other canvas, and this should be
the scen loader. Okay. And now I'm going to create a new image posin loader, and I'm going to snap
this to the size of our screen by holding the button inside the anchor process
and uses this one, so it will close all of it. And I'm going to add to
set the color to black, but I'm going to give
slight transparent to it. And then I'm going to
call this loading panel. And I'm going to create a new
text And for the text here, I'm going to set its size to around 500 and change the
font to our visitor font here and set the string of the text to loading
and set to best fit and also set the
color to this range here. And set the height,
maybe around 80 and also set the maximum
size to a much bigger 100 and I'm going
to align this to the center and move
this text slightly up, maybe around 50 on the y axis. And I'm going to also create
a bar for loading here. So let's just create a new image and we can just set this
length around this value here. So we have Yeah. I'm going to round this value to 300 and sets the height 25. I'm going to create a
new image and this will be the progress frame. And this one would
be the progress bar. For the progress
frame, I'm going to use this UI frame here and make this bigger as you can see here and make sure
it's centered like this, and we can move to the bottom here and
change its color to the same orange
that we have here. For the progress bar, I'm going to make sure it's
on the middle like this. And for the progress frame
to also make sure it's on the middle and
move this again. Sorry. Press holding shift. Yeah. Move this down, and I'm going to also set the loading text to be on
the middle of our frame. And for the progress
bar, I'm going to set its anchor to the left side. So how to show this blue circle, just press shift and press
this and I'm going to set this anchor to this
position here. Yeah. If we scale this on
the x axis as you can see, we can set the value of our bar by using the x scale
of its scale here. Now we have a nice
loading screen. We need to create a new script for switching between scenes. Let's just create a s loader
CSR script and open script. And we want to make this as a Singleton just like
our status manager. So we need to create a public static reference to
this class here, S loader, and I'm going to
name this instance, as with the usual Singleton, we are going to
create a new awake method and we want to make sure that this object
persistth scene. So I'm going to go to
our stats manager here, and undertake method. I'm going to copy
this slide here. And it will work right away because we are using
the same variable name. I'm going to delete the start method and the ablate method. Save this. Let's create
a couple of references. First, we need to create a
public transform progress bar. I'm going to add using Unity. Sorry. No, we've created
the progress bar here. Now we need to add reference to our scene manager
library from the unity, so type this using Unity
engine the scene management. And now we need to create
a couple of methods. First, I'm going to
create a F disable panel. And we need a reference
to this panel, so I'm going to add a
public game object panel. And whenever we
disable the panel, we want to hide this panel. Let's set the active
to false on wake, we want to hide the
panel right away. And now we want to create a
method to update our bar. And this method will
ask for a value. And we can create a a
private vector three, let's call this bar scale, and this would be a vector
three of one by default. And we are going to change its x value inside
our update bar here. Here, we can set the bar scale x to the value that we are passing
from our parameter here. Then we can update our
progress bar local scale and assign this bar scale as the scale of our
progress bar here. Okay. And the next thing we need
to do is we need to create a core routine for loading
the scene progress. So let's just type load scene. Los we need to pass a
string for the scene name, and we need to create
a Sing operation. And this is, let's call
this asynchronous loading, and this would be a new object to track our loading progress, we are going to use the
scene managers loading, not the use of loading, but
the loading asynchronous. And for the s for
the target scene, we are going to use
the scene here. With the asynchronous
operation here, we can check if it's
done or not by checking the property, loading is done. It has a done property. I want to make sure
while it's not done, that's why I'm adding
this exclamation point, exclamation character here. Exclamation sign in
front of our loading. Whenever it's not done, then we want to upgrade
our update bar. We can update the
bar here and pass the loading value progress, this progress, and this is a float and it will
return from 021. But before we are using this, we want to clamp this value, so we can just type f clamp. We want to set the value
of our progress to 021. Since the maximum
probably is 0.9, so we want to make sure
that when we reach 0.9, we have a maximum bar. So it will set the
maximum value to one. We want to use the met CLM
and the other method 01, and we want to
divide this with our 0.9 because the maximum number of the progress will be 0.9. So when we divide
with this number, we will have a
value of one later. The next we need to do is we
need to yield return, no. Whenever it's not done, then we will stay
in this loop here, and after it's done, we need
to disable our panel. Okay. And we need a public method should trigger this load scene, let's just create
a new public void. Load scene or we can just
create a new change scene, and we need to also pass
a string scene name. Okay. And inside this method, we are going to start the
load scene C routine, and we will pass the scene
name parameter here. Yeah, like this. So
now we can put this onto our scene loader here. So d there is an issue here. Okay. It's fixed.
Select the scene loader here and we can drag
the scene loader. And for the panel, I'm going to drag this loading panel here. And for the progress bar, I'm going to choose this
progress bar here. Okay, now I'm going to save
the scene loader as a preface inside our manager.
Okay, so save this. And if we play this, they should hide the panel
right away, as you can see. And now we need
to on next video, we need to create the menu
the menu for the level, and also the medals indicator if we have already unlocked the
achievements on that level.
45. 45 Level Menu part 1: Okay. So now we are
going to create the menu for our
level selection. And I'm going to hide
our sin loader first. And also, I'm going to hide the dialect system and
also the shop panel. But before I hide
the shop panel, I want to copy the transform
of our shop panel here. So copy the component here. And let's create the new
empty under our canvas here. I'm going to put it below
the shop panel here, and this will be our level
selector or level panel. Level sector panel, think
it's the best name. And I'm going to paste the component values to
this transform here, we have the same value
as our shop panel here. We need to hide the shop panel. Now let's first of all, I'm going to add a
vertical layout group and We need to create
a child object, and this would be our level. Let's call it level menu. And for size let's
change its size to 600. And for the height, I'm
going to set this to 200. So, we just direct to follow
the vertical group here. And now we can create
a couple of things. First, I'm going to
create a button and I'm going to snap this to the right side of our panel by holding out
and press this one here. So we have a large
button that fill our left menu size here
on the right side, and I'm going to
set its width to 200 and set the
exposition to -100. And we are going to set
up the button here. First, I'm going to
maximize the text here. Okay. And I'm going to
give it string of 01, so it will indicate
the first level and change its phone
to the visitor, and also the max size, make it bigger around 120, and I'm going to
change its color to the orange that we
have saved before. And for the button, I'm going to change the source image under the image component to our UI frame and sets its
color also to the orange. If we gross our game, we have this button, and in
order to play our level, we need to click this button, and I'm going to rename
this object to play button. And the next thing we need to do is we need to
create another empty, and we want to make this fit
our left menu layout here, but I'm going to shrink the right side direct
to the right side. So it snaps to our button here. And this will be
the achieve list. And for this achievement lift, I'm going to add another
vertical layout group, and I'm going to add, not the empty game
object, but a tax object. So just delete
this empty and add a new tax And we can just sorry. We can just add the tax
here and drag it snaps to the upper left of our anchor over here based on the vertical
layout group settings. And let's increase the
size of the tax here. Okay. And set it heights to maybe around 70 or
60 should be enough. Sorry, 60 and enable best
fit so the text can resize, set the phone to visitor and
also change the color to the orange color
that we have here. I'm going to align
the alignment to the middle and also align the vertical alignment
also in the middle. Our text sits nicely
on the middle here, and set this text
to let's say 100 my k the second one
would be 100% rescue. And the third one should
be stay untouched. This would be
achievement list here. And for this achievement,
we need to set its color to the same color, but with a much lower Alpha, maybe around 75 on
the Alpha value, so we can see that we haven't
unlocked this achievement. And now let's create a script. So under the Data script folder, I'm going to create
a new C script, and let's call this left
menu and open up the script. Okay, now, since we are
going to handling our UI, we need to import
the UI namespace. So let's just do that
using Unity engine UI, and we need to create
a couple of variables. The first one we need to
create is the button, and this would be
the play button. And we also need a reference to our scene and which
is in string. Let's just call it syn target, and then we need to create
a couple of text fields. The first one would
be our kill text and then rescue text, and the last one would
be the untouched text. And I'm going to create also
a color for our text here. Let's call it this
disabled color and enabled color. Okay. And on start, we are
going to grab our metals. So now we need to create a private variable types of
metals and the scene metal. Let's call this scene metal. And upon start, we want to get this scene metal based
on our object name here. Sorry, the scene target name. Let's just fill the set metal with the stats
manager, instance. And the achievement list here, and we can grab based on our string of the name of
our scene target here. And we can make sure
that only grab this when the achievement list contains the key
of our scene here. So like this, and
this is to make sure our achievement lift have contains the key
of our scene here, and if it's contained,
then we want to grab that. We need to also create a public method for
update menu here. I'm going to remove our plates. We are not going to use this. We need to also create a
local method for go to level. Okay. And we are going to add this to our
button listener. So let's just type
the play button, click add listener, and we
are going to add this method. So just type go two level. And this go two level, we'll access our
scene loader object, and it will access I think
is the change scene method. And it is asking for
a string this method, so we can just pass
our scene target here. And if we pass our scene target, it will load the scene. But before we finish loading,
it will show the progress. Okay. And for updating the menu, we want to set our color based
on our achievement here. Let's just do that. We need to check if our sin
medal is not empty. We make sure we do this, and if it's not empty, then we need to
update our tax color. Based on our result
on our achievement. So we can just use
the bullion here, kill this is called
ternary operator, and we can add a bon or condition in front
of our value later. And after the condition, we
can add a question mark. The first part here will be if the result of
this condition is true, then we want to set
to the enabled color. Enable color for the
color, our k text. And if we haven't achieved
or if the keel is false, then we want to set this
back to our disabled color. This is something that
is much shorter than if we create using if we
can make it like this, but this is much shorter. So if true, then we want
to use the enable color, we want to use the
disabled color. But this is way too long, and this is much simpler
for this kind of statement. So I'm going to use this
one. Let's just delete this. But this is actually
do the same thing, and we can copy this line here, paste this two times, and for the rescue tax I'm going to grab our rescue
bulon from our scene metal, and for the untouched text, I'm going to grab our
untouched bullion here. And we will get this
whenever we finish our Our scene, level. And if the seat metal is null, then we want to set all of this text here
to our disabled color. So let's just delete
all of this entry here. Just leave the disabled color. I save the script here. And since we need
to update this, whenever we load the game, then we need to look we need to find all of the object
that have this component on the scene and run
the update menu. Let's just go to our
stat manager here. And here we have the update item display
here and I'm going to put the level menu. I'm going to create
a level menu array, and this will be the level menu. I'm going to also find
object of type level menu. But this should be
plural objects of type. So we grab all of the object that has this component
in our scene. And I'm going to also look our level menus object
on our scene here, and we can do we like this
the items update display. And we can access its
update menu method on each of our level menu here. So let's just save this
inside our level menu, it if it's not new
that we update this it's we are going to use all of the disabled color to all
of our achievement here. Okay. So now, under the level menu game object here below the
level select panel, we are going to
set up our script. So let's go to our level menu
and our level manuscript. And for the scene target, we have a gameplay scene here, and we want
you to test that. So let's just type the
name of the scene here. And for the play button,
just direct the play button. And for the text, I'm going
to open the HFP lease. The first one would
be the k tax. The second one should
be the rescue tax, and the third one should
be the untouched text. And for disabled color, let's just pick the sorry, the same range, but
the alpha value of 75, so it's transparent and
for the enabled color, we want to choose the full opaque alpha
for this orange here. Let's save our scene.
And for the level menu, let's just go to our prefs
holder under the UI and direct this level menu as a pref safeties and also
for the shop petal, we want to direct the grade item as a prefapx here also here. Okay. So now let's
try this and play. Now if I press play here. Okay, there is an error. Let me check here.
Okay. Sorry. There is an error because we disabled
our scene loader here. So let's just enable this scene loader and enable also
our dialog system. And let's try to place
this once again. Game play is loading. Okay,
it's successfully loads, but somehow it doesn't
show our panel here. So let's just check our
scene loader script. Okay, I think I found
the issue here. We disable our panel,
but we never activate. So basically, whenever we are loading our scene here
before we start loading, we need to enable
our panel here. Okay, so let's just
try this again. As you can see, we
have a loading system, and now it loads to
our game nicely. Okay. So there is an
issue with the lighting, if we transition from
another scene before, so let's just fix this,
go to our gameplay scene. Basically what we need to do is we need to go
to our lighting, go to the window menu and
under lighting settings. We need to disable the
auto generate here, and we need to generate
lighting once. So let's just pick the
lighting one time. And after it finished picking, it will have the subfolder
with it will have subfolder with the same
name of our scene that we have to pick and save the scene. So if we go back to our
menu here and we play this, and then if we try to go
to our scene that scene, it will have the
correct lighting. Okay. So yeah. And
in the next video, we are going to continue to work on this
button here. Okay.
46. 46 Level Menu part 2: In this video, we are going to continue working
on the level menu, and now we are going to extend the level manager script
on the gameplay scene. So let's open the
gameplay scene. Let's focus to the
environment by selecting the environment
and press the F button. As of now, we don't have any Canvas object
in the scene yet. Let's create a new one by going to the UI menu and
then click Canvas. Okay. And for the
Canvas scale value, let's set it to the scale
with screen size and set the reference
resolution to 901,600. Next, we want to create an empty game object as
the child of the Canvas, and this is going to
be the level NS panel. Set its size to 600 by 500. Next, let's create an image
as the child of the panel. I'm going to call it
background and scale it using the most bottom
right anchor preset. Don't forget to hold button. Let's set the color to black, but with a slight transparent
value of 120 on the alpha. Let's take a peek
at the gate view. Now we have this dark tin panel. Next, we need to
create a button to navigate back to the menu
scene when the level ends. Set the position to be on the
bottom area of the panel. And adjust the
size to 200 by 75. For the image, let's pick the UI frame and set its color to the orange
presets we have saved before. And then select the
child text object, change the phone to visitor
and type exit for the text. I'm going to also enable best fit option and change the color to
the orange preset, and I'm going to also increase the text maximum size to 60. Next, let's create
an empty game object as the child of the
background object. This is going to
be the UI layout. I'm going to stretch
it to fit the parent. But I'm going to add a space for the bottom margin and set the number to around 85 and
set all of the other margin, which is left, right,
and top margin to 15. Let's rename the
empty game object to achievement and then add a vertical layout
group component. Next, we want to add a text as the child object
of the achievement and change the phone to visitor. I'm going to rename
this tax object to keel and this will be
the enemy k achievement. Change the text color to the orange preset
and set the text to 100% enemy k. Enable the best fit option and
resize it horizontally, so it fits the parent panel. For the height, I'm
going to round it to 80, and then let's set the
alignment to middle and center. We can also increase
the text maximum size to 60 so the text
is more readable, and let's duplicate
the text twice. I'm going to rename the
second one to rescue and set the text to 100% rescue. For the third one, let's
rename the object to untouched and set the
text to stay untouched. Next, we need to dim the text. Let's select all of the
achievement texts and modify the color by setting
the Alpha value 275. Next, we need to create a script to record the achievement
when the level ends. Let's create a new one
inside the scripts and gameplay folder and rename it to game script,
and let's open it. First, we need to import
the UI name space. Let's add it on the top area. Then let's create a
couple of tax variable. Because we are going to
modify the achievement tax, let's call it kill tax, rescue tax, and untouched tax. We need to also declare a button variable and let's
rename it to exit button. We can safely remove
the update method, and I'm going to change the start method into
un enabled method. Next, let's create
a routine method. We need to set the return
type to enumerator, and we can call it
show achievement. We need to also create a private variable
with the type of weight 4 seconds to add delay
inside the routine later. Let's just call it
interval and initialize it with a value of 0.5 seconds. Inside the coroutine,
let's delay the coroutine first using
the internal value. And we are going to work
more on the coroutine later. Next, let's create a new
method called B menu. And here we want to
load or go back to the menu scene using the change scene method from
the scene loader object. Inside the un enabled method, let's assign the B two main new method to the
exit button listener by accessing the unclick
property and then pass the method as an argument
into the add listener method. We need to disable
the exit button first by setting the
interactable value to false, and we are going to enable the button when the achievement
result has been shown. Now, let's work
on the coroutine. Below the delay,
we want to modify the tax color starting
with the keel tax, but we need to create two public variable
type of color first. The first one for defining the disabled color and the second one for the
enabled color. For the ke tax color
inside the coroutine, we want to assign the text color depending on the
metal achievement. Using ternary
operator, we can check the k from the level manager
instance metal object. If it's true, set the
color to enabled color, else, set it to the
disabled color. We can duplicate the
line and paste it twice, one for the rescue
tax and the last one for the untouched
text don't forget to change the achievement
also to rescue and untouched for each of
the corresponding text. Let's also add delay between
modifying the text color. We can copy the yield
return interval line and paste it in between. This way, the achievement
text will be revealed one by one with an
interval of half second. After we reveal all
of the achievement, let's add another delay, and after the delay,
we want to set the exit button
interactable to true. This way, we will
enable the exit button. We need to run this core routine inside the un enabled method. Let's just add a start
co routine command and pass the coroutine
name into the argument. Let's save the script, then head back to unity. Now, let's attach
the game script onto the left game object, and let's set the field with
the correct value or entry. Don't forget to assign the button object to
the exit button field. For the disabled color, let's set it to the orange
color from the preset, but set its Alpha to 75. For the enabled color, we can just pick
the orange color preset with no
modification needed. Now, let's save the scene, and I'm going to disable
the level game object, and we need to enable
it when the level ends. Let's select the level
manager game object, and we can drag the level same object into
the on game event field and pick set active method from the game object component
and set its value to true. This will activate the level game object when
we defeat the bus. Next, we need to add a new method on the
stats manager script, Let's create a new public
method called metals. We also need to add
two parameters. The first will be a type of string and we can
call it level name. The second one will
be a type of metals, and let's just call it metal. Inside the method, we are
going to add an entry to the achievement list dictionary with the key of the level name, and for the value, it
will be the metal object. This way, we will be able to grab the achievement list
based on the level name. And we need to execute this method from the
level manager script. Inside the core routine, when it finished calculating
the achievement, let's add a call to the Ed metals method from the
status manager Singleton. But because we need to pass
the C name or the level name, Let's import the scene
management namespace, and let's also create a new private variable
type of string, and we can call it level name. Inside on Awake, let's grab the scene name and save it
into the level name variable. Using the get
active scene method from the scene manager class and then get the
name properties. This will return the
current active scene name. Once we cash the
active scene name, we can pass this variable
into the metals method. For the second parameter, we want to pass the
metal object that contains the current level
session achievement. This way, the achievement
will get saved by the status manager script into a dictionary with
a specific key, which is going to
be the level name. Then we can use this
data to display the achievement on the level
manuscript as shown here. Hey, this is Romy
from the future, and I want to inform you a bug that is happening
in the future. Inside the metals method on
the stats manager script, if the achievement list already have an entry
with the same level name, this method will cause an error. We need to check whether the
achievement list already has an entry with the level
name pass from the method. But before that, let's create a new temporary variable
with type of metals, and we can call it new metal, and we need to also
initialize it. Next, we want to check
if the achievement list already has a certain key
using the content key method, we can pass the level name, and I'm going to add an
L statement and paste the achievement code
inside this L block. Inside the true block,
we want to fill the new metal object
achievement values with the metal passed
by the method. For the first achievement, let's set up the k achievement and using a ternary operator. We can check if the
metal k value is true. Which is received from
the level manager, then we want to set
the value to true. Else we want to get the
previous value we have from the achievement list by passing the key and
get the kill value. This is to prevent a false value overwriting a true value. Otherwise, if the
player succeeded in achieving the kill medal
in the previous session, but then replay the same level
and failed to achieve it, the failed medal will overwrite the previous one
that was a success. Of course, we don't want
to upset the player. Let's copy the line
twice and change each to the rescue
and untouched medal. Once we finish set
up the new medal, we want to set the
achievement list with the level name as the key
to the new medal object. Let's go back to unity
and give it a try. But before that, we need to add the status manager
Singleton to the scene. Let's go to the prefs folder and inside the manager's folder, let's direct the game
manager pref into the scene. We need to also add the
scene loader into the scene. We need to also update
the level menu. Basically, we need to copy
this statement line here, and we need to paste it inside
the update menu method. Whenever the menu gets updated, it will also try to update
its achievement list display. And this is Romy again from the future trying
to prevent bug. Inside the start method
of the level manuscript, we can comment out
this if statement, and we need to run the update menu method to make sure whenever the menin started, all of the level entries will update its achievement
list from the start. We can actually delete the
statement on the start method because we did check it inside
the update menu method. But for now, just to
be on the safe side, I'm going to common
Vector Unity. Now let's test the changes. I'm going to fast
forward to gameplay. Now let's just defeat the bus. And it's defeated. But I've only managed to get the enemy
kill achievement. It's okay. Let's just click on
the exit button. Now in the menu scene, we can
see that we have unlocked the 100% enemy kill
achievement on level 01. If we want to
create a new level, we can either create a
new scene or duplicate the previous gameplay scene and modify the environment
enemy types and position, also the level layout. Then we can duplicate the level menu game object in
the menu scene and set the scene target value to be the name of the new
level scene name. Now we are finished
with the level menu.
47. 47 UI Transition: Okay. So now we are going to do the last finishing for the UI. Basically, now we have this shop panel and also
the left side panel. We need to make a way for the user to switch
between this panel. So let's get started. We need to create
two new script. I'm going to create a new folder first inside our scripts folder. So it's neatly organized, and I'm going to call
this folder UI scripts. And this will be the UI screen. The first one, it would
be the UI screen, and the second one would
be the UI manager. So first, we are going to
work on the manager first. So let's just open this up. And what we want
to do is we want to create a coupon of variable. And the first one will be
our UI screen variables, and this would be
a type of array, so I'm going to just
create a new private. And since we already
created the script, we can access it
class UI screen, and this would be an array, and this would be
our screen array. Okay, let's make this public. I decided to make this public, so we can see it
in the inspector. The next thing we need to
do is we need to create a new private variable
and this will be the type of UI screen. But this will be our
current enabled screen and our previous screen. The first thing we need
to do is we need to grab our UI screen
in the child object. T U manager will sit on
the parent object of our shot panel and also
our level sector panel. Just type the screen
array and then I'm going to use the method called
get components in children, which is plural, and this will return all of
the components of type that we defined here in the game object
or any of its children. And for the type, we
are going to grab the UI screen class, and as usual, this is a method, we need to close it
with the parent to see. And we can just
type trough here. And what this means is this will include the
inactive child game object. It will also grab the
child object that is inactive. Let's say this. The next thing we need
to do, I'm going to create a initialization method. The init method we'll
need a integer parameter, which is going to
be the default UI. This will look through
our screen array object. We are going to grab its length. We want to make sure
that if i is equal our default default UI
that we defined here. We want you in the screen, and also we want to
set our current screen to this screen
array index of the. And I is equal our default
that we defined here. We want to disable the screen. Sorry, to activate the
screen, and this one, we want to disable the screen. Enable disling the screen, we'll be handled by
screen class here. We are going to create
this in a moment. Save this. Now, start, I want to initialize our
first screen array, remember. Zero. Since with array or
less, it starts from zero. So I'm going to initialize
and I want to enable the first UI that is grabbed by this get
component method here. Let's delete the update method. The next thing we
need to do is we need to create a
new public method. Method is going to be
accessed by the button. So let's just change
screen this change screen. And for the parameter,
we are going to pass a new icecream class here. So let's just type icecream. And this will be
this new screen. And we are going to check
to make sure that if our new screen is not
empty, it is not null, then we want to go
execute the code here, and we want to check
our current screen. If our current
screen is not null, or we can just type it
like this much easier. Then we want to set
our previous screen to our current screen, and then we want to hide
our previous screen. But since we haven't
defined the method, then I'm going to
create a comment here, disable the previous screen. And then we are going to set the current screen
to our new screen. And then we want to show
our current screen. And since current
screens is already changed and already insert
with the new screen here, we are going to show
the new screen. Okay. We can create a new method, but I don't think we need for
now, let's test this out. Sorry, test it. Let's continue. And let's go to our U icecream. For the U icecream,
we are going to create some sort of fate effect. So we are going to create
a new float variable, and this will be the app speed
and also the height speed. And the value probably
will be default to 0.5 on each of the float here.
Let's just type that. And then we are going to create a reference
to our Canvas group. Basically, a vast group is a component that will group
our canvasse together and we can control the
alpha of all of the UI element via
this Canvasse group. The transparency will
change together, even though that UI consists
of many child object, and let's just type
this Canvas group. We are going to remove
this build in method, and we are going to use
the void wake method inside the wake we want you
to grab our canvas group. So we will have this
canvas group ready before any start
method gets executed. Let's just type Canvas
groups the type here. And we need to close
this with a set of parenthese And the next thing we need to do is we need to
create a new public void, and this would be the
init method that we need to initialize
via the UI manager. And I'm going to add
a bullion show here. And we are going to
change our Canvas group properties
inside the unit. So basically, I'm going to modify the Canvas
group Alpha first. And for the Alpha,
we are going to use a ternary operator, and which we are going to make
sure if the show is true, then we want to
set its Alpha 21. But if it's false, then
we want to set 20. So this is I show is true, then set the Alpha 21. But if it's false, it
will be this value here. The next thing we need to set is our canvas group interactable. And we are going
to grab the bully and right away because
if we set this false, then it will not
be interractable, because the interractable
will be false. And the last thing
we need to do is, I think block we are going
to set this also show. Okay. Now we have this
inside our UI manager, we can activate initialize and also disable the
screen. How do you do that? We can just type the
screen array index of, of, then we can type. For the first one,
we want to activate. So we need to pass true value
inside the init method. But for the other
screen array index is not the same
as our default UI that we intend to activate here, we can set this two false. Let's just type screen, x of i, and then in it, and
then set this false. Okay. Let's go back
to our UI scream. The next thing we need to do is we need to create the animation. We need to create
a coroutine first to create some sort of
animation for the Alpha value. Let's just rename
this modified Alpha. The first parameter we need
to insert is the Alpha value. The Alpha target
and also the speed. The next thing we need
to do, I'm going to put a action callback. For this callback,
we need to be using the unit engine events and the unit action class will be available
once we import that. Let's just type
this unity actions, and let's call this callback. We can pass any method and we can execute
this method after we finish animating or modifying the Alpha to the
Alpha target value here. So, let's type this here while our Canvas group Alpha is not the same as
our Alpha target, then we want to keep animating its value until it has
the same value here. We are going to modify its
canvass group alpha using a math this will float value and the
starting float value will be our alpha, our current alpha, and
the target will be our Alpha target here
that we defined here. For its speed, we are
going to use the speed, but we are going to
multiply this time ta time. If we set the speed 21, this animation should
run for 1 second. And we want to snap if the value is very low or very
near to our alpha target. Let's just check that
out using the statement, if the Alpha is greater
than Alpha target -0.1, the Canvas group
Alpha is smaller than our alpha target added by 0.1. Basically what is
trying to do is we want to set our Canvas group
Alpha to our Alpha target. So basically, if our
alpha is greater than let's say if the
alpha target is one, then -0.1 would be 0.9. If our Alpha is
greater than 0.9, we want to set this
to one right away. And if our conaharget is
zero and added by 0.1, and if we are twining or
changing our Alpha 20 from greater value then if the
Alpha is smaller than 0.1, we want to set this
20 right away. We want to snap when
the value is very near, we want to set this, so we
will exit this loop here. And then we need to
type return null. And since we have this back,
we want to invoke that. So we can check this if
Callback is not null, then we want to invoke it. But we want to set the default
value to zero to u so we don't have to assign a method every time we're using this modified
Alpha method. Now we have this
modified alpha routine. We can create the show method
and the height method. So I'm going to create
a new public void show. And for show, we are going to
set all of this value here. We want to set the
start Alpha 20, and we want to set
the interactable and the block a
catch you through. And then we want to run T.
Since we start from zero, then we want to set using
the modified Alpha. The first parameter,
which is the Alpha g we want to set this 21. And for the float speed, we
want to use the appear speed. So we can change this
on our inspector later. And for the callback we don't want to use any Callback
for the show here. But for the height method, then we want to run
the co routine way. I'm just going to
copy this line here. But I want to set the
value target Alpha 20, and I want to change this appear speed to
our height speed, and we want to run a method. But it's not a method.
We want to create a delegate or Lambda expression.
And it is like this. So basically, two set of
parentheses, equal sign, and then right arrow and
then curly brackets, and we want to put the code
inside this curly bracket. Here, I'm going to enter
this for readability. And this is basically like
I'm not sure which one, but let's check
this test manager. Oh, sorry, the upgrade. I think is the upgrade item. Yeah, like this, this that we created before for
the show dialogue. The show dialogue requires
actions, and for the actions, we are putting the delegates
here, as you can see, and we run a set of codes
inside this Lambda expression. So go back to our ice cream and I want to run
the init method. I want to reuse our
previous function, and I'm going to
set this to falls Beish modifying our Alpha 20, then we want to set
all the value to zero, and then we want to
disable the intertable in the block k. So our
hidden screen doesn't block our interactions
to the other screen that maybe lies on the layer below
and our hidden layer here. So yeah, let's just save this. And once we already have this, all we can just hide and show. So we already activate the screen and disable
the screen in method. But here we need to disable
the previous screen. So just type previous screen, and then we are going
to use the height. Because when
changing the screen, we want to switch the
screen gradually, so we are using the height,
and this height method will run our core routine, modify alpha, and it
will set the Alpha 20. And for the showing our screen, we want to type
the current screen and we're going to
use the show method. Now we have this two script
done and make sure it's safe, and let's go back to our unity. So here there are couplets
we need to set up first. First, we need to
create a new anti game object below our canvas. And this would be
the screen manager. And I'm going to set this to
stretch to our scene here, and I'm going to put our
shop and level selector to be the child of
screen manager. And for a shop and
also the level sector, I'm going to add a
UI screen screen. And we need to create
a Canvass group. So if you haven't, just add a
new Canvas group component. And I already did that before. So here, and there's
nothing we need to change inside the Canvasro component
da to our UI screen. And also for we can
just drag this. But I don't think we
need to drag this. I forgot because inside
our U ice cream, we are grabbing actually on a wake so we can just
change this to private. So we are not confused with it. Sorry, I forgot to just
set this to private. Once we have set
this to private, the value here should
not be shown yet. Okay. Now we have UIcreen in
the screen manager below. We need to put the UI manager to screen manager here on run, it will grab our child
object right away all of the child object that has
the Ucreen component. Now let's hide our
screen loader here. I'm going to create a new
button to switch between our left and our shop screen. Let's create a new I'm not sure, which, create a new button. And for this button, I'm
going to put it here. And for the anchor, I'm going to change to a position
around here, I'm going to set this
to our top left here. I'm going to resize the button. So it is much bigger. Then I'm going to set this
would be our left selection. Maybe that space to keep
the convention the same throughout the scene
game object naming. Let's change its art
to our frame here, frame and let's
change its color to the usual range that we have been used over
and over again. For the text, I'm going
to set the font to our visitor and set the
best fit to enable, and this will be our level and change its color also
to the usual range here. Check if we go to the game
screen, we can see it here. And let's create a new button and move this to the side here, and this would be our
shop panel button. And for the text
object, just change its caption to shop like this. Now we have this
two button here. We can on each button, we can just add a
on click event, drag our screen manager, and run the U A function inside the UI manager or
method, which is change screen, and for the level selection, we want to drag the
level selector panel as the UI screen parameter that
we need to feed you here. Also for the shop panel,
we want to create a new on click event, and let's direct
the screen manager, and we want to run the method inside the UI manager class, change screen and this time, we want to direct
the shop panel. And I want to make sure that our selector panel
is on the top here. So it will fill the sorry, it will fill the first
member of our screen array. So let's just save
the screen here. And now let's try this, see
if it's working or not. So now, yes, as
you can see here, we have show the
left panel here, but if I press shop, it should change to our
the other shop panel. Okay. There seems an issue here. Sorry. The shop panel
needs to enable first, because we are looping through the UI here and we
want to run the script. The script. Save
the screen again. I think the speed
value is too slow, so let's select
both of this panel here and change each of the value to save the screen
save the scene again. Let's try again. Okay. Yeah. Now if I press change to our shop
and if we press level, it changes to our level
again. As you can see there. And you can have as many
screen if you want to and just put screen and the screening manager
will handle the rest. Basically, you need
to create a button, just to show which panel that you want to show
for that button. Yeah, I think that
concludes our UI setup. One thing we can do is sorry there is an issue
here, as you can see. If animation is running, it will cause issue here. So we need to make sure
that doesn't happen. We can create some sort of event that we can subscribe
on our UI screen. Let's just create a public
event and this will be an action action action. Oh, we need to use
the system space, so I'm going to use the
system here and type action. Let's call this on changing, and this will be
a delegate here. Basically, or we can just change And here we can run this
done change whenever we finish the modifying. Let's just run done
change here like this. And for the UI manager, we can create some sort of
a private private bullion, and let's just call
this is changing, and the default value will
be, of course, a false, but we need to create a
method that will set this to true switch done switching, let's say the done switching, and for this done switching, we want to set the
changing to false. We want to make sure
that we want to check if it's
changing over here, then we want to return.
We don't want to run it. But if it's not, then we want to set changing to true here. Because if it's
changing is false, then this will be ignored and we will go to this code
here and then we want to set this to ro and then we also want to subscribe to
the De switching here. But for the done switching, we can subscribe
on the start here. On the start, we cannot do that because
we need to subscribe to our current screen to the new screen event here because each of the
screen will has this event. So we need to make sure
which event that we are subscribing to sc
or which class. So whenever we set this, we want to subscribe
from our new screen. So let's just type new screen. Done change, then we want to add our method switching here. Sorry, without parentheses here. Okay. We want to clear Sorry. You want to clear any
event that are registered, I think let's check this. Okay. We want to remove
registration first, if there are any, and
then we want to create a new registration to clear. Let's just test this out. I think we need to make sure this is worked correctly later, but let's just try
this we can go to our screen manager here and
enable the bug here so we can see is changing value here. Let's just try to
run this again. Right now, it's false
and whenever we presos when it's finished,
it's go to false again. As you can see here.
And if we press this, Yeah, we have an issue here because we are
pressing the same button. So we need to make sure
that doesn't happen. Here if it's not changing, if we are currently changing, then we want to return or
we want to make sure if our current screen is the
same as our new screen. Whenever one of this is true, then we want to return this. We don't want to run the
code. Let's try this again. Still compiling. This is false, changing and change it through until it's transitioning
and it's false again. And if I press shop
again, nothing happens. But if we go to level, it's
true and then false again. We it's in changing process, we don't want to create
some sort of like this, like this, we don't want
to as you can see here, when it's transitioning,
nothing happens. But if it's finished
transitioning, then we can go to
the other screen. Yeah, that should
do with our UI, but we can create a nice screen effect if we
want to. Let's just do that. Go to our camera
first, main camera, and I'm going to set
it back to normal, and let's use a solid color
and use a black color. So as you can see
here, it's very nice, but we can add our game
object as a background. So let's just do that.
Go to our camera here. And let's put our plane
model as the background. And our play model should
be our plain A, I think. Yeah, correct. Let's just
drake this to our scene here. And there is our game object. But we want to make sure it's a position close to our camera here and
rotate this 90 degrees. Something like this. But we
can adjust the position here. Okay. Yeah, maybe
something like this. Should sorry, I'm going to change the
value around the value. Save the scene, and
if we play this, we should see that we can change our scene and we have this
nice background here. Yeah, but you can design to
any design that you want to and we already modify the
script during transition, we cannot interrupt
the transition. Okay.
48. 48 Finishing Up UI: In this video, we are going
to create a script to handle and updating the
money display in the menu. Inside the scripts,
UI scripts folder. Let's create a new
C sharp script, and we can call it Update money. And then let's open it. Because we are going to
access the text UI component, let's import the UI
name space here. And next, I want you to create a static reference
for this class, so we can access it
easily from other script. So let's declare a
public static field with type of update money, and we can just
call it instance. I'm going to change
the start method into an awake method, and I'm going to initialize the static reference
inside this method. So let's type the
static reference name and assign it with this keyword. Next, let's create
a new public method called Display Money, and we want to pass an
integer as the parameter. Let's call it value. And I'm going to create a public field with a type
of tax called money display, so we can access the tax UI that are going to display
the money amount. And inside the
display money method, we want to change
the tax property to equal $1 sign in string with space and concatenate it with the value argument converted into the string using
two string method. And we want to also add a start method so we can
update the money on sentart by running the display
money method and pass the money value from the
stats manager do instance dot M. We need to also update the money whenever we add the money from the
status manager script. So let's call the method from
inside the add many method. And using the static reference, we can access the update
Many script right away and then type
dot instance and then call the display
My method and pass the updated money value
into the methods argument. So now we need to set
up things in unity. Let's expand the Canvas. And on the money
display game object, let's attach the update
money script onto it and assign the tax component to the money display field. Now let's save the
scene and test it. Now as you can see, our
money is displayed here, and we can try to
buy some upgrade. You see, the money will
also gets updated. We need to also disable the buy button when the
update is in progress. Otherwise, the user
can press on it again, and it will throw an error. So let's open the
upgrade item script. And inside the by
upgrade method, we want to check if
the item upgrade is currently in progress or not. And if it is, then
we want to show a message using the dialogue manager dot instance and call the show message method and pass a message
which is going to be the stat name and concatenate with a currently
upgrading string. And then we can
return the method to prevent the code below
from getting executed. So back to Unity,
let's test this out. Now, if I try to buy an upgrade and press yes
and try to buy again, while the upgrade is running, it will show the message that the item is
currently upgrading. Hey, this is Romy
from the future, helping out to prevent a
bug before it happens. As of now, there
is an issue where the money display is not updated when we load the programs. So if we run the game
and buy an upgrade, you'll see the
money gets updated. Let's try to save it
and stop the game. And then we can try to
run the game again. Now if we try to load it, the money will stay at
500. So let's fix this. So on the update Manuscript, and don't mind the display
core method for now. Below the display money method, let's create a new
public method with a wturn type of void called
update money display. And inside this method, we just want to update
the money display using the display money method and pass the current money
from the stats manager. Now that we have
defined this method, we want to call it from
the upgrade item script. Inside the update item
display method to be exact, since this method gets called whenever the user
loads the progress. Let's access the update
money static reference and run the update
money display method. Let's save this and
head back to unity. Now if we try to run the game and then buy an upgrade,
and then save it. Let's top the game
and play it again. Now if we load the progress, you'll see the
money gets updated. This concludes the
finishing up UI lesson.
49. 49 Sound: So now we are going to create
the audio system and we are going to complete
the audio setup for our other object that
we need to add on. So let's open our
gameplay scene. It's currently
opening. Okay. And I'm going to disable our
s loader first here. And now we need to set a couple of things to
have an audio first. Okay, so we are going to create a new
script for the audio. So let's just
create a new folder and call this audio script. I'm going to create a new script called random audio.
Let's open the script. And now we need to
create a array of audio. Let's just create a new public
audio type of audio clip. This is where we
are going to store our different type of audio. Let's call this audio clips. We need to create audio
variable types of audio source, and this would be our
audio or this audio. We are going to make
sure that this component will require a component
type of audio source. Whenever we are going to add
this to a new game object, it will add the audio source
automatically to that object also start, we
want to grab that. Type this audio and use the good game component method and pass the class here
and close the method here. Save this and we are not going
to use the update method. But we are going to create a bulon bull on enable
or play on a wake. Sorry, not a method. We want to set this by theft to true. We are going to create
a public method first to playing the
audio, play audio. And we want to also create a float and this
should be floated, but I'm going to set this
pitch random or random pitch. Yeah. And this would be I'm going to create a attribute
for this public variable, and this would be type of range. The minimum value would be 0.8. The maximum would be 1.2 and be flow I'm going to type f
at the end here, and Yeah. Like this. You should do and I'm going to set its
value by the 421. So the perfect pitch, the normal pitch, and
this will be a deviation. Okay. This is somehow wrong. Just set the man
pitch to 0.80 0.8, and the max pitch 1.1
should be enough, I think, 0.9 should do, but we can change this in
the inspector, of course, it doesn't really matter
what value we set here. This will be the default value, whenever we play the audio, we want to set it pitch
to this value here. We are going to access the
pitch of this audio here. Pitch, and we are going
to insert a random range. For the minimum value, we are going to use
the main pitch, and for the maximum value, we are going to use the max pitch. We will have some random value between the two value over here, this is 0.9 and 1.1. Whenever we play the audio, it will have different pitch
to differentiate the sound. It doesn't really
sound monotonous. The next thing we need to do
is we want to play random. So here, we can put
an integer if we want you sound ID or Audio ID. Let's just play this audio
by using this audio. And we can access the play
one shot method and grab the audio clipse from our audiolips array and
insert the Audio ID. Yeah. Like this. This method are going to be used whenever
we want to play the audio. And we can set this on enable. This should be one on start. So we will have this
component grab before this is executed because on enable usually
executed before start. We need to put this
initialization inside awake. We can just play the audio. We want to make sure
that if on awake, then we want to play the audio. But we want to use
a random integer. We can use the random range
for the random range, random range random
random range. The minimum value
will be the zero, the first index and the
maximum value will be our audio clips dot length. So this will make sure how
many audioclips we put inside the audioclips array
going to make sure that all of the members
inside audiocyp have chance to get played
by display audio here. So, let's just save this, and I think that should do. Let's go back to unity. We are going to put a couple of things in the
prefect for example, we want to put explosion
sound under our explosion. So here we have the audio
source already added and we can add the play
random audio component here, and for the audio clips. We can just lock
this inspector here, so it doesn't get changed and go to our audio folder and we can put of the audio here
up to explosion four, so it will have different audio. The next thing we need to do is on our weapons on bullets. We want to put some audio, so I'm going to unlock this
inspector here and add the random audio and it will automatically add the
audio source here. And we want to
lock this and also go to our audio and put all of the three shots file to
our audio clips here, we can just copy this value, copy this component here, unlock this and select
the enemy bullet, and we can just paste
this component, and it will have the same value. And also for a missile,
we want to do the same. Let's just paste as here. But we want to set
the size to one. And if we go to our ADO, we have this missile sound file. We only have one, so
we can just use this. I'm going to copy
this component here, go back to our weapon,
player missile, and I'm going to paste
this as a component. Okay. Yeah. Save the
scene and let's try this. Okay. Now we have sound
for an can see here. It's very nice. We
have sound now. Now we can. Okay.
So, you can see, we have this work. And there is another
thing I want to choose. Sorry, to create the
sound for the box. So let's just stop this first, and let's go to
our bot activator. And whenever we are enabling the second touret I want
to play a certain sound. So when we finish destroying the first Trett
we want to play a sound, and I'm going to put
the audio source. Here, since we are
using only one sound, we don't need to use
the play random audio. I'm just going to use this
and set this to play on weak. Since these are
disabled on start, whenever it gets enabled, it will play the
audio automatically. We are going to Go to our object and we are
going to use this one. I think one. Sorry,
I should be I want to use this sound for playing whenever the boss are
enabling the second weapon. Track this machinery,
I think I forget. Sorry, mechanic machinery. Go to second game object. Machinery mechanic machinery
and then for the first one, I'm not sure. Should we. It's already been enable,
so we don't need that. And whenever will create
explosion. Okay. So yeah. Let's just adjust
our bus position, so it's not too far away. Make sure we move this I click this help butatn
here to ffixty 60 b. Yeah, I think so or 55
should do the trick. If we enable the bus ship here, let's see the track
of its movement. We need to move the notes here. So the first notes, we are
going to move the first one run this position here, and the second one
to this position. So we don't have to wait
so long until the bus shows up and Okay, I think I moved the first on the y x I'm going
to set this 20. Yeah. So now we can just apply this. Sorry. We need to
destable this and apply. Okay, so let's save
the seat again. And let's try this again. Now we have to adjust the duration of the ship object when it gets
destroyed the duration. Destroyed too soon, we
can see that the object is disappearing in the
middle of the s here. So we are going to add. Now we are waiting for the
bus. Human rescue. This is our boss. You
need to destroy it. Okay. When you destroy it, it shows a sounds enabling
the Ms we need to adjust the trajectory to make this Okay. Okay. So yeah. So this time, I have successfully
stayed out you can see. Okay. So yeah. So
that is the sound. And I think we've already enable we already use all of the sound that
we have here. So yeah.
50. 50 Touch Control: Okay. So now we are
going to create a behavior not behavior, a code to handle
the touch movement, so we can move the player
while using the touch screen. So let's just open our
player movement script. And here we have the player
movement script open. We have the player
movement script open, and it's quite easy to do this. We need to create some
condition here between the most position and
we need to create a new preprocessor directive. Basically, using the
preprocessor directive, we can type a sharp sign, and then type and we can add condition if
unit underscore editor. Basically if we
run in the editor, we want to use this most
position, and we press enter, and here, We type L L L and we can type
Unity undercot Android. And to see the list of our
preprocessor directive, we can just go to the
website unit or you can type Unity pre processor
preprocessor directive. And here it will show you the list of platform
that we can define. And here we want to
run the code when we are running the application from the direct from the editor. And if you want to define sets of code that will run
on the Android platform, you can use this, and also
for the other platform. You can see all of the
available list here. So yeah, go back here. But if I type this, it will disable the code. So we need to create
some sort of segment, and we need to create a code. But I'm going to create
it here first so we can use the intelecence
or the auto complete. Otherwise, it will not
show upto complete here. So I want to make
sure that what I've typed here is correct. And we are going to use the ternary operator and
we want to check the input and we want to get
touch Sorry, to touch count. We want to check how
many touch count are currently
touching the screen, and if it's greater than zero. This means that at least there is one touch on the screen, then I want to get the
position of the first touch. So we can just use,
not colon sign, but a question mark. And as you can see here, this is the true part, and
this is the false part. So for the true part, we need to assign
our touch position, get touch, and I want
to get the first touch, so I will type zero as
the index and we can grab it position like this. Since touch pos is on screen space like
the most position, so we can grab the
position right away. And if this falls, then we want to change nothing, so we can just touch
position like this. Sorry. Because the touch
position is a vector, then we need to cast this
touch po vector type. Just type vector and we will
we will remove any error. I'm going to just to
copy this line here. Cut it and I'm going to
paste this inside the unit. Now if we do this, editor, you can test this. But on device, if
you build this, you will able to move it
using the, the touch system. Now if we go back to Unity, now we are going to
create controller for the power apps system.
Let's just do that.
51. 51 Power Up Menu: In this video, we are going to implement the touch menu for the power apps and as well implement the bullet
time features. And now let's disable the shield object first and we can duplicate
the health canvas, and let's move the
duplicated health canvas to slightly in the
front of the ship, and let's just delete the health Bar
background game object, and we are going to
create a new button here. And we can rename this game
object into Powerp Canvas. And we need to create
a couple of button. So first, let's create a
button as the child object. And let's rename this
button to shield button. And I'm going to scale the
width and height to 50 by 50, and let's just
reposition the button. And for this button here, I'm going to change
the image source image to the circle bar here. And let's just also change
the color to a blue color. But I'm going to use
the blue color that I already have here
in the presets. But you can choose
any color you want. And let's just set
the Alpha to 190. And let's also change the phone of the child
object text here to ysitor and we can change
the text to S for shield. And let's also enable
the best fit option. And let's change the color to the same blue as
the circle object. And now we can just duplicate this button and
reposition the button. So it sits on the middle. I'm going to also move
it slightly forward. And let's rename the game
object to laser button. And let's also change the color, and I've already prepared
a presets here below. So I'm going to pick that, but you can choose any
other color you want. And let's change the child
game object text label here to L and change the color to the same
color at the circle bar, and let's duplicate
another button. And this one would
be the megam button. And let's reposition
this mega bom button around this position
should be good. And change it color to green and I've already prepared
a preset for it. And for the text child object, let's change the text to and
also change the color to the same green color as the circle bar. And
let's save the scene. And now we have set
up the power canvas, and let's go to
the script folder and the subfolder weapons, and let's create a
new Chesap script, and let's rename it
to power a menu. And then let's also
open the script. And first, we need to
import the UI namespace. So I'm going to type using Unity engine dot UI
here above because we need to access the button and the text object from
the UI namespace, and let's declare a
couple of variables. And the first one
would be a scope of public and type of button. And I'm going to declare
three variables. The first one would
be the shield button and then laser button. And the last one would
be the mega boom button. And let's also create a public text variable for the shield, laser text and the megabum text. And we also need to have
reference to the Shield script, the laser script and
the megabmScrip. So let's just create a public variable with
those types here. And the first one would
be the Shield script, and I'm going to call it Shield. And the next one would
be the laser script. And we can just call it laser. And the last one will
be the megabomScrip, and we can just call it megabom. We need to also declare
a integer amount for storing the amount
of each power apps. So let's declare here
a public integer. And the first one would
be a shield amount. I'm going to declare this
with a value of three, and for laser amount, I'm going to also
declare it to three. And for the mega amount, I'm going to set
the default value to one, and let's
save the script. And next, we need
to create a method, and this method will
activate the bullet time. So we are going to change the
time scale in this method. And we need to implement
a parameter for this method here with a type of bulon and we can
just call it slow. And using this parameter, we can define
whether we are going to activate the bullet time
or disable the bullet time. And we want to check if the
argument value is true, which is the slow variable, then we want to activate the bullet time or we want
to decrease the time scale by accessing the time class and its time scale properties, and we can set this
to a value of 0.25, and this will make the
game play much slower, and this will be four times
slower than the normal speed. And for the Ls condition, which is when we are
disling the bullet time, we want to set the time time
scale value back to one. And we want to also
enable or disable the power apps button based
on the bullet time mode here. So whenever we are in slow
mode, we want to enable it. We can use the bully
and slow value to activate or disable
each of the button. So let's just do that here. And we can just type
shield button and access the game object and run
the set active method. And instead of using a
fixed true or false value, we can just pass the slow value inside this set active argument. So whenever we enter
the bullet time, this will automatically
show the button. But if we are in a normal speed, then this will automatically
disable the button. And let's just copy and paste it and we can change each of the button
to the laser button. And the mega bum button. And here we want to execute
the bullet time depending on the mouse button
state to test it on editor or on the touch
state on the device. So let's just use a
preprocessor directive. We can just type it with a
sharp sign and then I keyword, and we want to check if we under the Unity editor using the unit underscore
editor keyword, then we are going to compile a sets of code inside this part. But we can add an Ls condition
using a sharp LF keyword. And for the directive, we can use Unity underscore Android, and this will compile
the code inside this preprocessor directive when it's being built
inside the device. And we should close the preprocessor directive using the sharp sign and
the NF q word. And if we are on the editor, we want to run this bullet time, and for the bul an value, we can just pass using an
input dot get Mouse button. And for the index,
we can just use one, and this will get
trigger whenever the right click is being hled and whenever
it's being hld, it will set the value through every frame while the mouse
button is being held. And for the date, let's
just type here inside the Unity editor first because with this
preprocessor directive, the intelligence gets disabled, and we can copy it later. And for the date is
quite easy, actually. We can just check for
the input touch count. And whenever the
touch count is zero, then we want to activate
the bullet time. So we can just pass the input the touch count equals zero as the bullion argument
for the method. So with this defined
on the device later, whenever we release the touch, it will automatically
activate the bullet time, just like the one in sky force. And now let's just cut this
code here and then paste it inside the Unity Android
preprocessor directive, and let's just reorganize
the code here. And next, we need to
create three methods, for enabling the shield
laser and mega bom. So first, let's just create
the enable shield method. And basically, first,
we want to check if the shield amount
value is zero, then we want to
return this method. We want to stop executing
the enable shield, which means that we
are out of shield. And if we still
have shield amount, we should enable the shield, but we are going to
enable the shield later. And here below just let's decrease the shield amount first whenever we
use the shield. And then we want to also modify
the shield tax component, and we want to change
the tax properties and set its value to a letter S, and we want to concatinate with the latest
shield amount value. So we can see how many shield
we have left in this level. And We want to also copy this line here where we
modify the shield text, and let's just
paste it on start. So this value will get updated
on the start of the level. And here below, we
want to check again, if after the shield
amount modification, the shield amount value is zero, then we want to
disable the button. So we can just access
the shield object and then set the
interactable value to falls. Now we have defined the
enabled shield method. We can just copy the whole
method and then paste it two times and we can modify the second one to enable
laser and we want to change all of the objects
to the laser variables one. So we want to change
this to laser amount, and we want to also substract the laser amount whenever
the laser is being used. And we want to also
change the laser text. And for the latter, we can
just change this two L, and we concatinate
with the laser amount. Unless we want to compare
the laser amount. And if it's zero,
then we want to set the laser button
interactable to falls. Let's just modify
the comment here. And the last method
is for the megabom. So let's just change
this to enable megabom we need to do
the same as the laser, change the variable
to megabu amount, and we can just
copy and paste it here and also there
and also down below. And for the text, we
need to change it to megabu and change the letter to. And the same with
the button, we need to change this to megabu button. Now we have created
all of the method. We need to also refresh the text on start for
the laser and megabm. So let's just copy the line. And then we need to also assign the Dose
method to the button, so we can just access
the shield button and then access the n click event and then add a listener and we can just pass the
method into the argument. And this will make sure that the shield button will trigger
the enable shield method. And the same goes with
the laser button. We can just access the
click event and then add the listener for the
enable laser method. And the last one would
be the mega Bom button. We can just access the nclick
event and then add Listener and then pass the enable
mega Bom method into it. And let's save the script, and I'm going to delete this two name space above here because
we are not using it. And now we need to check if all of the three
shield script, laser script and
mega bom script has a public method to
invoke the power up. So let's just open
each of the script, and I'm going to go to
the laser script first. And as you can see, we
have this core routine, but we need to create
a public method to trigger this core routine, so this core routine can be
triggered from other script. So I'm going to
create a new one. Let's just declare it public
with a return type of void, and we can call it shoot laser. And inside this shoot laser, we can just pass the start
core routine file laser. So I'm going to copy the
one from the update. But we need to make sure that whenever we are
starting the coroutine, the laser is
currently not firing. So let's just add
a check by typing if and if the laser
fired is false, then we want to
execute the coroutine. And here for the mega boom, we already have a public method, so we don't need to declare one. And we need to also take a
look on the shield script. And as you can see,
we already have a public method
called shield up, so we can just use
this right away. And let's go back to the
Power Up Manuscript. And whenever we want
to enable the shield, we can just call
the shield object and then access the
shield up method. And for the laser, we can
just access the laser object, and then run the
shoot laser method. And for the mega
bomb, let's just access the mega bomb object. And we can run the
deploy bomb method. And let's save the script. Now we have done
with the script. Let's go back to unity. And let's just
attach the power up menu script to the power
up Canvas game object. And now we need to set
up this script here. And we can just direct
the shield button into the shield button slot. And the same goes
with the laser button to the laser button slot. And for the megabum button, we can just direct this to
the megabum button slot. And the same goes with the text, we need to assign
each of the text to the correct tax slot on the script. So
let's just do that. And for each of this script, we can direct the
shield game object into the shield script slot and laser game object to
the laser script slot, and the megabam object to
the megabm script slot. I'm going to re enable the shield and let's
save the scene. And now let's test this. And here, as you can see, we
don't have the menu visible. Okay. But if I hold right click, you see that the
buttons gets enabled, and it's quite hard
to click it here. But if I move the mouse
quite fast to the button, one of the button and
I click it very fast. For example, I click
on this bomb here. You see that we have
triggered the megabom. And as you can see now, we
don't have megabom left. So it says zero on
the text button, and I can also trigger the
laser as you can see here. And it also decrease
the laser value, and I can also
enable the shield. And I can shoot the laser again. So again. Now let's try to shoot
the laser again. And once it's zero,
the buttons get disabled and we cannot
click it anymore. So we cannot trigger
the power apps anymore. This will be much easier
in mobile control. Faster. Okay, so let's stop the game. Hi. This is Rome
from the future, and there is a couple
of bugs that I need to address with the power a
menu and the shield script. So first, in the power a menu, basically, whenever we
activate the bullet time, the motion that are related to the physics time step will
be chop and we need to fix this to change the fixed Delta
time value because fixed data time value
is a fixed value, depending on the
physic time step. So we need to multiply those value with the
time scale here. So in order to fix this, we need to create a new
private float variable, and this would be the
default physics steps, and we're going to save the default physic
steps on start. Inside the start method, we want to assign this
default physic step value to the time fixed Delta time. And then whenever we activate
the bullet time here below, we want to change the
fixed Delta time to the default physics step and multiply it by the
time time scale. So here we can just
type fix Delta T, and then we can use the
default physics step and then multiply this by the time time scale that
we have changed here before. And here we want to also set the fixed Delta time back to
the default physics step. So let's just type
time fixed Delta time, and then we can just assign back the default physics
step value here. And with this line here, this will make sure all of
the animation that are related to the physics or fixed update are going to
be played very smooth, even though we are
in a slow motion. And the other thing
that we need to fix is the one in the
shield script here. And basically, whenever we are triggering the
shield up here, we want to check if the
collision is enabled or not. So if the call is not enabled, then we want to run the
engaged shield co routine. Otherwise, if the
call is enabled, that means that we are currently
running the co routine, then we want to skip
this code here. We will also need to fix the touch control with the bullet time because
as of this moment, with this code here, we cannot
trigger the menu at all. Whenever we try to touch it, it's disabled the
menu right away. So let's just cut this line
here and let's put it inside the Unity editor
preprocessor directive so we can have the
intellence activated, and we need to import
the Unity engine the van system namespace. And basically, this
is a namespace for using all of method and objects related to the vent system for
the UI interaction. And here, inside the
second bullet time method, we need to add an condition after the input dot
touch count equal zero. And for the second condition, we want to check whenever
we do touch the screen, but it's on top of the UI. So we can use the
event system class and we can use the
current properties. So type event system
dot current we can access the pointer
over game object method. And this method as
for a finger ID. And since we are only using one touch for
controlling the game, we can safely use the
first index of the ID. So we can just pass a
zero into the method. And then we need to cut the
code here and then paste it back to the Unit Android
preprocessor directive, so it will get compiled whenever we build
it to the device. So yeah, let's just
save the script, and those are the fixes that needs to be
done in this video. Okay, so now we have implemented the power apps, and
also the bullet time. Conclude the lessons and we
can go to the next video.
52. 52 Applying Stats: So now we have created
this menu here. We need to update our shield effect and
also the megabm effect, the radius and the damage and also the laser to be according
to our game manager here, like I think it should
be, not the upgrade list, the megabmrad value here, and also according to the shield upgrade list and
also the laser upgrade list. So let's do that. And go to our shield
script first. Now we can change the
value from start. We can grab the
shield duration in start and we can get it
from our stats manager. Let's go to type the
shed duration here, and we want to fill the value
from our stats manager, and we can get instance, we need to access it
static reference. Now we can get stats
value stats value. For the stats name, it will be the shed. Let us check this. Okay. Okay. Whenever we want to get the Stats name and for the
Stats name, it will be D. Okay. Shield. S should be the shield and
once we using the stats name, we want to get from the list shield upgrade
list, this one here. Let's just grab that.
So for the name, it should be shield. As we can see here,
the name is shield, this will get the current
level that we have here. The first parameter here,
and the second one, we want to get the
value from our list, and the lists type. But since the list is under
the stats manages so we need to grab this like this. Okay. Yeah. So now we have this
Wait a second. Okay. Yeah, we got the
shield data and we can grab its shield
duration like this. So yeah, because our shield out great return
the shield data. But inside our shield data, we have this public
flow shield duration. So we want to get this value. We want to get. We want to get the
shield duration on the correct level
that we are currently. So for example, if we are
currently on level one, then we are going
to access this one. Sorry, the first one, 01. So, this is the shield two, let's just copy this out. Okay. And for the
mega bum script, I'm going to do the
same on the start. But we need to do
this two times. Okay. We want to set the
first value to be the radius and the second
one to be damaged. So we want to update this
value two value here. And this will be the mega bomb. Need to check the
naming, Capital B. So that would be the mega bom, and this is also the
mega bom. Sorry. And under the state
status manager, I'm going to grab our
megaom agreed list, copy this, this list here. And for the megabm' going to change this list that
we want to grab. And the value should be
our radius for the radius. And for the damage, we
want to get its damage. So this will ensure whenever
we start the gate play, it will grab our current value from our current level
from the stats manager. And I'm going to save
the seal script here, also the megabm script. And the last one should
be our laser and start, I'm going to sorry. I'm going to copy our line
here from our megabu script. Yeah, that. And this would
be our laser duration. And for the Sat
name, it should be laser L and I'm going to get our laser grade list
name here and put it here. So we want to search
the valley from the scrat list and
inside laser grade list, we should have the
laser duration field or float variables. So we want to get that
our current and we put it as our laser
duration and safeties. Now if we go back to unity here, and I want to change the
shield to level five, the last level we have, if I press play here,
and then right We should have a very ship to check this and we can select our shield
game object and we can see our shield
duration is seven. It should be ten actually. Let's just check
our stats manager, where the state manager is
here, sorry it's not ten. This is the upgrade
time, but our level five, it should
be seven here. As you can see, this
is the value actually that we retrieve from
the stats manager to be put inside our shield duration value
here. Yeah, as you can see. If I stop this, it resets
three for the game manager, I'm going to reset
this back to one. Let's, for example, if
we change the mega bom, right now, the mega we are currently on
level one mega bom, but if we expand the
megab upgrade list here, we can see that on
the first level, it's four and 25 for each of
the radius and damage value. And let's say I'm want to
access our f five bomb here, the radius eight and
45 for the damage. So if I set this to
five and I press plea, You will see here
that our shield, our megabo has radius of
eight and damage of 45. So it's consistent
to our setting here. So of course, the megaboom will get the
latest value that we have. So for example, if
we have upgraded our level from the play menu, then it will get the
corresponding level value according to this list here. Now we have successfully create the upgrade system
for power apps, we did to also create the
correct value for our health, our missile upgrade
and our blesserpgrad. So let's just access our
auto shoot, I think, e. Is it auto shoot?
No. Let me check. The player has a shoot point and Autosoot for the bullet and also auto shoot
for the missile. Okay, what we can do is we can since we are using
a same script, for the missile shooter
and our blaster shooter. So we can create
another script for changing its starting data. So weapon start data. I'm going to create a new script called Weapon start data. And we are going to also
open our Auto shoot script. And here, we want to create
a public function to change our shoot profile. So let's just type public
void switch profile. And for switching profile, we want to pass in a new
profile here. New profile. And inside this method, we want to switch to update
our shoot profile using the new profile that we are
passing to this method here. And make sure this method is a sorry it's a public method. And for the weapons shoot data, we are going to delete
the update method here, and we only need to
access one variable, and we need to
creditor and this will be the Autosotosot component. And upon start, we also
need to create another, which is the sorry, the string. We need to create a string
variable and call this the I think would be
the weaponst name. Okay. And We can start, we can just access the
auto shoot component, switch profile for
the new profile, we can get it from our
stats manager instance that get stats value. And for this stats
value, I want to pass, without the sign
weapon step name, and for the list, we want to grab our from this
manager or Blaser are list. But we have this missile ages. So we have two different
list that we need to access. So we need to create
a condition here. Okay. Since this is
on our stats manager, then we need to copy this
keyword here and paste this. I'm going to enter this
line here so we can see it like this. Okay. Now we can switch profile, but we can create an statement. If our weapon st name is blaster I think, then
we want to do this. We want you to do
this line here. Okay. But if our weapons
stat name is missile, then we want to do
the different one. We want to copy this line here. And for the list, it should
be the missile list. And let's check our
weapon state name if it's the correct one or not. So let's go to our game manager. And here we have
Bester and missile, yeah, it should be
the correct one. Now we need to make sure
that the weapons start data, since we are we are
switching the profile, but this is run on start. And basically, our Our interval and rate
are being set up on enable. So we are switching
the profile here, but start is executed after
enables so we never get the chance to update the new value for our
weight for second. Let's just cut this two
lines here and let's create a local method and
we are going to run the set interval value. This time we are going to paste this code here and we
are going to make this sure this is public method
and we can run this enable set interval
value like this, at the same time, we can
also change our Sorry, I think we need to
copy this line also. Let's just copy this
and paste it here. Since we are accessing our shoot profile and
whenever we change this, we want to re run this
method here again. Let's just organize
this and save it. Under the weapon start whenever set up our
switch profile, whenever we finish executing
this switch profile, let's just run the method
from our Autosot company. Just type the toseton and
run the set into our value. Yeah. So this way we are we
want to make sure that let's say if we have a blesser of level
three or a level four, then whenever we run
this, whenever phew. Since we are switching
the profile on start, and we are applying
this value on enable and enable gets
executed before start. Let's modify our health
system also on start, let's grab the value. So just set our current help. Sorry. We need to
set this enable. Let's just set our max health Those the stats
manager, instance. Instance, and let's
get the stat value. And string value
should be health. And for the list, let's
just copy the name, the health upgrade list here. Go back to the health system, and I always forget we need to access from
the States manager. And let's grab its Since
health upgrades is a float, then we don't need
to put a field. We don't need to access the
field and there is no field, of course, since it's a float. It's not a custom class, so
we can just grab this and it will return float value and it will fill our max health. Then after that, we
will assign that to our current health.
Let's just save this. Now we need to set our
weapon start data here. Let's go back to our
player game object, and I'm going to attach
this weapon start data. To our time. And the first one
would be blaster, and the second one
would be our missile, and I'm going to direct the auto shoot from the
missile to our component here. And for the first one, I'm going to direct
this auto shoot here. Okay. Let's save this and let's try to change our level for our missile
blaster and missile. Try level three, and it should pick our level tree and also the play
missile level three. Let's play this.
Hopefully, there are no I get destroyed on start. But if I pick the player, the missile is updated to
the level three profile, and also the blister is also updated to
level three profile. The health system. I see it miel. There is an error. Yeah, I
think we have a mistake here, and I should stop this first. We need to make sure that on our health system,
if it's not enemy, let's just put it here and copy this line cut
this line here, put it inside the statement. Basically, we want you
to set this max health if it's not the enemy,
if it's a player. Let's save this and I want
you to try this again. You can see, there are no error. And for the player, we have the health
of whatever is ten, and let's try to
change the value here. So for the help, the first one is ten and the last one is 18. So let's just try to change
our help to the last level, which is level five
and place the out. And deposit and if we
select our player, we can see that he the
max health is 18 here. Yeah. Now we have created
a reference value from our stats manager to all of the upgradable object here to the blaster and the missile and the health and
also the power apps. I'm going to reset this value
back to the default value. Press supply. We change changes that is for this
video and after this, we can continue on
to the next video.
53. 53 Scoring System: Okay. So now let's
create our score system, and it's quite easy, actually. We can just go to our canvas here and I'm going to
switch on this TD view here and center to our
Canvas by pressing the F keyboard button. And we can just add new
tax under our Canvas here. So go under the UI
and choose tax. Let's make this bigger.
I'm going to make this around 400 or maybe more, 550 for the height, I'm going to make this 75. I'm going to position this onto our top parts of our game here, and we should have
our score here. I'm going to type a zero. Character, many zero character, and I'm going to choose best fit and also increase
the max size, the maximum size
to let's say 90. I'm going to set
the alignment to middle and also the vertical
alignment to middle. I'm going to change
the font visitor and choose our orange. But range is quite hard to read, so we are going to use
a different color, perhaps a dark gray here. You can choose any dark
color if you want to. Let's rename this
object to Cortex. Okay. Now we can modify
our level manager script, so let's open this
level manager. The first thing we want
to do is we want to add Ak add value here, and let's just name
this score value. We are going to
create a integer of score we need a reference to score to our score text since we already have
the update script, we can just put it there. I'm going to open our
update money here and we can add another
variable called score display. Okay. And we can create a new
method and we can copy this method and just call this display score, and
we don't need this. Lets just delete
this and we want to add a default formatting, maybe 80, so this is 40 and
another 48080 should be. Save this and this will
be our score of display. I'm going to change
the target object that we are going to change
here. Now we have this. We can just add the script to
our score text, it's okay. It's going to be a
static reference. And since we haven't
we check this, we can search by type and
type the update money, and we don't have any object, let's have this
component attached to. So it should be okay if we put
this under our score text, and there's an error
actually in the script. Let's just type. Yeah. So as you can see here, since we added a argument
to our a Mykal, we need to add a score. Let's just Let's just create a new integer
public integer, and this will be
the minimum score, and we need to add
another max score. Let's just set this
225 by default, the minimum and the
maximum one would be 50. Now whenever we are adding MQ, we can also add a score
by using the random range and type the minimum score and also the maximum score
for the maximum value. We will have random score value. The good thing with this
is we can go back to our unity and we can set a different score to
different two different enemies. Here, we are going to
direct our tax script to the tax display here, and we don't need
to put anything under the money display
since there are no components that
are going to call this money display
in our game level, so we can just leave this
empty and save this. The next thing we need
to do is we need to rose to our bus ship here, and for the health system, we can give a bigger amount
for the bus, for example, 25025 for the minimum
and for the maximum, for the Turret also we can
create something bigger. Like this. For the
second missile, we can change this to like this. Yeah. I basically when
we kill our enemy, the normal enemy we
get a small score, but if we defeat our bust then
we'll get a bigger score. Let's just save the scene
here. Then now let's try this. There is an error. Yeah. The updates since we are running the start
here, display money. But we don't have the money display so we
need to make sure that if money displays not null
then we want to update this. Same goes with our
score display. Just make sure we create
some sort of error checking. If it's not, then we
want to update it and if it's then we don't
want to do anything. Let's save this and
go back to unity and let's just try
to play this again. Last. So the score
is not working. We need to check what
is wrong with it. Let's just check here. Sorry. So basically, we are passing
the value string here. Yeah, we are passing
the value and the one we need to fix is
under our health system. We need to add our score, sorry. So Oh, we are adding the random score
value to our atomic kill, so we need to go to our
level manager here. Whenever we kill, we need to increase our
score score first. Just add this by our
score value increment. After we increment
this, we can use the update My instance reference and use the display score method and we can pass our
current score like this. Let's say this apparently
I forgot that that part. And it's working, but there is a weird behavior when the score is somehow is adding after we
destroy the enemy. So yeah, we need to make sure
that doesn't happen. Okay. There is an issue actually here. Let's let's check this enemy
here, the ground enemy. Go to our treaty mode, and I'm going to expand
our ground enemies, and this is the first one and let's check
under our game here, the bus codor
should be disabled. Yes, it's disabled. But whenever we hitting, it actually as our
it adds score. Let's go back to
our health system and see for checking health. Now we need to make sure that
we don't add score anymore. Probably the easiest thing
to fix this is to create a bullion variable b death,
and this would be false. Then successfully get killed, Then we set that true, we make sure that if it's enemy and that is currently false,
then we want to run this. So this will only run once.
Let's try this again. Basically, if we
successfully kill, now we're testing this and
the issue is still there. We need to check for another box in the
code and I'm going to pass the video and
search for the solution. So to fix this since we
have this issue here, whenever we kill this,
we accidentally kill the other enemies
outside of our screen. We can modify our
bullet moove to destroy itself whenever we hit
this activator here. Let's just do that, open
our bullet move script and we want to create a
fight on trigger enter. Let's just check if the
other tag that we hit this it's activator. I
think it's activator. Let's just check
the type name here. Yeah, it's activator
or the activator. We want to put this game object back to the pull system.
Let's just do that. Pull manager
instance, and we can use the return
object method and we can return this
game object here. The bullet. Because the
bullet object is of course is going to be pulled
since we are shooting a lot of this bullet object. So, let's just check our
health system. Okay. Okay. And now let's try this. Okay. Now this is
finally working great. We don't have any
unexpected behavior, and once we kill the enemy,
we will stop adding. I'm going to try with the
Ron see if it's working. You can see it's
working very good. So we fix the problem. Another thing we can do is actually whenever
we rescue the human. We add also a score. So let's go to our
level manager. And whenever we add rescue, we can add a certain score here and just add 75 and
also update this. For the human rescue, we can set a fixed value of 75 each rescue. Okay. Let's try this one last time for
when we are rescuing the people without human rescue gets added. Score whenever we rescue people. This concludes our score system and we can proceed
to the next video.
54. 54 Weapon Upgrade Menu: In this video, we
are going to add a weapon upgrade menu and also set up the
weapon upgrade item. And here, in the menu scene, expand the Canvas game object, and let's expand
the screen manager and then the shop panel. And under the shop panel, we have the child object
called Upgrade item. And let's just duplicate the upgrade item twice
by pressing Control D. And I'm going to rename the second one to
upgrade item laser. And the third one to
upgrade item missile. And for the first one, let's just rename it to
upgrade item health. And on each the
upgrade item object, we have the upgrade item script. For the Set name, we can just copy the name from the
game manager object, the stats manager script, and we can just copy the name for each of the
stats for the laser. We can just copy the
blister name here, and then we can just
paste the string to the stet name
and the item name of the upgrade item laser. And next one, we can just
select the gamee manager again, and then under the stats, we can copy the missile name. And then we can paste it to the upgrade item missile
upgrade item script, both on the step name
and the item name. Next, let's select the parent game object,
the shop panel. And as you can see here, we have the vertical
layout group. And I'm going to disable the child force expand
the hide check box. So we don't have this gap
between the upgrade item. So let's just uncheck this. And as you can see, once
I've unchecked the option, the menu stack nicely together without any
additional gaps. We can add a bit of spacing here on the vertical
layout group. I'm going to insert
a value of ten. And now we have image object on each of the upgrade
item object as a child, but it's still only a white rectangular. So
we need to fix this. And I've provided the art for each of the stats
here on the resource, so you can just download it, and I'm going to import this
asset into the project. I'm going to direct this
PNG to the sprice folder. And once it's imported, I'm going to select the PNG file and then change the
texture type to sprite. We need to change the
sprite mode to multiple. And now we can slice the sprite. And as you can see, if we
use the automatic slice, it will automatically slice
into three different sprites. And now, let's just go to each of the
upgrade item object, and we can assign
the image manually. It is under the game
object called game object. There is a game
object called image, and we can just select
that game object and then assign the sprite. So for the health,
I'm going to use the first one, S's icon zero. And we can also assign the same orange color by
copying the color from the text object
here above and then select the image again and then paste it on the color slot. And for the other two
upgrade item game object, we can just do the same. So for the blaster, I'm going to assign the Sets icon one image to the source image slot
and then paste the color. And for the missile,
we can select the last image from the Sets icon and then also
paste the orange color. And now we have all of the
upgrade items set up nicely. Now if I test this, In the shop here, you'll see that the blaster
is maxed out because our current profile is set to the maximum tier
for the blaster. Here, as you can see
on the game manager, I've set the blaster
level to five. But let's just try to
upgrade the missile, and I'm going to press yes. And let's just test
this and save the game. And let's stop the run time. Now if we try it
again and then go to the shop and then load again, you'll see that the missile
upgrade is continuing. So this concludes the
weapon upgrade shop setup.
55. 55 Level Unlocking: So, hi, in this video, I'm going to show
you how to create a level unlocked
feature and also adding a scroll bar to our
level selection. So if we have lots of level, we can scroll the
level selection. So in order to create
the scroll bar, it's quite easy, actually. I'm going to disable the scene loader first so
we can see much better. And also on our screen manager, let's just disable
the shop panel. Okay. And now under our
level selector panel, we have this vertical
layout group, and we are going to move
this to another game object. First, let's just right click on the level cellular panel and create a new UI and
create a scroll view, and the position will
be messed up right now because we have this
vertical layout group. Okay. And then just
expand the scroll view, expand the view port, and all of the button of our
level or the level selection needs to be under the
content child here. So let's just direct our level
menu to the content here. And then another thing
that we need to do is we need to just copy this
component or create a new one, if you will, and under the content, let's
just enable this. So right click Transform
and then paste as new. So we have the
vertical layout group in our content game object. And on the level start panel, let's just delete the
vertical layout group. And here under the scroll view, I'm going to fit
the scroll view to be the size of our
left side panel. So let's just press the
preset anchor here and hold button and then press the
lower left preset here. So it fits our panel. Now I'm going to
disable the image. In the scroll view here, we have a image and it has
a white transparent color. So I'm going just to disable
this, so it's clear. And under the view port, we have also an image, but we should not disable this one because this is
required by the mask, and this will clip
any button that are outside this
scroll view here. For example, if we duplicate the level menu a
couple of times. Okay. You'll see that
the ones that are outside our scroll view
panel will not get rendered. And this is because
this mask here. So let's just lift the
setting for our view port. And I'm going to
delete right now, we need to test if the scroll
bar is working or not. Okay. So if we go to the
scroll view game object, we can disable the
horizontal scroll bar because we won't
be deleting that. And under the content, I'm going to change the
spacing to around 25. So we have a space between the button between
the level selection. Okay. And for the scroll view, I'm going to set this to clamp. Okay. Now if we save
and then press play, you'll see that we cannot scrub or we cannot slide
the level section, and we still have two level outside this scroll view here. So in order to make
this two work, we need to go to the
content view and then use a content size
fitter component. Let's just search content, and if you see content
size fitter, just add it. And for the vertical fit, I'm going to set this
to the preferred size. And this will conform
to the content size. If we have this many button, then it will try
to set the height to the value of the height
of our child combined. So it will accommodate
the size of our child. Then now if we press play, you'll see that we
will be able to scroll our level selection. Right now, of course, the button was still not set correctly, and we will do in
this next part here. Let's just top this and I'm going to delete
all of the level menu. And let's just save
the scene first. And we can also apply
this to shop panel. I'm not going to do
that in this video. I hope you can do do it yourself by seeing the example for our level selector panel. But now we are going to add
the level unlocked feature. So let's just open
our script here, and now I have the
stats manager. And we need to
create a new field, which is type
dictionary string and boll it's called
level completed. I've already typed this. So just type this line here, and the type should
be string and boll for the key and the value. And here, first, under
the save progress, we need to save those level
completed field also or data. So under the save data, we need to duplicate that. So let's just select
the line here, copy by pressing the
control C button, and then here under
the safe data class, I'm going to insert this by pasting in the Ststimr it will fill in the line
above of Stster. Now that we have
this, we can go to our safe and load method
and just under safe, I'm going to type safe data and then level completed equal
the level completed. And for the load data, I'm going to copy this
line here, sorry, and then paste it here and
then change the order, so it should be completed equal the load data level completed. So basically, we want to fill the level completed
that are still fresh in a new session from our loaded data
level completed. And when saving, we want
to fill the save data with our level completed that we already changed
during the gameplay. So once we save this, we need to go to
the level manager, and then upon finishing a level, we want to make sure that
we add those value here. Under stats Manager instance, we want to access the level
completed field or variables, and then run the add
method, run the ad. Then for the string, we are going to pass our
level name for the key value, and for the bullion value, we want to set this through. Once we play the level, it will set this through, and we can use this
value to unlock other level in the level menu. Okay. So now that we set the status manager script
and the level manager, so I think that would be
all for those two script. And another thing that we need to change is the level menu. Here in the level
menu, first on start, we want to access the script, sorry, not the script, the text game object
under the button. So I'm going to access the
play button and then use the GT component in
children and pass the type, which is tax tax UI, and then run the method, sorry, modify the
text properties, and we are going to use a
get sibling sibling index, so we can just type transform. Get sibling index, and this will return the sibling index of our game object base
relative to its parent. Let's just set the value first. Since the base is zero, I'm going to add this by one, and then I'm going to close this with set of parentheses and then convert this two a
string with a format. So put double zero inside this value string value
here under the e string. And this will convert the value, choose string with a format
of two digits format. So once we save this, and this g sibling
index is basically getting the index of the
object based of its parent. So for this level menu here, this one would be zero, the sibling index, and
this one would be one. And because this lies on the same level
under the content, so this will return
different index. And here, as you can see,
we are adding by one. So the first index will be one, and then the second
index will be two, and we convert this to strings, so we can show this to the
level label here, the 01 here. Now that we modify this, we need to create a new method to check if level is unlocked. I'm going to call this
check if unlocked then I'm going to create a new
bull unlock condition. And this we'll check for the stats manager level
completed variable. So under stats manager instance, we want to check the
level completed, does it contain key of
our required level, and we need to create a
new string variable in the level menu to define the
required previous level. So here under the sin target, I'm going to add a new
variable call required level. And we need to fill this
later in the inspector, but now we can use this variable to check if the level completed
contains this key or not. And then I contains, then we want to
check if the level completed has that true value inside the record level key. And basically, we need
to check for this. We need to use this
contains key method because if the level completed does not
have this key yet, and we try to access this key, then it will return a
new reference error. So we need to specify
this contains key first. And with this N
operator, basically, if this falls, this
never gets executed. So this is a safe measure if we don't have this key
yet on our level completed. And now, If we already
have this bullion, we want to set the play
button interact play button, interactable to the value
of our unlocked condition. So if this sorry, state level completed, it should be the
unlocked condition. Or we want to check if the string of the required
level is empty or not. So if we use this method
string is or empty, it will check if this
string is empty or not. If empty, then we want
to set this two true, and if it's not, then we
want to set this two false. And this is the ternary operator have already been discussed
a couple of times. Basically, if one of
this condition is true, then we want to set this
value to this one here. But if it's false, then we want to set to this value here. Okay. Now that we set this up, we need to check if the level is unlocked on start and also
on updating the menu. So we can just add here and update menu is called whenever
we load the progress. So whenever we load, we want to also change the unlocked condition
based on our safe data. Now that we have set this up, we need to create a new, sorry. I think there is an error.
Let's just take a look. Clear. Oh, yeah,
it's previous error. It's clear now. So let's just duplicate the
gameplay level. And I'm going to call
this gameplay two. And here, in the built settings, let's just add the gameplay. And now, Once we set this up, we want to set the
second level menu button to the gameplay two. Then for the required level, this should be the previous
level, which is gameplay. And this will check the level completed variable for bully in value on start or
when we update, sorry, not this one, when we update the menu here. Okay. So let's just
give it a try, save the scene, the menu s
and I'm going to press play. You see that the second
level, it's locked, and as you can see
the transform, get sibling index return the correct value,
as you can see. This is the first and
this is the second level. So if we press play,
Sorry, there is an error. Oh, yeah, I disabled
the scene loader, so this needs to get re enabled,
and also the shot panel. Okay, save this and press play. Okay, now I can press
the first level, and it's going to load the game. And this is quite hard. So let's just go back
to the game manager. I'm going to set the
blaster to level five, and let's try this again. Okay. So I'm going to pause
the recording and then continue once I finish level. Okay. So now I finish the level. And if we press it, you see the level is unlocked now and we can
play the second level. And for saving,
We can save this. But if we want to save
this automatically, we can modify the script here
under the level manager. We can call stats
manager instance, and then call the safe progress
when we finish up level. And then save this on starting the game here
under the start here, we can call the load progress. So it will load and save
the game automatically. When we win level, it
will save the progress, and when we start
the level menu, it will load the progress again. Okay. So yeah, for
adding new level, just add new button here under the content scroller and
set the required level. And this should be
the scene name. So if we duplicate this
and for the third level, the target should be
gameplay third or whatever the scene called and
for the previous level should be the gameplay
or gameplay second here. For any questions, just
fight away in the questions, and I'll try to answer it as soon and best as possible. Okay.
56. 56 Final Fix and Builds: In this video, we
are going to build the final game to the
Android binary or pk. And this is the updated video, and I'm using Unity
2019 0.4 0.15. So first, we need to prepare the Android SDK and
also the FFA SDK. With the newer Unity version, I think above 2018 or
starting from 2019, you can go to the
Unity Hub here. So I'm going to
open the Unity Hub and under the Install menu, you can add a module on each of your unit version
installed in your PC. So for example, I'm
using this one here, and we can just click the
Naviigation button here, the three dots button and
then press Add modules. And if you have installed
the Android build support, you can expand this and you can check to see if this
option is installed, the Android SDK and NDK, and also the open JDK. In my case, I've
already installed. But if you haven't, you can just check both of this box
here and then press the, and it will
automatically install. And once it's finished, you can open your project and start to follow this video here. So I'm going to cancel this and I'm going to
close the Unity Hub. Once we have installed the SDK, you need to setting in the edit preference and under
the external tools here. And if you use the open JDK
and the SDK from the hub, you can check both of
this check box here. To use the ones that are
installed with Unit. And also the NDK here. And probably the gradle also
will be checked by default. If you haven't, just check this, but I'm using a custom
gradle here, so it's okay. And if you use a custom
Jaffa development kit or SDK that you've downloaded from the
Android SDK website, then you can uncheck
this and then browse to the installed GDK path and
Android SDK path here. The next thing that I
want to emphasize here, make sure that the scene
loader is enabled. And here, in my case,
I have enabled this, but in the previous video, we might have disabled this
when we are doing the UI. So make sure that you have
the scene loader is enabled, and under the gameplay scene, I'm going to open the
gameplay scene here. I'm going to check also the
scene loader is loaded. Okay. So now we are all
good with the scene loader. Now let's set up
the build settings. But first, I'm going
to import the icon, and I've already prepared
the icon for this here, and you can download it under
the resource in this video. So let's just track
this icon and I'm going to put
it in the sprites. Okay. Now, it's important. And we can go to the
file build setting, and I'm going to click
the player setting. And this will open the
player setting here. And let's just drag the icon. I've already selected before. But you can just drag
the icon or you can just prose using the select and
search for the icon here. Then the next thing
that you want to set is the company name here, and I've already set
the company name using my name and the product
name and the version. And for other settings, we need to make sure
that the package name is set to come, do your company name and
then dot your game name. You can set the minimum Android supported level
here if you want to. And we have this
bundle version code. By default, it has
to be set to one, and this value has
to be an integer. So make sure whenever
you build a new version, you increase this number by one. Otherwise, the play store will reject if you upload an EPC or an updated PK that has the same bundle version code as the one that are
live in the store. So make sure you increase
this version code here. And make sure that the
scripting back end it's set to L two CPP and for the
AP compatibility level, set this two dotnet for
x, and with this setup, you will be able to select
the 64 bit built here. Otherwise, this will be grade out and you cannot enable this. And as per requirement, I think it's since 2019
August or September, new applications that
are being submitted to the Playstore needs to have
its binary in 64 bit format. So you need to make sure
that this is enabled. And the other setup, we can just leave this
as the default settings. And under publishing settings, you need to define
a key store here. So let's just press
custom keystore here, and we can just browse. But if you haven't created a keystore, you can
create a new one. So let's just click on the keystore manager
here and let's create a keystore here and
let's press anywhere. And I'm going to create
a new folder here, keystore, and I'm going
to call this my name. And you need to
set up a password. So I'm going to set up
a Dami password here. And for the new key, you can
just set some names here. For example, this game
is the Smoop project, so I'm going to call
this Smoop project. And for the password, I'm going
to use the same password. And for the name, I
can use my name here. Okay, we can leave
the other empty. I'm going to press Add key, and it will add this key. Now it's created,
and we can just use this as the project key store
and the project key here. Now, once we have this setup, you'll see that we have
the options to use this smooth project that
we have created key here. But if we remove this
custom key store here, then you'll see
that we will build this APK sign or
debug mode here, and you need to re enter the password every time you
restart the Unity editor. So make sure you're
aware of that. Okay, so now I'm going to close this and I'm going
to save the project. Now we can build this by pressing the build under
the build settings here. And I'm going to replace this APK here, and
let's build it. And I'm going to post
the video and we will continue testing the
build out on the device. Now, the build has finished, and we need to install
this to our phone here. And to install
this to our phone, I've already prepared
a batch file to open this AP and it will automatically install
it to our phone. But you need to attach
your phone to the PC here, and this is the batch
file example here. Basically, we need to
point this to ADB file, and I've point this to the SDK that being installed by the previous version
of my unity here. And you can search your path and just replace
this path name file, and you can use
this batch file to install your APK. So I'm
going to close this. And here under the Bills folder, I'm going to click here and I'm going to choose Open With
and choose another app. And here I will use the
ADB install do path here. And if you don't have this, you can just click more apps and then look for another
app on this PC and you can browse to this batch
file here, the ADB Install. So I'm going to choose
this and press. And this will install the
game. Now it's installing. It doesn't show anything, but if we successfully
install to the phone, it will show a success
message like this. I can just press any
key to continue, and it will close this, and now I'm going to run the
game on my phone. So this is how it
look on the phone, and let's try to play the level. So far, it's looking good. Let's grab the coins. And bullet time also works
when there are no touch. Let's test the laser power ups
to this enemy ships chain. Human rescue also works great. My weapons are kind
of overpowered now, but it is only a
matter of settings. So here comes the boss. Let's try the shield. And now the bus is defeated and I only got two of the
achievements out of three. So yeah, that is the
end of this course, and I hope you learn
something from it. And if you have any
questions, feel free to ask. And if you also found a
bug, please let me know, and I'll try to fix it and update the bugs on
the related video. And if you haven't
reviewed the course, please do so as reviews will help me develop a better
course in the future, and also helps other students when deciding to
enroll in a course. Thanks again for enrolling
and for completing. I hope you find
this course useful, and I'll see you on the
next course of mine.
57. 57 Node Move Optimize: In this additional video, we are going to optimize the note move editor script and also the note
move component. And in this video, we are going to overhaul the
note Move script, so it will take the local
transform into account. Previously, it works in
the local transform, but the curve indicator
are in world transform. So now I'm going to change the Gizmo controller to be also in the local
transform of the object. So whenever we move the object, the Gizmo will follow
the object around. So in order to do that, let's open the note move
editor script. And here, inside the
note move editor script. Inside the scene I method, we need to convert this
into a local space. But position handle works
with a world transform. So in order to do that, we can just access the
source game object here and access it transform, and then we can use the
transform point method, and then insert the nodes value here inside the
transform point method. And basically, this
will transform the position from local
space into world space, and we are going
to convert each of the nodes position
into a local space. But in order for the handles
the position handle to work, it needs a world space. So first, we need to convert this value into a world space
using the transform point. But whenever we are storing the resulting vector from
this position handle, as you can see here,
the return value, we need to convert this
back to the local space. So here, I'm going to add a
source dot transform dot, and this will be the
inverse transform point. And we need to put all of this code here inside
a parenthese here. Let's just add a closed
parenthese at the end here. And this is basically we'll convert the nodes
into a local space. And we need to also convert this value
into the world space. And here, we need to run the transform point method
from the transform object. So let's just access the
transform and then run the transform point here and
then pass the nodes here. Okay, let's save this. Now let's head back to
unity and take a look. Here I have this
cube object here, and this cube here, I've already attached
a node move here. So if I add nodes, add a couple of nodes here. I'm going to create four nodes. Let's just adjust
the nodes position, and as you can see, right now, nodes follow the object here. So I'm going to add a random value here so
we can move the nodes. And now let's adjust the notes. So this is the first note. And this is the third notes. This is the second notes, and this is the fourth note. Okay. So now let's
just adjust this here. Okay. As you can see, if we move the notes
here, now it works. All of the notes follow
the game object here. But we need to fix the
curve, the draw line here. So I'm going to just
adjust the nodes here. So it starts from this position. And now I'm going to
say the scene here. And I'm going to call
this note Move test, and we are going to
use the scene for testing out the modified script. And let's go back to the
physical studio here. Now that we have this modified. Next, we need to modify
the note Move script here. First, let's go to the G
curves node method here. And basically, since the nodes now already in local spaces, we don't need to convert the position from
world to local space, so we can just safely
delete this method here. And I'm going to delete
all of this method. And delete all of
this parenthese here. This extra parentheses. Okay. And then I'm going
to remove this code here. So we will start from the first note instead
of the initial position. Basically, we want to start
from the first note and then go to the next
note and so forth. So we can just remove
this code here. But just to be on the safe side, I'm going to commend
this out here, so this code won't get executed. And the next thing
that we need to do is here inside the smo selected, we need to remove
this conversion here. So I'm going to remove this
parent transform point here. But basically, this will draw
the line in world space, but the problem is that
the factors inside this list called curve
positions are in local space. And if we leave it like this, then the curve will be drew in an incorrect position and also not relative
to the game object. But we cannot use
the transform point because we want to only grab the starting position
whenever we play so we can see the curve better when
the object is moving, we can see it clearly that
it follows the curve. So in order to do
that here above, I'm going to add a new
private vector three, and this would be
a start position. And here in the unenable method, we want to cast the initial
position of this object here. So let's just grab it
transform that position, and we want to store the initial position inside
the start pus variable. And here below, Inside
the rogs Most method, I'm going to add a
new local factor three variable called offset, and I'm going to check if
the application is playing, then we want to get
the start position. Otherwise, we want to get
its transformed position. And basically, whenever
the game is running, we want to only get the
start position and we don't want to get the transform
position every frame. But whenever we are editing
or if we are not playing, then we want to get
from its position. So whenever we move
the object around, all of the line here
will gets updated. And using this offset here, we can just easily add the offset here to
the curve position, and this will convert the local position of the
curve into the world space. So let's just add another upset here to the second argument. And now, since the nodes
is in a local space because we modified in the
note move editor here, we need to also add the offset. So I'm going to add
the offset, and here, I'm going to also add the
offset. And let's save this. I've made a mistake where the start position variable is vector two when it
should be vector three. So I'm going to
set this to vector three and save the script again. And let's go back to unity. And now, as you can see the curve aligned with
the nodes controller, and whenever we move the object, all of the lines and
the nodes follow. But this won't work
yet with the movement. It will mess up the movement.
So we need to fix that. So here inside the
note move script, we can just disable this print because we don't
need it anymore. And basically, right now, whenever we run the
co routine here, we are running this method here, and we are calculating
curve notes every time, and this is not performance. So in order to make
this more performant, let's just cache
the curve notes on enable here by creating a
new private list of vector. So I'm going to create a new private list of vector three. And I'm going to call this path, and let's initialize this. And here on the nenable method. Let's just get
curve nodes method and pass this into
the path here. And now we can safely
remove this line. And here inside the
road gizmo selected, we want to also modify
this code here. So basically, we want to check if the application is playing, and if it's playing,
then let's just pass the path that we have
generated on enabled here. So it won't calculate new
curve notes every time. But if it's not playing, then we can safely calculate
new notes every time because we may make adjustment in the editor,
and let's say this. And now we need to modify
the movement here. So for the movement, basically, we want to start the object
position into the first note. So in order to do that, we can just access the
transform position, and then we can pass
the path position ID. But since the path
is in local space, we need to add the
start position. Now we need to modify
this also here. We need to always compare with the world position right now. In order to compare this, we need to add the
start position here. I'm going to add
the start position with this path
here and I'm going to add a set s parent C here, so we can group this calculation first and then substract it with the
transform the position here. Here, whenever we are
moving the object, we want to move the
world position, and here we can just access the world position and then add the start position offset to the path position
for the rotation, we also need to
modify this here. Basically, we need to add the start position
as the offset to the path position and we substract it with
the world position. Another thing that
we need to modify here is the get
curved node here. Basically we don't need to
add the first nodes here. Because we want to make
sure that the first note is the first notes that we've
defined in the editor, the Gizmo position, so
I'm going to remove this. And now that we have modified
this, let's give it a try. Let's go back to unity, and let's clear the console
here and let's press play. Now as you can see,
if I press play, the object follow the
line here very nicely. And if I move this object
to the other position, and if we run the game again, you see that it will
move to this line here. So with this modification, it makes it very easy to adjust the movement of the
node move object, and we can see on the run time the correct path and the correct movement
according the path. There are more optimization
that we need to do here. Basically, we don't need the
transform parent anymore, so we can just
safely delete this here and we don't
need this anymore. So let's just remove all of this line related to
the transform parent. And this one that we
have commented out, let's just delete this because
we don't need it anymore. And now we have removed
the parent variable. Let's go back to unity
and let's give it a try to see if this til
works correctly or not. And now as you can see
it works correctly. Oh, another thing
that we want to modify here is the curve here. As you can see, the curve path doesn't end at the
correct position. And in order to fix this, it's quite easy, actually. If we go to the node
move script here, we can add an equal sign. So we want to create the curve if it's less or
equal the curve segment. So this will cover the curve
until the end of node here. Let's just save the script here and now once the script updated, you'll see that
the the green line is finished up to
the last node here. And now with this
modification here, basically, it's more performance because
whenever we run the game, it will only cash the curve
notes once on enable. But if we are currently
editing on the editor, then the curve notes will
get updated every time here, as you can see on the
g is more selected. And with this modification, we need to modify the
enemy on the scene here, so let's just open
the game play scene here and I'm going to go to
the first enemy wave here. And if we enable the enemy play, You'll see that this is the position, and
this is the nodes here, so we need to modify the node, and this is the
enable the activator. So let's just move the
enemy plane first to make it much more closer
to the activator. And then let's modify
the curve here. So I'm going to subtract
the z position here with ten on each of the nodes here. And now you see that it
is aligned correctly. And now if we select both of the enemy waves and
the enemy plane here, you see that we can see the activator and we can
see the enemy plane. So once the collider or the activator hits
this object here, it will activate this enemy, and the enemy will start
from this position. So we have a much better
visual representation whenever we are designing the enemy movement on the level. I'm going to adjust
this nodes here a bit. So it moves further
to the forward. It approach the player. Okay. Okay. So yeah, that is basically how we modify
the script here. Another thing that I want to
make sure is the rotation. So I'm going to enable
the rotation here and let's give it a try because we already modify the rotation, and as you can see, the
rotation works fine. So this will work also with the enemy ship on the
gameplay scene. Okay.
58. 58 StatsManager Bug Fix: Hi. This is a update video for fixing a couple of
but that Paul Torn, one of the student
of this course spotted. Thanks Paul for that. So yeah, First thing that
we have an issue whenever we are replaying a previous
game that we have completed, it will throw an error
at the end of the game, whenever we get skilled or
whenever we kill the boss. So we cannot exit that level. And I can show you here. Now let's play first level. And let's get killed by
the enemy, for example. Okay. So here, if we exit, you see that we unlock
the second level, and this should also not happen. We need to make sure that
whenever we are get killed, then we don't unlock the level, and we only unlock the level
whenever we killed the boss. So we are going to
fix that as well. But now here, if we try
to play the game again, and then we try to
get ourselves killed. As you can see, the
menu doesn't show up. And here in the console, we have a couple of error. Okay. So here, let's
just filter this out. I think it's on the last. Yeah, here. This is the error. And basically on
this error here, And here, as you can see
on the lefl manager, whenever the games and we are starting
this core routine here and we are adding
the level completed. The problem is that
if we already have a key with the same level name inside this level
completed dictionary, then this will throw an error. So we need to fix this. In order to fix this, we need to open the stats manager first. And here inside
the stat manager, let's create a new method below, and this is going to
be a public method, so we can access this
from another script. And let's just call
this level completed. Here, we want to
pass an argument, which is a type of string
can just call this the same name which is level
name as the method above. And for the second value, we want to pass the bullion value. And here inside, it should
be pretty straightforward. We can check if the level
completed dictionary contains a key of a string level name
here from this parameter, then we want to modify the value by accessing
the entry, the key here, and then pass the afo name
as the index or the key, and then we assign the bleen value that
we are passing here. L, we can just run the add
method from the dictionary, and then add the level name
as well the ban value here. Now we have created this method. We can go back to
the lethal manager and instead of adding to the lefl completed
dictionary directly, we can just run the add
fo completed method, and we can use the
same argument here. But there is another thing
that we want to fix here. We want to fix that. We don't want to pass through
all of the time here. So we want to change this value depending
on the condition. So here inside the
public void game method, we can add a bullion value and
we can just call this win. And here in the count delay, we can also pass the bullion
value and call this win. And now we need to pass
this bullion value from the game method to the count delay method here
inside the start Cote method. And now we have
this Bulen value. We want to replace this true
value with that bin value, which is win. Let's save this. And now we need to change a couple of things in the scene. So let's go back to unity. Okay. Now while we're at it, we see that we have
another error message. So let's just open this here. And basically, this
can throw an error if there are no game object
with a type of player. So we need to check this. I'm going to create a new temporary variable
called player game object. And I want to get the game object and pass this to this
temporary variable here. And now we want to check if
the player game object is not null Then we want to
get the transform, and we can use the
temporary variable that we have already cache this here. So if it's not null,
then we want to get the transform and this should
fix this second issue here. So here, when we
change where is it? When we change the game to
use a bullion variable here, we need to fix the object
in the gameplay scene. So let's just open the
gameplay scene here and basically on the
player game object here. Whenever the player is dead, then we want to run
the game again. But now it's missing the same method on the
death system here. So we need to go to the left
manager again and then pick the game with the bullion here because the method
signatures change. And for the player, we want to uncheck the game bullion value. So it doesn't pass a true value as the
bull win argument here. And for the bus here, if we go to the bus ship, We want to select the game and method
again to update this, to use the new method
with the Bulon value, and then we want to pass
the bulon value here. And we need to disable the
bus ship actually here. So it gets activated
when the lifo starts. Let's save the scene here and
let's go back to the menu. And now let's try to kill
the player twice again. Okay. Now, it shows
this menu here, and then let's clear the log here and play again
and let's get killed again. And as you can see, we don't
have the same error again. And we can see this
this UI is shown twice. So this will also fix
the issue with the bus. We cannot exit the
game when we are defeating the bus
for second time. Okay. So yeah, that will be all. And thank you again,
Paul Thornton for spotting this issue. Cheers.