Create Stunning Vertical Shoot 'Em Up for Mobile with Unity | Romi Fauzi | Skillshare

Playback Speed


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Create Stunning Vertical Shoot 'Em Up for Mobile with Unity

teacher avatar Romi Fauzi, Game Developer, 3D Artist & VFX Artist

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

    • 1.

      01 Opening

      1:25

    • 2.

      02 Scripting Concept

      2:22

    • 3.

      03 Project Setup

      5:41

    • 4.

      04 Player Movement

      13:16

    • 5.

      05 Temporary Pooling

      3:14

    • 6.

      06 Scriptable Object for Weapons

      3:47

    • 7.

      07 Bullet Setup

      6:35

    • 8.

      08 Auto Shoot

      13:20

    • 9.

      09 Health System Part 1

      10:11

    • 10.

      10 Hit Effect

      6:29

    • 11.

      11 Death System

      10:06

    • 12.

      12 Spawn Objects & Health Bar

      15:13

    • 13.

      13 Node Move - Creating Bezier Curve Movement

      16:56

    • 14.

      14 Node Move Editor

      11:36

    • 15.

      15 Node Move - Moving Objects

      12:33

    • 16.

      16 Node Move - World to Local

      6:36

    • 17.

      17 Node Move - Rotate Objects

      9:36

    • 18.

      18 Enemy Waves

      12:56

    • 19.

      19 Auto Rotate

      14:18

    • 20.

      20 Look at Player

      24:42

    • 21.

      21 World Moving

      9:13

    • 22.

      22 Designing Boss

      29:29

    • 23.

      23 Boss Movement

      12:01

    • 24.

      24 Human Rescue

      11:55

    • 25.

      25 Finishing Pooling System

      28:39

    • 26.

      26 Level Designing part 1

      11:56

    • 27.

      27 Level Designing part 2

      10:55

    • 28.

      28 Enemy Activator

      12:08

    • 29.

      29 Coin Setup

      20:51

    • 30.

      30 Camera Movement

      5:01

    • 31.

      31 Boss Integration

      14:31

    • 32.

      32 Enemy Waves Integration

      7:53

    • 33.

      33 Laser Power Ups

      21:12

    • 34.

      34 Mega Bomb Power Ups

      17:34

    • 35.

      35 Shield Power Ups

      22:16

    • 36.

      36 Player Missile

      16:30

    • 37.

      37 Level Manager

      17:30

    • 38.

      38 Stats & Upgrades part 1

      14:36

    • 39.

      39 Stats & Upgrades part 2

      13:45

    • 40.

      40 Stats & Upgrades part 3

      22:05

    • 41.

      41 Upgrade Item Continued

      6:41

    • 42.

      42 Dialog Systems

      19:06

    • 43.

      43 Save Systems

      22:08

    • 44.

      44 Scene Loader

      11:39

    • 45.

      45 Level Menu part 1

      15:35

    • 46.

      46 Level Menu part 2

      14:14

    • 47.

      47 UI Transition

      26:56

    • 48.

      48 Finishing Up UI

      5:15

    • 49.

      49 Sound

      12:30

    • 50.

      50 Touch Control

      4:09

    • 51.

      51 Power Up Menu

      19:48

    • 52.

      52 Applying Stats

      17:16

    • 53.

      53 Scoring System

      12:01

    • 54.

      54 Weapon Upgrade Menu

      4:33

    • 55.

      55 Level Unlocking

      16:25

    • 56.

      56 Final Fix and Builds

      9:36

    • 57.

      57 Node Move Optimize

      14:40

    • 58.

      58 StatsManager Bug Fix

      7:30

  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

23

Students

--

Project

About This Class

Course updated to be compatible with Unity 2019.4!

Ready to take your game development skills to the next level? Join us in this exciting course where we will teach you how to create a fully functional Shoot Em Up game (think Skyforce or Raiden) from scratch using Unity.

Whether you're an experienced Unity developer looking to expand your skill set or a newcomer to the world of game development, this course is for you. We'll guide you through the entire process of creating a game, starting with object oriented programming and delving deep into Unity's C# API.

But we won't just stop there. We'll provide you with all the assets you need to bring your game to life, including 3D models and audio. And you'll have the freedom to use these assets in your own games as well.

Throughout the course, we'll also introduce you to advanced concepts such as Component Based Design, Movement, Shooting Patterns, Curved Movement with Nodes, Scene Transitions, Saving and Loading, Unity's Scriptable Objects, Coins & Human Rescue, and Medal Achievements – all the features you need to create a game that stands out from the rest.

With our guidance, you'll gain a deeper understanding of Unity's API and how to leverage it to create games that are engaging, fun, and challenging. So why wait? Sign up now and get ready to unleash your creativity and build the game of your dreams!

Note: Basic knowledge of Unity's C# API is recommended.

Who is the target audience?

  • Game developers who want to expand their skill set and learn how to create a fully functional Shoot Em Up game using Unity.

  • Programmers who want to improve their knowledge of Unity's C# API and learn how to leverage it to create games.

  • Designers who want to learn how to bring their game ideas to life using Unity's powerful game engine and tools.

  • Hobbyists and enthusiasts who are interested in game development and want to learn how to create their own Shoot Em Up games.

  • Students who are studying game development or computer science and want to gain practical experience in game development using Unity.

What they say about this course:

Jamie Lowe - "Course is mainly for more intermediate/advanced developers but even if you attempt this as a beginner then you will still learn some valuable stuff, reason for my 5 star rating is for the fact Romi is always on hand to help with any problem and most other courses I have taken on Udemy I find it sometimes have to wait a long time for help and that's not good when needing to solve issues, Romi still updates this course to fix any bugs that arise and that is exactly what students need so you are not left with a broken project at the end of the course, I will still be hanging around making adjustments to my project, thank you"

Lance Spence - "I learned a lot from this course and learned new things that I have not seen covered in other Unity courses such as implementing a pooling system, using platform directives and making use of the Gizmos to visualize objects moving along a path. the instructor is knowledgeable and very responsive to students questions. This is one of the primary reasons he has earned a 5 star rating from me. I highly recommend this course if you've ever wanted to learn how to create an awesome SHMUP."

Meet Your Teacher

Teacher Profile Image

Romi Fauzi

Game Developer, 3D Artist & VFX Artist

Teacher

Hi there, I'm Romi, a self taught 3d artist and game developer with more than 10 years of experiences in the industry.

See full profile

Level: Intermediate

Class Ratings

Expectations Met?
    Exceeded!
  • 0%
  • Yes
  • 0%
  • Somewhat
  • 0%
  • Not really
  • 0%

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

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.