Design and Build a Thrilling Rail Shooter Game in Unity | Romi Fauzi | Skillshare

Playback Speed


1.0x


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

Design and Build a Thrilling Rail Shooter Game in 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.

      Course Introduction

      1:05

    • 2.

      01 Project Setup

      11:29

    • 3.

      02 Environment Modelling

      7:34

    • 4.

      03 Camera Path Movement

      19:36

    • 5.

      04 Creating Shoot Out Point

      13:45

    • 6.

      05 Basic Shooting Mechanism

      10:43

    • 7.

      06 Initial Enemy Setup

      20:46

    • 8.

      07 Enemy Animations Preparations

      12:00

    • 9.

      08 Enemy Animations Scripting

      15:33

    • 10.

      09 Enemy Movement Fix and Hit Animation

      11:39

    • 11.

      10 Basic Hit Effects

      11:02

    • 12.

      11 Enemy Hit Effects

      4:18

    • 13.

      12 Exploding Props

      17:30

    • 14.

      13 Custom Weapon

      19:30

    • 15.

      14 Weapon Pickup

      4:44

    • 16.

      15 Weapon FX

      9:33

    • 17.

      16 Delay Action Extensions

      5:48

    • 18.

      17 Game Manager States

      7:59

    • 19.

      18 Game Manager Score and Lives

      6:10

    • 20.

      19 Weapon Pickup Visual

      6:50

    • 21.

      20 Enemy Attack System

      12:07

    • 22.

      21 Enemy Attack Visual

      13:26

    • 23.

      22 Player Damage FX

      11:22

    • 24.

      23 Hostage Setup

      16:50

    • 25.

      24 Area Timer Setup

      16:51

    • 26.

      25 Game Play Statistic

      4:24

    • 27.

      26 UI Health Bar

      8:41

    • 28.

      27 UI Weapon HUD

      14:06

    • 29.

      28 UI Timer

      6:50

    • 30.

      29 UI Hostage Killed

      19:35

    • 31.

      30 UI Intro and End Screen

      21:01

    • 32.

      31 Bug Fixes part 1

      10:06

    • 33.

      32 Custom Mouse Cursor

      3:57

    • 34.

      33 Looks Development

      14:48

    • 35.

      34 Enemy Upper Body Fix

      4:58

    • 36.

      35 Audio Library Setup

      8:40

    • 37.

      36 Audio Player Setup

      18:26

    • 38.

      37 Audio Getter Custom Editor

      12:56

    • 39.

      38 Optimizing Audio Workflow

      6:04

    • 40.

      39 Applying Sound FX

      14:10

    • 41.

      40 Shots Calculation Bug Fix

      6:05

    • 42.

      41 Rank Calculation

      12:41

    • 43.

      42 Pause & Volume Setting

      17:32

    • 44.

      43 Player Dead Setup

      6:18

    • 45.

      44 Title Menu Scene

      17:51

    • 46.

      45 Title Menu Continued

      10:52

    • 47.

      46 Build the Game!

      13:28

    • 48.

      47 Area Cleared Bug Fixing

      7:18

  • --
  • 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.

32

Students

--

Project

About This Class

Updated and Tested on the Latest Unity 2022.3.62f2 LTS version!

Ready to learn how to create a thrilling rail shooter game that will keep players engaged for hours? Join us in this exciting course where we'll teach you how to create a game similar to Virtua Cop and House of the Dead series from scratch using Unity.

Throughout the course, you'll learn about object-oriented programming and gain a better understanding of Unity's C# API. We'll show you how to download all the assets you need for the project for free from the Unity asset store, and we'll provide links to these assets in the lectures.

But that's just the beginning. We'll delve into advanced concepts like Inheritance and Interface, Events for loose coupling, path trajectory for camera movement, and post-processing to enhance the visual appeal of your game.

This course is aimed at intermediate level students with a basic knowledge of Unity's C# API, but anyone who wants to learn how to make games is welcome to join. Whether you're an indie game developer, a seasoned pro, or just a game enthusiast looking to learn more about game development, this course is for you.

So why wait? Sign up now and learn how to create a rail shooter game that will have players coming back for more!

What they say about this course:

Andrew Newman - "Halfway through, and I've been really delighted to work along with this tutorial and have been seeing 1:1 consistency between what is being taught and what I'm able to create. Looking forward to finishing soon!"

Brian Cole - "Excellent course. Lots of new ideas and tips that you don't see in a beginner course e.g. extensions. I particularly like the very flexible way he implements the audio system."

Michael - "Excellent. Second course I have taken with the excellent instructor."

What you'll learn

  • Create a complete rail shooter game similar to Virtua Cop and House of the Dead using Unity
  • Object Oriented Programming (Inheritance & Interface)
  • Utilizing events for communication between scripts
  • Scriptable object for creating custom weapon data
  • Define a path for the camera movement
  • Post processing usage to enhance the looks of the game
  • Audio manager & mixer settings

Who this course is for:

  • Intermediate Unity Developer

Requirements

  • Unity 3D Installed on your PC (version 2019 preferable)
  • A strong will to learn game development
  • Basic understanding of Unity C# API

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. Course Introduction: Hi. Welcome to this Unity course. I'm Rome Faze, and I've been a game developer and treaty artist for many years. I've taught for over 9,000 students how to develop games in Unity. In this course, we are going to develop a rail shooter game akin to fear Talk Op or House of the Death series. With over then 7 hours content, this will be a complete course with a fully finished and polished game at the end of the course. I'm going to cover best practices of Unity game development, including object oriented programming, such as inheritance and interface, events, for script communication, and two post processing to enhance the look of the game. For these projects, I'm going to use Unity 2019 0.2, but any version from 2018 should be okay. So if you are a Unity developer and on you upgrade your skill, you'll have a blast in this course. So enroll today and let's learn together. 2. 01 Project Setup: Okay, so now what we want to do is we want to create a new project. And this is actually the revised lessons for this project setup. In this case, I'm going to press the new project button here and I'm going to use the latest 2022 0.3 0.62 F two. And for the rest of the lessons, it's going to be using a different version because those are still the old videos, but it should work okay. I've tested. Okay, so for the project here, we want to use the three D built in render pipeline, and let's set up a folder there. I'm going to call this. This is going to be a new local project because with the new Unity Hub, you can decide if you want to create a project that gets registered to your Unity Cloud or a new local project. In this case, I want just to be a local project. And let's just call this. Let's call this virtual club style project. And let's press Create Project. This will create a new project and prepare everything for us to start. Okay, so now we have this new project open. First thing that we want to do is we want to go to the lighting tab here, and if you don't have this, you can just go to the window rendering lighting. And that menu will open this tab here, and we want to disable the autogenerate. So if the autogenerate is disabled, then good. Otherwise, if this is enabled, just uncheck this so we don't generate lighting every time we change the scene. And the next thing that we want to do is we want to install a couple of plugins add ons and assets to be used as we go with the lessons for the course. So here you go to the window package manager, and we want to select the Unity registry here. And we can search for Pro Builder, and this should list the Pro Builder there. And once we have this, just press Install, and this will install the Pro Builder package so that we can build di custom geometry and unity to create our level. Okay, so now we have the P Builder installed. The next thing that we want to do is we want to install the Pgrids, but that one is still on preview package. So what we need to do is we need to enable the preview package overt here, project settings here. And now we want to enable pre release package. Okay, so now that once we have this here enabled, we should be able to refresh this. If for some reason the progress is still not there, then what we want to do is we want to install it by package name. So basically, we can just type com dot Unity dot Progress. And this basically we'll install the progrets there. And since this is an experimental package, it's hidden by Unity. But basically, we can add this by typing its name here. So now that we have this progret installed, let's just close this. Now in the scene here, we should have the Pgrits options. Okay, so that's good. The next thing that we want to install is the post processing add ons from Unity. So back to the package manager there, we can type post. And this should filter the post processing. Okay, no result there. So let's just delete this. And we need to go to Unity Registry first and search for post processing here, and we want to install this post processing package from Unity. So it's under Unity Registry and just search for post processing. At the time of this video recording, it's on version 3.4 0.0. Okay, so we have post processing installed. Next, we want to install a couple of assets from the Asset Store. But since 2020 or 21, Asset Store is not available in the Unity anymore. So what we want to do is we can go to our browser here, and I've already set up I've already put the links here. So the first that we want to install is this robot Kyle. You can search, and I've put the link in the second content of this course, second lesson. You can open that link there. And if you haven't added this asset to your account, this button will says add to my assets. So just click that. You will be asked to accept their terms of service. Once you have added, we can download it from the package manager. And from the package manager here, we can go to my assets, and this will list all of the assets that we have added to our account from the asset store. So we want to import this robot Kyle, and then we want to import this particle pack. This particle pack link is also on the second lesson, the Sci fi gun light. And the barrel. On this course, I'm going to use these Sci Fi barrels for the example for the props that we can shoot at later on. But unfortunately, this has been deprecated. So I've put a new link, which is this one, and this should work as well. It's just a different model, so feel free to use anything else if you want, but you can also use this one to follow along this course. And then the last one that we need to import is this kinotch addons for creating the glitch effect later on this course. So, okay, so here, I'm going to search for the robot Kyle. And once I've had this, I'm going to download it and install it into the project. Okay, so now it has been downloaded. I'm going to import this. I think they can safely skip this here. So they just skip this. And we don't need to import everything here. So here, let's just disable everything. And what we want to do is we want to import only the model here, so we can just press the space robot Kyle. And I don't think we need the sound effects as well. Feel free if you want to import the sound effects, but we need the texture, we need the models, the materials, and the animations as well. Okay, so now that we have selected this, we can just disable all of the other assets and we can press Import. And the next one is going to be the particle pack. So I'm going to search for particle, and there should be a Unity particle pack here. This one here. And this is quite big. So it might take a while to download. Okay, so now the particle pack has been finished downloaded. We can just import this into our project. Let's just skip this here. And let's check a couple of things here. If there are some script that we don't need, we can just here, I think we can just remove the spawn effects. Shaders, we need it, textures we need those. It's just a script that we don't need it. And I don't think we need the scenes as well. So just check the scene there and the shared folder as well because those are the material for the scenes as you can see here. And text Mesh Pro. Yeah, we can install this or we can just import this from the package later because basically UNIT already has this text Mesh Pro. So this is just support files. And as well, we can just unselect this here. Okay, so make sure that these are unchecked. I don't think we need to read me as well. We just need the particle pack folder here. So let's import this. So next, let's import the Sci Fi gun. So this is the Sci Fi gun light. I'm going to download this and import into the project as well. Let's remove the scene. We don't need that let's import everything else. And let's import the Scifi barrels on my end here, so we have the barrels that we can use later as a explodable barrels. And we can just remove this example scene here. So here, let's just organize let's better organize this project here. I'm going to create a new folder in the assets, and I'm going to call this game with Underscore as a prefix, so it's going to be sorted on top. It's easier to search this folder and I'm going to move everything into this folder here. And I'm going to create a subfolder called model. And I'm going to put the Sci Fi barrels, the Sci Fi gun light, and also the robot space kyle into that folder here. And for the particle pack, I'm going to direct the effect examples and put it on the game here. And now I can just remove this folder Unity technologies folder. That way, it's going to be easier to follow through to the other lessons as well. And the last thing that we want to import is the grid textures and a map textures that we are going to use to create our level. So in order to do that, let's create a folder first inside the underscore game. Let's call these textures, open that folder. And now I'm going to direct those textures into this project. And this texture is provided on the second lesson, along with the links to those assets that we are importing in the project setup lessons. So yeah, this concludes the project setup, and we are going to continue on the next lesson. 3. 02 Environment Modelling: So now with the sample scenes is open, let's create the guide for our scene first. In order to create the guide, we want to create a new plane object. And this should be ten grids wide, I think, but it's apparently bigger. Let's just, it is ten. It's ten by ten, but we want to increase the dz size to 1.3, so it's then and I'm going to set the snapping to half, so and then back to one and set the y position to also zero. Now we have this plane here, we can create a new material. Let's just create a new material folder. Under the material folders, let's create new material. This will be our guy and for the guide, we want to set the albedo texture to the map texture that we've imported and then direct this material. Now we have a correct representation of our C in here. The way rod it is 13 units by ten units. Now let's create a new shape from the pro builder. If you don't have this window here, just go to the tools the pro builder and then press the probable window. It will be floating by default like this, and we can drag the name of the tab and then put it besides the project panel. Now that we have this and also when we install the progrit, it will show the settings of the progrid here, and we can disable or enable the snapping. We can also change the value of the snapping increment by using the negative and the positive sign on the keyboard. I'm going to set this 21 first, but if we need this, we can also make this smaller. Next thing that we want to do is we want to create a new shape. Press plus besides the new shape button here, and we will have this, and now we want to create this box first here. It's four by two, and let's just set this four. No, sorry, I should be two on the x and four on the z. Let's just set this to three on the y. So it's high, it's a wall, and then press built. Now we can position this and then move this up. There you go. The next thing that we want to create is another cube here. We can set this on the z, but here we have one, two, three, four, five, six, it shod be six on the z xs. Let's just position this here and then move this up. There you go. Now we need to create another shape, and this should be three on the x axis and also six on the z axis, and by pressing built, we can insert this object here and reposition accordingly. As you can see, I've miscounted the grids here, it's okay. W probilder, we can modify the object here by selecting the sub object on the top here. So here is the vertex, and this one is the edge, and this is the phase. In vertex, you can select the vertices, and then you can move this. You can modify it. The UV mapping will conform, it won't stretch, it will expand. So that's good for creating the level. I'm going to use this phase selection and select this phase here and then move it one grid to the side. It's conform correctly with our map guide. Now once we already satisfied with the sizing, we can go back to the object mode object selection, and now let's create another shape. And this will be on the x, how many is this? We need to count this. One, two, three, four, five, six, seven, it should be seven on the x xs and then on the z xs. Yeah. Now I'm going to reposition this and then move this up. We need create three more wall here. Let's just create new shapes. This shod be on the x and one on the z. And then move it up, and then press build. Let's create another one. But this is wrong in terms of size so I'm going to delete that one, and then I'm going to create this one here, small one, it's one by one. But I'm going to set the y value to two, so I'm going to press or it's here. Now move it up and then press built. There you go. Let's add this is three b one. It should be one on three under z axis, and we can two, it's okay, and then move this here, and then move it There you go, we have the scene created. Now the last object that we want to crate is the ground. Let's just create the ground, it should be ten by 13 on the z, and I'm going to change the y20 0.1. Let's just move this here, and I'm going to set the y value 20. And I'm going to align this here. There you go. Now we have the scene here. We can just hide the guide as we won't be needing this for now. The next thing that I want to do is I want to create a new material for this probilar object. Here I'm going to create a new material, and I'm going to call this environment grid. I'm going to enable the emission material. Here, let's just use the grid texture that we've created, black and white grid texture. You'll see we'll have an emissive of white because we set the color of the emission is white, and we can set the base color to a probably dark blue. Something like this, yes, and change the grid to something orange. With this settings, you'll see that when we going to use the post processing effect later, the line will be glowing. Now we have this here. Let's just apply this to the object. I'm going to select the material editor, and then I'm going to assign the environment material here, and then I'm going to apply this. There you go. Now we have a very nice looking grid for the environment. 4. 03 Camera Path Movement: So in this video, we are going to create the camera movement using the Unity Spline. And with Unity Spline, we can create a series of nodes that will be connected like a spine. We can adjust its curvature with busier style handling, and we can move any objects along that spine. So in order to use Unity spine, first, we need to import it from package manager. If we go to Unity Registry, we should be able to search for spline and here, let's just install the latest one. Currently, is at 2.8 0.2. Okay, so spline is finished installing. Next, we can start creating a new plan. But before that, let's just a couple of things here. So here let's go to Perspective view by pressing this box cube here, and we want to use the we want to move the map object here. Because it's being occluded by the ground here, so we can just enable the progress. And if we move this, it will move by one unit, and we want to reduce this. So here, we can just change the SNAP value to something small like 0.125, for example. So if we move this, it will move at that increment. So yeah, for now, we can just position this here so we can see it from the top view. And the next thing that we want to do is let's just put this back to 0.5 for the snap value. Here, I want to move the camera, and this is going to be our start position here. So let's just move the camera around that position, maybe here and let's rotate the Y axis by 180 degrees. So facing to the scene here, and we want to increase the Y position. Maybe around 2 meters should be good or if we want to overwrite this, we can just type this. I want to put 1.75. And we should have this view as the first frame. And now we can create the spine. In order to create the spine here, we can press this button here. There is a pencil and wrench. And if you press the editor tool here, we can press Create spine. And this will allows us to create a spine. So I'm going to start from this position and then go to this green point here and maybe at another point here so we can decide the turning point. And move along this point, maybe around this position here and we can so let's move this few. And yeah, this should be the position or we can just press Escape to cancel the last one. So this is the position. And we can rotate this if we want to rotate this. We can just set up the bezier point Yeah, we can just direct the busier here. There is a node here and make sure that this last node is facing to this direction here. Okay, so we have set this up here. We can go to the side view. Now let's select the spline and let's disable the spline tool here. And now we should be oh, sorry, this is enabled, and now we should be able to move everything. So I'm going to move the game object, the splaying game object to be around the camera hive there. And maybe now we can just press this again, and then for the first, can move it slightly above here. So it's higher than the starting position. And yeah, this is our spline here for the move. Okay, so let's save the scene here. I'm going to change this order, put it above the cube here. And let's reorganize the scene a bit. Here, we have a bunch of cube. So let's create a new anti game object. Let's call this environment. Let's reset the transform, so it's centered in the origin and select every cube that we have on our scene. We can just drag this into the child of this environment and we can collapse this. Okay, so Max, what we want to do is we want to create the script for the camera so that the camera can move along the spline. Here, inside the game folder, let's create a new subfolder called scripts. And inside this script subfolder, let's create a new shap script. And let's call this script player move. And let's open this script here. Okay, so now we have the script opened. We need to start creating variables that we are going to use here, field. So let's just create a serious field, and this is going to be a private field. And we can search for spline container, and spline container is basically the component that we use for creating the spline here, spline container there. And let's just call this path. And we want to create a new enum for this. So let's just create a path loop option. And let's just call this NO path. And for that um, we want to create a new num and we can just create that um in the same file here. So let's just type public num pathop option. And for the option, we want to have a loop options and then a stop option. And make sure this num outside of the class player move. Okay. So next, we want to create a new private float, and this is going to be the speed. Let's set this 23 by default. And that is going to be a speed in which the camera will move using that spit and it's in meter per second. So it's going to be 3 meter/second. And we want to have a bullion, and this is called Is moving, and this will dictate whether if the camera or the player should move along the spline or not. Let's create a couple of debug fields that we can use to test some of the options or positions in the edit mode instead of running the game to see the position. So this is going to be a private float preview distance. And this is going to be a bullion where we can enable or disable the debug. We will also need to have a couple of private field. I'm going to call this distance travelled. And for variables or fields that are not exposed and it's private, I always use this underscore. It's a good convention. One thing to note on other video lessons, it will not be using this convention as well, since those are old videos from when this course was initially created. I apologize for any confusion, but please pay attention to the name of the fields and feel free to follow which style suits you the most. For the other private flout, this is going to be the spline length or the path length, in this case. And in start, we want to get the spine length or we want to cache the spline length, so type path, and then we can get the spine. And here we can get the length of the spine. And basically, spine container can have multiple spine. But since we are only creating one spline, then we can just grab the spine. Otherwise, you can use the spline objects and then add an index here, like an array or a collection. But in this case, we just need the main spine. So this should be good. And here inside the update, we want to check if the path is not null means that we are assigning an object, a spline container to the path. And then if it's moving as well, then we want to run the update code, which we are going to use to move the camera along the path. So here we want to increase the distance traveled by its speed, but we want to multiply this by time Delta time. And basically, we want to make sure that the value is not frame dependent. So we want to use time Delta time so that this value changes is time dependent, not frame dependent, which is good because on different devices, the FBS can run at a different rate. And then we want to have a normalized distance travel. And here we want to create a function or method called calculate normalized distance. And in this case, we want to use we want to pass to float, distance traveled and the splint length. Now we can generate this method by pressing Control or command on Mac and then dot the keyboard, and it will give us options to generate the method there. So now here we can start defining the method here, and basically we want to return a float. So here in the calculate normalized distance here, we want to create a normalized value, and this is the distance traveled divided by the spline length, but we want to change this normalized value based on the path loop options or the end of path options that we have here. So we can have a stop. Whenever the camera arrives on the last point of the curve, it will stop the camera or else it will loop the camera. So here if the end of path is set to stop Then we want to clamp the normalized value F with a lowercase F there. And then we want to clam function and we want to pass the normalized value here, but we want to clamp this to zero and one. Else if end of path is loop, then we want to loop the movement. So basically here, we want to normalize we want to run a modulo operation using this percentage sine equal, and then we want to modulize with one. So basically, it will loops the value to zero if pass one there and then because basically it's getting the reminder when we dividing this. So if it's a fraction like 1.1, then if we divide it by one, that the reminder is going to be the decimal values there, so it will loop the value over and over again. And then we want to check if the normalized value is for some reason, below zero, meaning that we scrub it into a negative values. Then we want to normalize we want to set this value to one, and then we want to add with the normalized value. So we want to invert the increment, and then here we want to return the normalized value. So this should handle different pass loop options behavior. And then we want to create a new function called reposition camera here, and we can pass the normalized distance. So here, let's just generate this using the Control dot key combination there. And now here in the reposition camera, it's very simple. Actually, we can just access the path object, which is the spine container, then we can evaluate and evaluate takes a normalized distance here so we can just pass the normalized distance and then we can output the position and the type that is being outputted is flow tree. It's not a vector t, but we can easily use this into a method that uses vector three because it's compatible. So we want to output the position, and then we want to output the tangent which is the forward of the curve direction, and then we want to output the up vector. Okay, so this should do. And then we want to set the camera position to position. And for the rotation here, we want to use the quaternion rotations. And as you can see, Fisostudio already give us suggestions, which is correct. We want to use the look rotation and forward using the forward value and the up value. So we get the correct rotations along the path. And we can just remove all of this system collections name space that we are not using. And the last thing that we want to create is a validate method, and Unity has this built in on validate method. And basically, this method is being called whenever we are changing value in the inspector. This is good for debugging stuff, so we can just check if the enable debug is true. Then also, we want to check if the path is not null. Then we want to create a normalized distance. We can use the calculate normalized distance method. In this case, we want to use the previous distance, not the distance traveled, because this is the value that we can see in the inspector that we can debug. And then we are not going to use the spine length because at the edit time, we won't have spline length available for us since we are getting this value on start. So what we want to do is we know that the path is not known because we checked here. So we can just type path, spline, get length. And this should do and what we want to do here, we want to reposition the camera using the normalized distance. Okay, so now we are done with the player move. Let's go back to Unity and let's apply this to our camera here. Here in the camera, we can just direct the player move component here, and we should be able to direct the spline into the spline container here and we can save the scene here. Now if we enable the bug here, for example, you see the camera snaps to that position, and if we scrap this, the camera moves. So this is useful later when we are going to define our shootout point. Shootout point is a position where we want to stop the camera and then we want to spawn the enemies, so we can scrap and see which distance is going to be the best for this camera position. Okay, so let's just zero this out and enable the bug here. And now if we go to GameView we can press play, and then we can see the movement. Okay, so it's running at three units per second. And I think we might need to lower this to 1.5. So let's just see if it's nice enough, the speed. Yeah, I think this is nice. And here with the end of path options here, basically, we set this to stop and enable the debug here, camera won't move, but if we move this in a positive values that it moves. But if we set this to loop and we scrap this two, it will loop to the end of point there. So we can create the looping movement by changing this end of path. Another thing that we can test is the moving and stopping the movement of the camera. So let's enable the bug field first and let's run the game. So now if I uncheck this is moving, it will stop and if we check this back, it will continue move. We can use this to stop the player on a position we are engaging with the enemies. Yeah, that concludes our player move lessons. 5. 04 Creating Shoot Out Point: In this video, we are going to start implementing the shootout point. And this shootout point basically a position where the camera will stop and the enemy will start spawning. And when the timer runs out, or when the player has eliminated or kills all of the enemies, then the camera will start moving again following further to the path. So with the camera here, basically we have this distance, right? And we can create a series of shoot out points that have a distance value that dictates whenever the camera needs to stop. So when the camera arrive at that distance, then we are going to stop it. So in order to do that, we need to create a new script here. So inside the Asset game scripts folder, let's create a new sharp script, and let's call this heed out point. And let's open this script. Okay, so here in the script here, first, we want to create a new public boolean properties called area clear and this for marking if the shoot out point has been cleared or not. And then the next one that we want to create is private boolean, and this is the active point. And this will dictate if this current shoota point or this current instance of a shoot up point is the active one or not. And we need to also cache the player move script. Let's just put this under the player move. Variable here, I'm going to add a dash or an underscore for this active point since this is a private field. Now first, we need to create a public method and this for initializing this instance of shoot off point. We want to pass a player move object. And whenever this method is called, we want to pass the player move and cache this player move into our underscore player field. And we don't need the start method, so we can just safely delete this here. And the next one that we want to create is we want to create another public method, and this is for starting the shootout. And when starting the shootout, we want to set the active point through here in the update, we want to do some sort of the bug here. So I'm going to add an input get key down, and this is just for simulating the shootout point when we are testing it in this lesson. So when space is pressed, we want to stop the player movement, but we don't have that yet. So let's just type player move here, and then we can just type the method that we want to create and we can pass a bullion here. Now that we have this created, we can press Control and dot here, and basically, we can generate the set player movement. And this will generate a public method here or an internal one. So we can change this to public, and then we can call this Enable. And we want to set the moving variable to enable. So when this method is called and false is passed, then we are setting that is moving tube false here like this one here. And here we want to do another get key down, and I want to use Return for now or Enter on PC. And here, I'm going to set the player move set player movement to true. So we want to continue. We want to simulate whenever a shutle point is clear here, and we can mark this area clear to true, and we can set the active point to falls here. Other thing that we need to check here is whenever we are continuing here, we want to make sure that this is the current active point. Otherwise, when we are continuing from the first shootout point, the second will also be clear if we don't have this active check. Let's save this now let's work on the player move here. Here in the player move script, we want to check whenever we have arrived in the shootout point. But before that, we need to create a custom class here. Let's just call this shoot out entry. And we can mark this serializable. And this is coming from the system namespace. So if you haven't had this using system, then you should add it first, and then we can mark this as serizable. And this will allow this class to be shown in an inspector later in unity. And here we need to create a public field, and this is going to be the shootout point. So we can assign a shootout point to this variable or to this field. And we want to add a float distance, and this is going to be the distance that we are going to test against the camera position to whether we need to stop the camera or not or the player. So here inside the uptick method, and when we are moving here, we want to add a loop here, and we want to look through a field that we need to create first. So here, let's create a new series field. And this can be a private. And this is going to be the shootout entry array. And let's just call the shootout entries. And here we can look through the shootout entries length, and we can create a local variable here and cache the current entries based on its index. And then here, we can check the position. So we want to use the path, evaluate position. And we can use the entry distance value divide by the spine length and to get the normalized distance. Then here we can substract it with the transform the position. But since a valuate position returns a flow tree, we need to cast this into a vector three. Since we are doing operations with a vector three, which is the transform the position. So we need to cast this to a vector three. That's at a parenthesis here, and now we should get the, we need to check for the magnitude, but square magnitude is faster because we don't do square root operations with square magnitude. And to know if this is quite close, then we can just compare this against a very small value which is like 0.01. And if this is true, then it means that the camera has arrived in this distance position here. Okay, so now when this happens, we want to check if the entry area is cleared, sorry, shootout point area is cleared, and this is why are we created this area cleared as a public properties, so the player move can read that value. And if it's cleared, then we want to continue this loop. So it goes to the next iteration. And here we want to check if it's moving. Then we want to stop by going to the shootout point and then call the start shootout method that we've created earlier. So now, save this. Another thing we need to add before testing this out, we need to initialize every shootout point here. Here in the start method. We want to add for each loop, and we want to look through the shootout entries here. And let's call this item entry. And for each entry, we want to access each shootout point. We want to pass the player move into the initialized method here. So we can just use this keyword here, and this will pass the player move into this method here. And another thing that we need to make sure is that whenever we are starting the shootout here, we need to make sure that we are stopping the player movement here using the set player movement method. So here I'm going to add that call to this method here and set these two falls. Okay, so now we can save both of the files here and let's go back to Unity. Okay, so here in unity, first, we want to create a new anti game object, and this is going to be the shootout group, where we're going to put every shootout point object in this empty game object so we can better organize our scene. Let's create an empty child, and let's call this shootout point number one. We can add the shootout point script, and then we can also copy this and rename this to shootout 0.2. And on the camera game object here, now we have the shootout entries variable, and we can add a component here, and we can direct the first shootout point to this shootout point here and the second one to the second shootout point. Now, let's save the scene here, and we need to test some values in the preview distance to get the distance value for each shootout point. So for the first shot out point, let's enable the debug here and scrap this value. And if we go to top view here, we want to stop the camera at that first green point here. So around these position should be good. Let's round it to 2.6 and set that distance to 2.6. And if we scrub further, we want to stop the second shootout point in this green in the second green circle here. So maybe around this position here. Let's copy this value and paste it here. So we have set up this shoot at point distance, and let's just reset the preview distance and disable the enabled bug here and let's save the scene. And whenever we are testing or we want to build the game, we need to make sure that this enabled bug is disabled. Otherwise, it will mess with the camera movement later. Okay, so now let's go to the game you and test this out. Okay, so now at the first shootout point, you see that the camera stop and is moving gets set to falls here. And later we are going to spawn enemies, do Tr come down, and then also check whether if all of the enemies has been killed or not. But for now to emulate the area cleared, we can just press return or enter, and it'll continue move. And then when we arrive to the second point, we can do the same. By pressing Enter, we are simulating the area cleared and we reach at the end of the path here. So, yeah, there is what we need to do to create the ShutlePoint, and this concludes this lesson. And we are going to continue on the next video. 6. 05 Basic Shooting Mechanism: In this video, before we continue to shoot out point, we need to make sure that we create a shooting mechanism for the player. In order to do that, let's create a new script, and let's call this player script. Next, we are going to create a interface an interface script for creating a basic method for hable object. Let's just create a new folder and let's just this interface. And I'm going to create a new C sharp script, and I'm going to call this I hittable. Basically, for the standard practice in C sharp, interface, we name the class with an I in front of the class name here. Interface able. And we are going to remove all of the un here and it's not going to be a moo behavior, and it is also not going to be a class, but it's going to be an interface. And we want to also delete this method here. And basically interface is a basic contract for other script to implement a method. So for example, we can declare a method name and all of the other clays that implement this interface needs to implement that method. For example, let's create a new method called it. And basically, if we create a new script, for example, if we go back to UT here, and let's create let's create a new SSH script, and let's call this dynamic dynamic objects. L et's open this script here. And we can make this object implement the hit able by adding a comma after mono behavior and then type the interface that we want to implement. Now it gave us an error because our class here does not implement interface member hit. We need to do that. But before I'm going to implement the hit method, I'm going to modify it and for the hit, it will ask for a object for the argument. Let's just call this hit. And safety. Now if you are using Psal Studio, you can just highlight the interface on the dynamic objects class and then press show potential fix and then implement interface. You'll see that it will automatically implement the method that are declared by the interface. Let's just delete this here, and now we can do anything with it. For example, if I just delete the built in method, and let's create a new private rigid body RB and we can just initialized the rigid body on start. Let's check if get component rigid body is no, Then we one to create a new one. Or perhaps it will be better if we try to grab. Let's just put the get component rigid body inside this variable here. Let's just duplicate this and then paste it here. Now we can check if the RB is, then we want to create a new rigid body to it. Let's just type RB equal game object. I think it's at component rigid body. There you go. This way, it will make sure that any objects that are using this class are going to have a rigid body in it. Now whenever we got hit, we can always apply a force to the rigid body. For example, we can just type rigid body at force, and we can get the vector from the ca it information, and the cas hit information has a lot of information. For example, we can grab the normal and then we can inverse the normal and then multiply by some value 50 here or a 100. This will be a basic, and of course, we are going to modify this. Let's go back to unity, and then let's open our player scripts file here. In this script, we want to create a mechanism where we can shoot to an object in our scene. Since the player script is going to be attached on the camera, we can create a new private camera variable and grab the camera component. Let's just create a new camera variable called CM. On start, we can always just use the GT component camera. And save it. The next thing that we need to do is we want to make sure that whenever the mouse is clicking the left button, get mouse button down, and the left button is zero. One is for the right button, and two is for the middle button. Whenever we click the left mouse click, then we want to create a new y cast. Let's just type ray, and this is object ray object, and let's just call this ray. And this will be a cam for camera. I have a method, which is screen 0.2 ray, and this is basically will shoot ray from a screen point. For the screen point, we are going to put the mouse position input mouse position. There you go. Now we can always try to test the ray using the physics ray cast. It has a lot of overrides, as you can see here. We are going to use this one, I think, this one. Yeah, this one, we can use this one. So basically, we want to pass the ray and we want to out the RCAs hit info. So we need to create a new cs here. Let's just create a Cas hit. Let's just call this hit. And we can pass the value to hit. So whatever the resulting ras hit will be safe to this hit variable, and we can pass this to the other class. That needs that information. And I think the next thing will be the max distance. Let's just put it 50 units. And if it hits something, then the code inside the if statement will get executed. Let's just create a new itable object. Sorry. We need to make sure if the collider is not known first. Let's create a new I statement and here we want to check if the hit variable or the hit object has an collider attached to it. So if it hits something, it should have a collider. It's not null, then we want to grab the hittable object if it's available. Let's just create a new i hit hit, let's call this hitable. Then I'm going to grab from the hit, get hit collider, get component, and here we can grab the i hable. There you go. We are going to check this again if itable is not null, then we want to run the hit method here, and then pass the cast information hit. We can also print its name by running the debug log command and pass the collider game object dot name. Okay save this, and now we can attach this to our camera. Let's go back to Unity, and if we select the camera here, we can add the player script component, and for testing it out, let's just create a new cube here. I'm going to create a new normal cube. I'm going to probably put it here or here in the middle. And put it on top here, and let's add the dynamic object script. Let's save this and let's give it a try. And let's open our console here. If I click here, you see that we are hitting this cube here. And if I, since the object name is the same, the debug lock is collapse. So let's just call this box, this one here, and save this. And now you'll see that if I shoot this box here, it moves because we have this We have this where is it? Because we have this at first comment on our hit method. Basically, this script will check if the object that gets hit by our Cs, does it have a hit component or any class that implement hitable interface? And if it's not null, if it's available or if the object has an hable interface attached to it, then we want to execute the hit method. And we can implement this in any way we want to. For enemy, we can put the health. We can decrease the health inside the hit. Method interface is quite powerful. And this is how we do the basic shooting mechanism. And of course, we are going to expand this mechanism. 7. 06 Initial Enemy Setup: Hello, in this video, we are going to continue our project, and we are going to create the basic simple enemy mechanism, and of course, we are going to expand those mechanism. First, let's just delete the box here. We don't need that anymore. And we need to define the NAF mesh area. In order to do that, we can go to the window under the AI, click the navigation menu, and it will open this navigation panel. And here under the bake, first for the environment, we want to set this two a static. Let's just enable the static and then, change the children. Now once we change this to static, if we go to navigation, we can press the big button and then it will bake our area here. There you go. As we can see, we have an area here, but in this position, There is an issue here because we are going to need for the enemy to hide from this area here, and we don't have navigation math. We need to decrease the radius here to maybe 0.3. We have a smaller agent size and it will have it will create more area for the N the N mesh area. Let's just create bag again and see if. As you can see here, now we have NAF mesh inside this and it's connected here. It's better. We can create from this position and then it will be able to move to a certain position outside of this hallway or alleyway. Once we already create the NF mesh, if we go back to the inspector, this blue navigation mesh gets hidden. The next thing that we want to do is I'm going to create a new capsule For the enemy, I'm going to create a new capsule object, and this will be the enemy. And to be aware of the direction of the capsule. I'm going to add another three d cube object, and I'm going to make this smaller, like so and then move this to the front here. So we know which are currently the capsule is facing right now. Yeah, let's go to the lighting here and I want to disable the ato generate. So it doesn't generate the lighting every time and save the scene. This is going to be the enemy. Let's just call this enemy. First, we need to add a navigation mesh agent, and also a rigid body. Since this object is going to move, we need to also assign rigid body. But if we don't need the physics interactions or the dynamics calculation to this object, we can just disable the use gravity and then enable the is kinematic. Okay. Now let's change the navigation mess radius to 0.3, so it's the same with our navigation mesh settings. For the capsule, I'm going to change also the radius of the capsule collider to around 0.3 also. Now we have the enemy. The next thing that we need to do is we need to create a new script for the enemy. Let's just create a new Shop script, and then let's call this enemy script. Let's open this. Now there are a couple variables that we need to define for this enemy script. First, we need a serialized field, and this should be integer, and let's call this Mx health. This is for defining the maximum health. Then we are going to also add a private integer and this will be the real health or the current health that we use for calculating the enemy health. Then we also need a serialized field type of transform, and this will be the target position. And the target position is where the enemy are going to reposition or move after he came out from the hiding or the ambush position. The other thing that we need to have access to is the transform of the player. Let's just create a new private transform variable, and let's call this player, and we also need a bleion variable, and this is for toggling whether the enemy is already dead or not, and the last one will be a NF mesh agent component. But if you can see here, it doesn't show in the out complete because you need to using the unit engine AI. If we Highlight the class here and then show potential fix. We will have an option to add this. I'm going just to click this and it will also be automatically added on the script, and I'm going to call this Agent. Let's create a new initializing method, and this is going to be a public method. Let's just call this in it. Another thing that we need to create, I forgot, we need to have a reference to the shoot out point. Let's just create a U variable shoot out point. Now on the init, we are going to pass the shootout point and just call this point. Let's just assign the value point here that we pass as a parameter to the shootout point. Okay. Now we are going to grab the player, also the NF mesh agent. Let's just type agent equal get component NF mesh agent. For the player, we can just get the camera class and then get the main camera and get the transform. There you go. We have the player transform. Inside the update, we want to also make sure that the enemy we also always face the player. Let's just check that. Inside the update, we want to check if the player is not null, and if the enemy is also not dead currently, then we want to face the player. In order to face the player, we are going to create a new factor three, and let's just call this direction, and for direction, it will be the player that position, substract with our enemy position, current position. Then I'm going to zero out the y value. The rotation will be strictly on the x and z plane, and we can set the transform rotation, rotation to a quaternion look rotation at the direction. Now inside the init method, we are also going to add the destination for the agent. Let's just check this if agent is not. Then we want to set the destination to our target position. Target position position. We want to grab the target position position as the destination for the agent. Another thing that we need to make sure that we need to disable the rotation of the agent, the me agent component doesn't drive the rotation. Since we already handle the rotation ourself inside the Pate method here. Let's just add code here, Agent rotation and set this to falle. This is basically we'll ignore the rotation, and we are going to also create a hit method and we need to implement the interface hittable. Now once I've implemented this interface, you'll see that we have an error, so I'm going to click the show potential fixes and then implement interface, and it will automatically implement the interface here. Right now, we can just subtract the current health, but we need to initialize this also. Inside the init, let's just set the current health to the Mx health. I. And then we can subtract the current health in the hat method, and also print a log message to the console, am shut and if the current health is less or equal zero, then we want to enable the s is that bulto true, and we also want to disable the agent component set to false. Another thing that we need to do is, we need to make sure that if that's true then we want to return this method, so it doesn't execute any of the code here below. The other thing that we need to set up is, I think that would be all. Let's just give it a try and we need to do a couple of modifications on the shootout point. Let's just go to the shootout point. Now we need to create an enemy entries. I'm going to create a custom class here outside, and I'm going to add a system serializable attribute to it and call this public class enemy entry. And this is custom class, so it doesn't need to derive from mono behavior. I'm going to create a new public enemy script, the enemy. Then for the other value, it would be a float delay, and this is the delay in seconds. How much time we will need for this enemy to appear. Now we are going to add a new serialized field, and this will be the enemy entry array, and let's just call this enemy list. And we are going to create a new coroutine for spawning this enemy here. Let's just create a new i enumerator method that returns type enumerator. Let's just call this send enemies. And Inside the cotin here, we want to look through the enemy list collection here. Let's just type for the variable, it will be the enemy and inside the enemy list collection. Here, we are going to add a yield return new weight for seconds, and we are going to pass the enemy delay here. This is the delay that we declare in the enemy entry here. And after we delay the code execution here, we want to access the enemy that enemy initialize. So when it's initialized, it will start the enemy to move here, as you can see here, once we initialize, it will set the destination for the enemy NMS agent. So the enemy will start moves. But we need to pass the shootout point. Let's just pass this shootout point here with the dis keyword. If we want to, we can just also debug the enemy object name. Let's just type enemy, enemy, game o name spawn. Inside the shootout point script. We also need to add a private variable, which is an integer, and let's just call this enemy killed. This is for counting how many enemies that we already killed and after we kill all then we can move to the next area. Let's just create a new public method and let's just call this enemy kill. For this public method, we are going to increase this enemy k integer. Let's just type enemy kel plus plus. This means that we are increasing by one or incrementing by value of one, and we want to check if the enemy kel value is equal to our enemy list length. Then we want to continue the movement here, the movement of the player. Let's just use this this value here. Copy this and then paste it here. Okay. So now that we've created the public method for the enemy kilt, we need to call this from the enemy script. Whenever each of an instance of the enemy script gets killed, then we want to run this method here. I increase the enemy killed value here. Let's just go back to the enemy script and inside the current health here, we can just access the shootout point and run the enemy killed method. And save this. Of course, this is still the basic implementation and we are going to modify this more later. Let's just go back to unity and test this out. This will be the enemy here. I'm going to set this or save this as a pref Inside the game folder, I'm going to create a new folder. And inside this prefabs folder. I'm going to direct this enemy game object as the prefabs. Now since we already changed this to a prefes, we can just add a script, which is the enemy script, and then we can apply this to the prefabs here. Now we need to reposition the enemy. Let's just enable the navigation and I'm going to move this enemy to this position here. I probably here. I'm going to duplicate this enemy. But first, let's just set the health value because currently it's still zero. Let's just set this 23 and apply this. It will be the default value. We can duplicate the enemy here, and we can put it here. If we go to the navigation, we can see, we can put it for over here. Then in the shootout point, we can create a new t game object. And this will be the position. This is for this enemy here. We can move him to this position here, and we can duplicate this anti game object and put it behind here. The second one will appear in this position here. We can move this slightly to the site here. Let's just rename this. This is the target position one, and this will be the target position two. Okay. Now if we select the enemy here, I'm going to set this enemy here, the target position to the second target position. And for the first enemy here, I'm going to set this as the first target position. Okay, let's save the scene here and under the shootout point, we want to set up the enemy less, let's just set this 22, and for each of these entries, let's set the first enemy two this one here, and the second enemy will be in the second entry here and probably we need to set a delay, so let's just set this 23 for now. The next enemy, we can set this two. Basically, this will get triggered after this is shown is B if we go back to the code here, you'll see that in the shootout point. The four e loop will get led by the first enemy delay. And then it will initialize that enemy. And then on the next loop, it will delay the code based on based on the second enemy delays. For example, this this enemy here or sorry, the second one, will get shown after 5 seconds after 5 seconds approximately. So let's just give it a try here. I'm going to check one more time by the code here. When we start shoot out, there's another thing that we need to do is, we need to start this coroutine here when we run the start shoot out method here. Let's just run the start routine SN Enemies. Save this, and let's get back to unity. Now after it's compiled. Let's give it a try. I'm going to enable the console window so we can see the message here, the debug lock message. Let's press play. Sorry, I'm going to generate the lighting one time. Now we have the light bag, save the scene again and then press play. Now let's take a look when we stop here, the enemy after 3 seconds show, there you go. We can shoot him. And if we go to the enemy here, the under the inspector, the first enemy. We can check its health, and now our current health still one so we can click one more time. There you go. It's zero. But we need to destroy or later if we use the character, we need to play the death animation. Let's just use destroy. First now here. In the enemy script. After we kill, we want to destroy the game object. Save this let's give it a try. If I go to the prefet here, let's just fix a couple of things here. Let's just remove the collider from the box game object here. Let's just remove the collider. Yeah. And save this again. Let's run this one more time and give it a try. Now the enemies show up, we can delete here, and then we can shoot three times. After we kill all the enemies, you see that the player starts to move again, and we can define another shootout point here. Yeah, that is the basic of the enemy initial setup, and later we are going to change the model with the real robots character and also with animations. 8. 07 Enemy Animations Preparations: Okay. Now in this video, we are going to continue develop our enemy mechanism, and now let's start preparing model. If we go to the game folder and inside the game folder, I have a Robot Kyle model, and inside the folder model, we have the FBX file, which consists of the three D model of the Robot. First, we need to change the RIG setup to a humanoid and press apply, and we can leave the other settings to default. Now once we have the animation type, change, we want to open this on Explorer, so we can see the FBX model, and now we need to prepare a couple of animations. In order to do that, I've used Mixamo for creating custom animation. You can go to the address, which is mixamo.com. Just register. It's free, and then after that you can log in, and we can also upload our own character. Press the upload character and I'm going to copy the model path here. I'm going to select a character file and then paste the path, then I'm going to upload the FBX file. Once we upload the FBS files, we are going to pick one of the animation library, and that library will be retarget to the Robot kyle object. So we can use the animation correctly and fit very nicely to the robot character. Press next once already done just PressNx, and now we can select many of the animations that are available. We can also search. I'm going to search a walk with gun. Or we can search just gun and there should be a lot of gun related. Let's just search for the walk with gun. Or we can just search for rifle. Yeah, we can use this. We need a forward motion. Probably the one that are not firing would be the best. We can use this rifle walk. I'm not sure if slow, let's just for the one that are probably faster. This should be better. We want the translation information because we are going to use that to create a very nice motion that are synchronized with the animation. Press download and then set the format two FBX four unity and we can choose without skin, and then just download it. Once we press download, it will prepare the assets and we can save the FBX file. I'm going to paste our path here. And then go to the game folder and I'm going to create a new animations. Then I'm going to save this. But probably I'm going to change this to run forward rifle. Once we save this, let's search for the one that are sts. This one, we can use this one for sidestep, but I think this is too slow, so let's just look for one that are faster. Do we have this on top? Let's just search from the other pages. This one should do. We can use this. I'm going to press download again and we have the previous settings reed, just press download and then save in the same folder. We probably need a animation. This one is quite nice actually. Or this one probably. Yeah, we can use this, press download. I cannot include these assets in the tutorial because the terms and license for using Mixamo, so you can just sign up yourself and then download the animation that you need. I'm going to download this one and let's just call s for animation. Or rifle that. Yeah. I think we can use this one. Now we can press download and into the animations. Now that we have all of this, animations prepared. Let's go back to unity, and it will have the animations automatically imported. But we want to set up the animation type first. Let's just select all of the FBX files here inside the animations folder and choose humanoid. Then for the Avatar definition, since this is only an animation file, there are no avatar inside of it, so we need to copy from the other vor, Let's just copy from the other Avatar, and we can choose the Robot Kyle avatar here. This one here. It's from the Robot Kyle model inside the model folder, and it's from the Robot Kyle FBX. Let's just select this one and then press apply. Okay. So now if we select one of them, and if we go to the animation, there are some issue here. Let's check. The issue was with the model settings. So we need to change the scale factor to 0.01. We need to make sure that the settings here are the same with our Robot Kyle model here. As you can see, it sets to scale factor 0.01, and all of the settings are unchecked except blend shapes and sort hierarchy by name. And this is the most important. This convert units is unchecked. So we need to make sure the animations have that same settings. Once we uncheck the convert units and the rest of the options, press apply. Now if we go to the rig, you'll see that we don't have the error anymore. And if we select one of the animation and we go to the animation window, you see that we have a very nice animations for the robot here. Okay. Now we need to set up a couple of things here. First, we want to set the rotation, not to the body orientation, but the original and then press apply. Here, we want to change the two feet. We want to set these two big into pose here, and this one is also a big into pose. Now we have a very nice moving motion. If I close this, and try reselect this, you'll see that the robot will move linearly on this line here. So it moves very nice. But make sure that for the root transform position, we don't want to check the big interpose options. For the other the left cover here, let's just set the same thing. Set this two original, big inch pose, and this is two feet for the root transomposition y. Big inch pose, and let's just leave the root transomposition. And now if we press play, you see it moves nicely to the x axis here. The other thing that we need to set is for the hat reactions, and this make sure the root trafposition y to feed and leave the other settings. For the des animation, make sure we have the same settings. And what this setting is basically do. We are preserve the original rotation. So it's facing correctly on the z axis, the way it should. And for the root transform y position, we want to bake into the pose so it won't change the translation in the animation, and it starts based upon the feet on the first frame of the animation. There is one animation that we forgot to pick up. So basically, we want to pick up the rifle idol. So let's pick up this one. Or we can, the rifle aiming idol should be better. And then download this and save it to the animations folder. If we go back to it, you'll see that we have this new animation. I think it's wait a minute. This one. Let's just set up the model taps first, set the scale factor to 0.01, and check all of these options, except the blend shapes and the short hierarchy by name. For the rig, change this to humanoid, and copy from other Avatar, and I'm going to pick the robot Kyle avatar and press apply. Once we've already set that, we will have this aiming. For the aiming, we can set this loop options to enable the loop time. Set this to original, Big into pose, set this feet, Yeah. For the running, we also need to enable the loop time I forgot before. Press apply, check this and then press apply. Also for the left cover, we want to also set the loop time to enable. 9. 08 Enemy Animations Scripting: Okay, now we are going to continue preparing the animations for the enemy. Now, the next thing that we need to do is we need to go to the prefabs folder and then open the enemy prefabs by pressing the open prefabs here in the inspector, and it will go to prefab modes. Now here on the enemy, we can delete the cube object. For the enemy, we can also delete the mesh, caps mash filter component, and also the mesh render. We only have the collider, the mesh agent, rigid body, and enemy scrip. Now I'm going to drag the robot kyle model. Let's go to the model file and then drag this as a child object. Now if we go to the perspective or the isommetric view from the right view, if I select the enemy, you'll see that the robot is basically in this position here. Let's just align the robot game object to the base of the collider and the NM agent. Select the robot Kyle, just move this down. And there you go. We can also adjust the capsule height. Let's just select the capsule collideer. And if you over the top part of the capsul coder, you'll see a very small yellow square. It's like a handle and you can drag this, drag this and move it, so it's aligned with the upper part of the head of the robot. For the NF mass agent, we can change the height, and here we have the value of our capsule glider, just select the height value copy, and then paste this inside the height value of our Nap mas agent. We will have the same height. Now we have this setup, we need to create an animation controller. If we go to the animations folder, I'm going to create another subfolder inside the animations folder, and I'm going to call this controller. Here, I'm going to create an animator controller, and I'm going to call this base enemy. If we double click this, you'll see that we have this animator window open. We need to set up a bland tree. State here, and this will be the default state. Inside the bland three, we will have the options to change the bland three type. I'm going to use a free from directional, two d free from directional, it needs a parameter. If we go to the parameter, it automatically create a float parameter with the name of bland. I'm going to create the other float parameter. This will be the x speed. I'm going to rename this by double clicking it, and then call this x speed, and this will be the z speed. And now we are going to use the x and the Z speed as the parameters of our plan three type here. We need to create a couple of motions. Let's just add motion field. We need five motions. The first motion will be the rifle aiming idle, this one here, we want to have a value for the x position 20 and the y position 20. The x and y positions corresponds the x speed and z speed value here. The other thing that we need is the run forward rifle. The third one would be the left cover. Pick the left cover again here. For the last one, this would be the run forward rifle. Basically, we are going to invert the last two animation. This will go to the right side and this will be run backward. In order to reverse the run forward, we need to change the speed to negative one on the, the run forward rifle, animation entry. For the left cover, we want to enable the mirror animation, so it will mirror the animation. And now we need to change its value here. If we are idling, then we want to set the position x and the position y20, and if we run forward, we want to set the position y21. The z value should be one to trigger this animation, but the x speed should be zero. For the left cover, we want to set this two negative one, correct, and for the right one, which the left cover inverted with the mirror options here, we want to set this 212 positive one, and the Y position 20. For the run forward that are reverse in terms of animation speed here, we want to set the position x20 and the position y two negative one. Now we have a very nice settings over here. If we press plea, and then I expand this, you see that we have the ideal animation. But if we start modifying the x speed here, you see that it goes to the right side and here, it goes to the left side, as you can see here. If we set the z speed to one, it will move forward and it will start move backward. And we can test this out by dragging, I think we can drag this yet. You see, if I move this sideways, we will have a slightly shifted or tilted motion, and it blends very nicely with the animations. As you can see here. Now we set up the bland tree correctly. Let's just set this back to zero, zero. Now we need to go to the base layer and then start set up this so it works with the script. Let's go back to the scene view here and select the robot kyle, and now we want to direct the base enemy controller to the robot kyle controller inside the inspector and leave the apply root motions enabled for now. Let's go to the enemy script. Now we need to add a private animator variable, let's just type animator, and let's just call this ym On start, we want to grab the ym component by typing ym equal, and then we want to get component. But this time we want to get the component in children. Why is that? Because if we go back to it D, you see that the script is on the parent and the animator is on the child object. Let's go back to the script here, and then grab the animator component. The other thing that we need to do is we need to create a method called Run blend. And save this. Now the animation will drive the translate or the movement of the enemies. We need to disable the update position on the agent components. Just type agent, update position, set this to false. The other thing that we need to create is a private for three variable. Let's just type vector three as the type or the class, and I'm going to call this movement local. Okay. Now inside the run blend method, we want to check if the m is not or the m is not disabled, so enabled, but with the exclamation sign. Then we want to return. But if it's or if it's disabled, then we want to return. This method won't gets executed. Now we need to check if the agent next position. Next position is basically gets or sets the simulation position of the NMS agent. This way we are getting the next position, the simulated position, and we want to substract with our current position. We want to check the distance of this position by using a square magnitude. We can use magnitude, but square magnitude is more performant because there are no square root operation. It's less than, for example, a very small value 0.01. Then we want to make sure the animations are running to translate the enemy. Here inside the statement, we want to modify the movement local to the direction of this vector here. Let's just type or just duplicate this calculation vector. But we want to get based on the local transform of the anime game object. Let's just get the transform and then use the inverse transform direction. Since this is method, as for a factor three direction, as you can see here on the help, so we are feeding this direction to this method here. Make sure we put a sem cooln at the end of line. Now outside this if statement, we want to access the anim variable, which is the animator companion. Then we want to set the float value, which is the, this should be string, X speed, and this should be named correctly as the one inside the animator. Window here, the parameters for the animator. Now we want to pass the movement local dot x. Then for the next line, it should be the set float for the z speed, and this one would be the movement local z. Now we save this Now to test this, we can just run the method inside the update method. Let's just run the run plan here and save this. Let's give it a try and let's go back to the UT app. Go to the scene here. If we exit the prefabs, you see that both of our enemy are change or switch to the robot game object, since this is a prefab, it gets affected. Now if we press plea, let's test this out. On stop, when it's appear, it should play the correct animation. There is an issue here. Sorry, there is a mis type on the code here on my end. Basically, we need to make sure that the square magnitude is greater than this value, then we want to calculate the movement local. Means that if the transform position hasn't arrived yet, then we want to calculate the movement based on the direction. Now let's go back to unity and then press to test this out. If we stop here, it shod start playing. There you go. But it moves further, as you can see here, the enemy, because the parent game object are staying here and the one that are moving is the child game object. We need to make sure that the root motion from our animator or animations are driving the parent game object. Let's just create a script for that. Here inside the scripts folder, let's just create a CO script, and let's just call this animator move. Then we want to delete the start and the update method for the matter move here. Let's save the enemy script. Here, we want to create a on animator move method, which is a built in method from unity, and this callback will be invoked at each frame after the state machines and the animation have been evaluated, but before on animator IK. Let's just use this. Basically, we need the ym component. Let's just create a private animator, call this anym just recreate the start method, and then for the an ym, let's just get component animator. Inside the animator move, we want to offset the transform pan position based on the animation Delta position. Let's just sorry not this here, but inside the anima move on animator move. We want to access the transform Parn position, and then we want to increment this by the m Delta position. This, L s this and let's go back to unity. Here, let's just modify the prefep, so I updates the anima game object here on the scene. Let's just open prefep. Under the Robot Kyle game object here, object, we want to add the animator move script. As you can see, once we add the animator move script here, the root motion are handled by script. Animator acknowledge that inside the script, we have this on animator method or callback, and let's head back to our scene here and save this. Now let's give it a try and see if this fix the issue. Now if we stop, we should see the robot appearing. Now it's moving and once arrived, it stopped, as you can see. There you go. Now we have the robots and the robots and the animations working. On the next video, we are going to continue for the animation implementations. 10. 09 Enemy Movement Fix and Hit Animation: We are going to continue working on the enemy script and we are going to smooth some movement in this video. Let's take a look at what we have right now, and I'm going to press play. You'll see that when we selected the enemy and enable Gizmo, you'll see that the NMS agent is moving faster and it follows. And if I try to play this again, you will see also that the robot object or the game object are walking through the wall. If I dog this below here, the game window, you will see that if we try to replay this and I press play, you'll see that the agent will move correctly, avoiding the wall, but the game object are trying to get the nearest direction to the agent gizmo here, the N mesh agent gizmo. We need to fix that. I'm going to revert the layout here. In order to fix this, let's open the enemy script, and now I have open here, and we are going to create a couple of modification inside the run bland method. The first thing that we need to change is instead of measuring or comparing the square magnitude between the transform position and the agent next position, we can just grab the remaining distance from the agent object. We type the agent variable. We can get the remaining distance, and we can check if the remaining distance it's greater than 0.01. Then it means that we haven't arrived to the destination yet. We can also use the agent velocity instead of calculating the direction. I'm going to grab the agent velocity here. And I want to make sure that the NaF mess agent stays together with the game object or the main transform. Here we can put Below here, we can type Agent, the next position, and we can assign the next position to the transform. Basically, what this code is doing is, we are going to make sure that the NaF mesh won't go as fast as before and it will stick to the game object. Now we can save this and let's give it a try. Let's go to the game view and press play. If I highlight the enemy here, you'll see now the NF mesh will stay with the capsule glider when moving. There you go. And there is an issue when we arrive, so we need to fix this. But if you take a look, that you'll see that when the butt start to move, it moves correctly. It follows the path. It doesn't go through the world anymore because we are compensating the NAF mesh next position to our transform position, every frame. So we are getting the velocity, and it drives the animation to move based on its velocity. But after that, we are correcting the agent next position. Now we can tweak this even more. First, we can normalize this value here. So it's taste one, and we want to add an else condition and for the else condition, basically that we want to set the movement local value 20 whenever we arrive. Let's just type movement local equal to factor 30, and save this. Now let's go back to unity and give it a try. Now it starts move and when it's arrived, it should stop. Yeah, we still have issues. Okay. Now we can move this line here to be inside the if statement here. We want to make sure that we are updating the next mag when we are still moving and when we arrive to the destination, we don't want to execute this como. Let's let's t to play this again. Now it moves, and when it arrives, it stops. There you go. But you see that the stop transition, the dal animations transition very abruptly. We need to fix that. Let's go back to fical Studio. And here we are going to add a vector tree and then run the erb method. No left. Basically, this lb will interpolate the vector A two vector, for the vector B, we want to use this value here, and for the vector A, it's going to be our previous movement local. Let's just use movement local. After the vector B, we need to pass a float as the interpolation value. I'm going to use value of two here and multiply this by time Delta T. Now that we have this. When we arrive, we also want to the vector to this vector 30 value here. Let's just create a new vector method and then pass the movement local as vector A and vector B. We want to set this two vector 30. Let's just set the same value for the interpolation value to multiply by deta Let's save this. And let's go back to unity and play this again to see if this fix the issue or not. Now when the enemy start moving, we can see that the animations will stop very nicely. There you go. We have fixed the movement and now the enemy will follow the NAPM agent movement very close. The next thing that we need to create is we need to create an animation whenever the butt gets hit by the bullet. Let's go to the prefs folder and let's open the enemy currently on a debug inspector. I'm going to switch back to normal inspector, and then press open prefet. Here, if I select the robot kyle here, go to the animator. Let's go to the base layer. We only have this plant. We need to create two different state, and the first one should be the head state. And the second one will be the dead state. I'm sorry. This one should be the hit and that. Oh I made a mistake here. Let's just rename this default state here. This should be plan three, and this will be the hit. For the hit animation, let's just pick the hit reaction and for the dead, I'm going to pick the death front headshot. Let's create a transition from any state to the hit state and any state to the dead state. And let's just make transition from hit back to the bland three here. Probably we can reorganize this better. We need to create a couple of new parameters inside the animator. Let's just create a trigger and this will be shot and another trigger. Dead, and we are going to also create a bulion, and let's just call this is dead. So the dead trigger will trigger the dead animation, and the bulion will be a safe or a safe check for the hit animation. So we can only go to the hit animation when we are shot and the is false. Now let's go back to the script here. And we want to set whenever the bot is that, then we want to trigger the animation. Let's just try to trigger the animation, set trigger, and we should trigger the dead animation. We also want to set the set b, and this would be the is b and the string should be the same with our parameter name here in the animator window. Let's just set this true. Whenever we are still alive, we need to add an else condition, and if it's still alive, then we want to play the hit trigger, hit, shot trigger and save this. Now let's assign the condition transition here from the any state to hit, we want to add a shot trigger and we want to make sure whenever is false. The value will be false by default. For the dead, we want to set this that we want to use the dead trigger. We need to make sure that has exit time is disabled and for the hit back to the bland t, we want to make sure has exit time is true and no conditions at all. It will automatically go back to the bland t whenever the hit reaction are finished playing. Okay. Now if we check the script, again, I think is good. Let's just let's just test this by running the game, and let's to shoot the bug when it arrives. There you go. It plays the hit reaction. Oh, we cannot check the dead because we destroy it right away, so we can add the delay on the destroy. Add a coma here, and then maybe we can set the two 4 seconds delay for now and go back to unity, and let's test this again. One, two, three, and it's dead. Yeah. After 4 seconds, it will get destroyed. Yeah, there you go. Here in this video, we fix the movement, now it's much better than before, and also we added the hat reaction and the death animation. 11. 10 Basic Hit Effects: Hi, in this video, we are going to create the particle effects on the surface. So when we want to create a feature, whenever we shoot on the ground or on the wall, we want to create a particle effect. So in order to do that, let's just create a new C shop script. And let's call this effect. And let's open the script. And in this script, we want to implement the able Let's just do that, and then let's just implement interface, so it will create the public method. We don't need the uplate method for this script. And now we need to create a serize field for holding the particle prefs. The particle eff prefs. Let's just call this particle prese or eff prefs. Let's save this. We also want to create a private particle system. And let's just call this particle cache or FX perhaps describe the variable better. And on start, we want to instantiate this, and we want to make this object as a child of this game object who holds this script here. And for the effect prefs, it should have a particle system. So we need to make sure that the object that are reference to this variable here should have a particle system component attached to it. So we want to check if the effect prefs is not null, then we want to instantiate this. So let's just create a new game object reference, effects, temporary, and let's just instantiate the effect prefects, and we want to set this game object as the parents. So let's just type transform. Then we want to set the effect cache variable to the game object particle system components that are attached to it. Let's just type cache here, and then grab the effect tem and type get component particle system. Okay. So now we've created this. We want to play the particle whenever this method gets triggered. So let's just delete this, and we want to check if the FX cache is not null. Sorry, I set the wrong parenthesis over there. FX cache is not null, then we want to set the position of the effect cache to the hit point. Set also the rotation, bits its normal and play the particle effect. Let's just do that. We can grab the particle system cache here, and then type transform type position, and we can set this to the point. And we can also set the rotation by accessing the particle system variable. The transform rotation, and we can grab using the quaternion look rotation, and we want to facing the normal of the hit point or the Cas hit variable here. So now we can save this. And then we want to also play the particle. So we can just access the play method. And since the Flex cache is a particle system, then we can access the play method directly. So let's just save this. And let's give it a try. Okay, here, if I select the cube here, we can add the ha effects, and it ask for an ef prefab. So If we go to this effect examples folder and under the weapon effects, under prefabs, you see that we have a metal impact. Let's just use this. But instead of using this pref, I'm going to duplicate this prefab by pressing Control D, and I'm going to modify the duplicates. That way, we will have the original prefe And we can always duplicate the original prefabs when we want to make a modifications to it. So let's just direct this to the prefes folder. And I'm going to open the prefbs and we need to modify this. Since the particles reside on the child object here, let's just create a modification. We can just remove all of the mesnder here, and the filter, also the collider, and we can duplicate the particle system by copying the component and then paste this here. And we want to drag the sparks, dust and decal as a child of this and just delete this. Now if we go to the sub emitters, you see it still have the same reference. And as you can see, it emits to a certain spear shape. B here under the shape, we have an hemisphere, we want to use I think, instead of using a spear, we should be using cone here. Yeah. There you go. Now we have the cone is facing that way. And we can probably change the direction of the spawn here by setting the let's check the sparks here. We can rotate the child object. Let's just rotate this set this 20, and now it should be facing the correct way. Okay, let's just select all of the child game object and then set the y value 20. So I face the correct way. Okay. And now we want to make sure that the particle is not looping. Let's just disable looping and then press play. And it's looping. So We want to set the rate over time under the emission panel to zero and set the particle emission using birst instead. Let's just press plus on the birds here and set this 21 should be enough. For the child, we also want to set this out. This is already set correctly, so let's just check the dust also. It's using burst most of it. Okay. So if we press ph play only once. Et's stop and then press play again. Yeah. There you go. And we want to set the simulation space world for all of the particle here. Let's just select all of the particle and set the simulation space world. Okay. Now if we try to play again, Yeah. Okay. This way we make sure that the particle aren't going to loops, and we only want to play the particle whenever we invoke the play method from the script here. Okay. Another thing that we need to set up is we want to disable the play on awake options in the parent particle, so let's just do that. So the particle doesn't get play whenever we instantiate to the scene. Let's go back to the scene here and save the scene. And select the first cube here, and we want to drag the metal impact prefabs from our prefes folder to the effect prefabs here. Now let's save this. And if we press play, let's give it a try. There you go. If we shoot on the surface, you see that we have the particle effect instantiated. And the nice thing with this, we only have one particle, but we are basically moving the position of the particle based on our shot or hit rac as hit location, and we play the particle. And since the particle space is rolled, those particles stays on that spot, even though we click on another area and we move the p not the parent sorry, we move the particle system game object. As you can see here, we have traces from our previous particle invoke or particle play. So now we have this setup. We can just duplicate the component here. Sorry, I paste it by mistake. So I'm going just to undo this. And we can copy component this this hit effects component and then select all of the other e, and we can paste this as new. Okay. That is the basic hit effects, and on the next video, we are going to create a specific hit effects for the enemy whenever we shut the enemy. 12. 11 Enemy Hit Effects: Hi. In this video, we are going to continue on our virtual Cp game project. And in this video, let's create the hit effects for the enemy. So in order to create hit effects on the enemy, we can simply reuse the previous script that we have created, which is the hit effects and assign the effect. But there is an issue here. This won't work right away because the enemy script also implement I hitable, and the hit effects also implement that. So if we take a look here on the player script here, you see that whenever the player press the mouse button, the left mouse button, and start to shoot, it will detect only one hitable component. So we need to change this to make it work with multiple hit or a multiple component that implements I hitable. So let's just do that. And first, we are going to change the itable class here to an array, and let's just call this itables. And then we are going to use the get components method, the pleural case for the get component method. Then we want to check if the hits is not u and hables length. It's greater than zero. It means that we have at least one hitable components inside this able, I hittable array. Then we want to run this code inside the statement. We are going to use a four each statement, and basically we can create a hable in able array or collection. Let's just cut this here and paste this inside the four each statement. Let's just save this. And now let's go back to unity. And I've already prepared an effect prefs, and it's attach in the description of this course here, take a look. Basically, we need to import that package. It's called FX electric unity package, and when it just imported. And here, it used the texture from the particle eff example from unity. So we don't need to reimport this. We can just import the pre, electric prefs, press import. And now we have this prefs. If we double click on the prefs, you see that we have a very nice electric effect. There you go. Let's just use this as the effect prefs for the enemy. Let's just open the enemy prefs, and we want to change this in the prefabs level. So let's just add the Hat ex component again, and then select the fx electric drag this as the effect prefs under the at ex component. And if we go back to the scene here, you see we have multiple component just remove this one. Okay. There you go. We use the hit ex component that we added on the prefabs level, and let's save the scene. And this should be applied also to the other enemy. Yeah. And now if we press play, and then we start shoot the enemy. I'm going to disable the gizmo so we can see it better. There you go. We will have a very nice electric effect. There you go. And it still works on the wall, regardless of the changes of our player script here. Because it will grab any amount of itable or any amount script component that implements hittable. So if there are only one, then this steel wheel gets executed. 13. 12 Exploding Props: Hello again. And in this video, we are going to continue our Virtual Cp game project. And in this episode, let's create an explosive items or a props that we can shoot and then explode and also create damage to the enemy. So in order to do that, let's just create the explosion prefex first. If we go to the effect examples and the fire explosion under the prefes folder, we will have this big explosion prefep. Let's just duplicate this. And then we want to go to the prefs folder, sorry, not the prefs folder. We want to drag the duplicate prefet into the prefet folder. Let's just do that. And now we have a duplicate version of it. If I double click here, you see that we have a very nice explosion. Currently, it sets to loop, so we want to disable that. Select all of the game object and the child game object here, and all of them have this particle systems component attached to it, that's disable the looping options. Now if I go to the most parent game object, and if we press play, it will only play once. There you go. And now let's create the explosion script that handles the applying damage upon explosion, and let's go to the scripts folder. And I'm going to create a new CHOb script, and I'm going to call this explosion damage. And let's open this equipment. Now we can create a couple of variable. The first one should be the float damage radius. The range of the explosion damage, at what distance are this explosion going to damage the enemy or other object that has implemented the itable interface. We want to also create a float delay until destroyed. Yeah. So this will be the delay, how long before this explosion game object gets destroyed, and we don't need the object method, so let's just delete this. And now we want to create a method, a built in method called dro Gizmos selected. And this is basically for handling any Gizmos when this object is selected. We want to access the Gizmos class and access the color. And I'm going to set the color to red. So with gizmos dot color, this will apply any Geismo that we implement below this line here to this color. And for example, if we implement a couple of codes here and then we implement another color changes to green, for example, then this implementation will affect all of the Geismos that we implement after this line here. So that is how gizmos dot colors work. So let's just delete that. And then let's go deleting all of this used line, and let's just access the Gizmos class again, and we can draw couple our many shaped cube frustum gutture, icon and stuff. I'm going to use the wire sphere. And this is a method. And for the center, I'm going to use the transform the position of the explosion damage game object here. And for the radius, you guessed it that we are going to use this value here. So I just duplicate this and paste it here. And safety. And if we go back to unity here, you see that if we apply the explosion damage script, you see that if we increase the damage radius, we will have a radius indicator. So when we approximate the damage radius size on the screen, we can estimate the optimum size before this explosion affect nearby enemies. So let's just set this 23. And here if we go to the top view here, you'll see that press play, the explosion is approximately size of three in terms of radius. This should be enough. For the delay until destroy, we can check the duration, which is 2 seconds currently. Let's just set the delay until destroyed to also 2 seconds, but I'm going to add 2.2. It took longer until we destroy this game object. Let's go back to Fiscal Studio and continue on the script here. Now we want to run the destroy method, and then let's destroy this game object after the delay until destroy seconds arrived. Now the next thing we need to do is we need to create a method and this will be a custom method. I'm going to call this damage nearby objects. Here, when we execute this method, we want to grab all of the collider inside a sphere that we are casting. So let's just create a collide class here or object, and array of collider, and let's just call this calls collider. And we can use the physics class access its method member and use the overlap sphere. This also ask for a position and also radius. Let's just pass the transform that position, and for the radius, let's just use the damaged radius. Now, we will get a bunch of collider stored inside this calls array, and we need to look through that collider. Let's just create a four e statement. For the variable, I'm going to call this call Stans Form collider, and for the collection, we can just grab the calls collection here and save this. Basically, we want to check if the variable or the object that we are currently iterating, we want to check if the object have a i hable components attached to it or not. Let's just create a able array, or we can just copy the code from the player script. Let's just take a look. We can grab this, and then paste it here. There you go. Basically, we need to change the hip to the call game object here. Let's just type call. Since this is already collider, we don't need to access the collider. Let's just delete that. And we want to pass a ray cast inside this if statement here. So basically, on every look of our four each here, we want to create a ray cast from the explosion damage central position to the game object that has hit als attached to it. So let's just create a new ray cast it, let's call this hit. And then we are going to create another if statement. And this would be a physics that Rak has, and we are going to use the overrides the eighth override. So we want to use this variant of the method. Basically, we want to use the origin of the explosion and the direction, and the rac has hit as the out parameter. So let's just type transform that position here as the origin. And for the direction, we can just grab the collider game object that we are currently iterating. Grab it transform that position, and we can substract it with the transform position. And with factor subtraction, we will get the direction from the central position to the collider game object position. Here for the third method, we are going to output the resulting cast operation to the hit parameter or variable that we've declared here, and now we can save this. Here inside this hables or the second for each loop here, we can pass the hit cast as the argument for the hit method and safety. But for the explosion damage, we want to make sure that it kills the enemy with only just one hit. We need to modify our or hittable interface. We need to also pass a integer damage, and we can set this default to one. Okay. Basically, with this default value, if we don't specify damage value, then it will pass one as the damage value by default. We can just leave the previous implementation without changing the code here, for example, the dynamic object. We can just yes, we still need to implement the damage. So let's just type damage, set this two equal one. Let's check the other script. For enemy script. We also need to modify the hit able. Yeah. There you go. We have an error. Let's just go to the hit method and then add an h damage equal one. Now here on the enemy script, we can just use that damage to subtract our current health. Let's just And safetess. The other thing that we need to check is the hat effects. Yeah. We need to modify this also in damage one. We won't be using this integer here, but still because we implement that in our interface, we need to pass those value here. And now if we go to the explosion damage, you see that the hat method now soon will ask for an integer damage. But since we set the default value to one, we don't need to pass that. But for this explosion damage, we want to pass a very high value, for example, 100. So it will kill the enemy instantly and save this. Later, we are going to also use this damage value to create a weapon variant where we can have a better or a greater weapon that has a greater damage value. For the player script, right now, we can just lit this as it is. Okay. Now we have this implemented. We need to run this on start. Let's just run the damage near my objects method on start and save this. The last thing that we need to do is we need to create a spawn on shoot a script that will spaw the explosion upon shoot or upon head. Let's just create a U subscript, and let's just call this spawn on a let's just open this. For spawn on it script here, this is a quite simple script actually, so we can delete the start and the update method, and we will need to implement the able interface, and then let's just implement the interface. Now we are going to create a serials field, and this will be the game object. We can just call this prefabs paw. Then we can create another Serres field, and this will be A B and we can call this destroy on it. And let's implement the hit method here. Basically, we want to check first if the p choose paw is not null. To prevent null reference exception, and inside this statement, then we want to instantiate the choose paw, and we want to set the spawn on hit game object transform that position. And after transform that position, we want to pass a default rotation, which is quaternion do identity. And now we want to check if the on hit is true, then we want to destroy this game object. And the spawn on it game object will be the object that spawn the explosion, for example, or anything else. For example, a barrel, gas barrel, or something that are explosive or flammable. Let's just save this, and let's go back to Unity. The next thing that we need to do is, I've already downloaded this assets from Unity ***. It's free. It's called Ci Barrels 40 sample, and I will put the link to the description here. Let's just press import. Let's just import this. But I'm not going to import the scene here because we won't be needing that. Okay. Let's just import this. Once it's imported, I'm going to direct the sci fi barrel folder sample to inside the underscore game project game folder here. Now, let's go to the prefect here and select the one that we want to use. Probably I'm going to use this one. Let's just d barrel white S to the environment group here game object. And it should be somewhere in our scene here, it's here, and let's just put it here. Let's just check the size of. I think we can put it over there. Let's just hide this guide here. We won't be needing this anymore. Let's just deactivate it and save the scene. Now if we select the barrel white game object here, I'm going to add a collider first. We need a collider. Let's just add a box collider and it fits. Then we want to add the spawn on hit component. For the pref to spawn, let's go to the prefex holder and drag the big explosion that we have prepared before, and let's enable the destroy on hit and save this. Now let's open the console window here and press play. So let's just wait a while until the enemy appears. There you go. It appears and also appears, and let's shoot the explosive here. There you go. It kills all of the enemy. So it's quite nice that we have this and we can use this for help the player navigate a harder area. And if you take a look here, we have an issue that the get remaining distance can only be called on an active agent. And this is happening because here on the run bland, we are checking if the agent remaining distance is greater than this value here, and this gets executed on update. So after the enemy is killed, we are disabling the agent. There you go, and this causing issue. So let's just add a condition here on top of the if statement. And add if if the agent is disabled. Basically, we want to check if the agent is not enabled, then we want to return, and save this. And let's give it a try one more time to see if this error is still showing or it's still happening or not. Let's press play, and wait for the enemy. Okay. So now let's shoot the barrel again. Okay. There you go. We killed both of the enemy, and we don't have that error anymore. Yeah, that is how we create an explosive props, and you can use any other explosion type if you want to. Just add the explosion damage to the explosions. 14. 13 Custom Weapon: Hi. In this video, we are going to create a custom weapon mechanism. So we can change weapon based on the weapon that we pick up, and if the MO runs out on that weapon, we want to revert back to the default weapon. Okay, first thing, first, we need to create a new CS script, and this will derive from the scriptable object. So I'm going to create a new subfolder inside the scripts folder and I'm going to call this scriptable objects. Here inside the descriptable objects folder, let's just create a new Shap script, and let's call this weapon. Data. And let's open a script. Since this script is going to be a scriptable object, we need to change the mono behavior type here to a scriptable object. And scriptable object is basically a script that we can save as an asset in our project folder, and it can hold and also method. And we also want to move the up method here from the player script to this weapon data. We want to move all of this shooting script or code into the weapon data here. Another thing that we need to do, we need to define a menu to create a set menu here. On top, let's just create an attribute and it ask for two arguments. First is the file name. Both are string. The first one is file name and the second one is the menu name. For the file name, we can set this two file name equal weapon data or we can add a custom weapon data. Then here inside the parenthese menu name, we want to pass weapon data. And close this with a parents, and safety. Basically, this will allow us to create this scriptable object using the menu inside the project folder. Let's just delete the update and start, we won't be needing that. We are going to create a custom data here. First, we need to create a custom enumerator. Let's just create a custom a here outside of our weapon data class. Let's just type public am, and I'm going to call this fire type. And there will be a single and rapid. Rapid is for automatic gun type and single is for the normal weapon or the default weapon. Let's create the needed variables here. First, we are going to need the fire type. Let's just type the fire type as the variable type, and I'm going to call this type. And the second one will be the rate, but this should be a float, so type float and call it rate. I'm going to set this default to 0.15. The next field will be an integer, and this will be the max MO. And the other one would be an integer also and this would be the damage value. We also need to create another bleion to define whether this weapon data is the default weapon or not. Let's just create a bleion called default weapon. And we also need to declare a couple of private variables. First, we need to have a reference to our camera. Let's just create a private type of camera. Let's just call this CM. We need to also have a reference to our players script. Let's just call this player, and also a reference to the current O, and also we need to create a float variable to hold our next fire time. Okay. And since we need a reference to the player script and also the camera, we need to initialize this scriptable object using a method, and that method will be called from the player script here. So I'm going to create a public void setup weapon. And I'm going to pass the camera as the first argument, and the second one would be the player script. I just call this player also. Okay. So inside this method here, we can first define the KM variable here by using this statement, this equal K, and this will be referred to this variable here, the local variable that we have inside our class, and this will be referred to the argument that we are passing here. The second one should be the player to player equal player, and we want to also set the next fire time to be zero, so we can shoot right away whenever the game start. Also for the current MO, we want to fill this to the next MO that we've set up on the inspector here. That will be all for the weapon setup, and the other method that we want to create is the public void fire. For fire, we don't need to be a public, so we can set this just to be a private. Let's just go to the player script here, let's just copy all of this here inside the update method. I'm sorry, I'm going to highlight all of them from the I statement to the closing brackets, right click, and then press copy, and then I'm going to paste this inside the fire method. We will have errors. Good. There are no errors because we already defined the CM here so we can use this right away. And I'm going to create a public void, and I'm going just to call this weapon update. And this is the method that we are going to call from our player script update, replacing all of this here. Okay. Inside the weapon update, basically, we want to check whether the fire type is a single shot or a rapid shot. Let's just create if statement, and if the type equal to fire type single. Then we want to have a separate code else. If it's a rapid one, then we should have a different kind of shooting mechanism. The first one, we are going to use the if input, get mouse button down, and we are going to grab the left click. This zero value indicates the left click, and inside here, we want to run the fire method. We want to run this one here. Oh, sorry. In the fire method, we don't need the input get button down statement anymore. So let's just delete this and the last bracket here, and I'm going to organize this by moving back to the indentation. And then when we are firing, then we want to substract the current MO by one. And here, inside the rapid fire type, we want to use an input that get mouse button. Zero. So this one is for holding, and it will return strug whenever we hold the mouse button. And this is only on the first frame when the user press the mouse button. So this only happened once, and this happens throughout many frames, depends on how long the user are holding the left click. And we want to add a statement where the time the time is greater than the next fire time. And safe test. We want to also check if the current MO is greater than zero. We want to also check if the current MO is greater than zero, and we want to create an if statement, and this one if the current O is less or equal than zero. For this here, we can just create the else statement. Here, let's just type the bug log and type O runs out, please reload. We can just copy this line here and paste it here, so it will throw out the same message. And now here, we want to run the fire method and also substract the current MO. Then we want to set the next fire time to be equal our current time when we are firing at this moment here and then add the rate value. This is the rate value. So we will only be able to shoot automatically at this time or if the time time is greater than our last next fire time. There will be an interval between shot. Although this is a very short one, just like an automatic weapon, and we can change this rate value in the inspector, so we can tune those value to fit better of our weapon characteristic, and let's save this. Now that we have this inside the weapon update, we want to also create a Couple condition. And this one would be if currently we are using the default weapon, and we are pressing the button. Sorry, not to get button, get most button down. And this one will be the right click. So that's why I'm using one as the argument. Then we want to refill the O. Current O equal the max MO. And this is for the default weapon. We want to set that we can reload for the default weapon, but for a custom weapon, we won't be able to reload this. And then here, we also want to declare if this is not a default weapon, and the current O is equal or less than zero, then we want to switch back to the default weapon. But we haven't implemented this yet in the players script, so I'm going to I'm going to type a comment here. Okay, save this, and I think that should be okay. Let's go to the player script. I'm going to drag the play script, to be the site of our weapon data, so it's easier to switch. And now we can just safely delete all of this, the update. I'm going to create a new SuriS field, and this would be a weapon data, and this would be the default weapon. And I'm going to create a private variable, and let's call this weapon data, and this would be the cur weapon. Inside update, we want to check if our curn weapon is not new, then we want to run the cur weapon weapon. And here, let's just create a public method, and let's just call this switch weapon. And for switch weapon, we need to pass a weapon data as the argument, but we want to set a default value of null here. So we can run this method without passing any argument and it will automatically pass a uL data to this method here. Then we want to set the current weapon value to whatever we are passing here. We want to check if not null, then we want to pass the weapon, and if it's null, then we want to pass the default weapon here. So it seems that I've mistyped this, so it should be default weapon. And I'm going to use this name here. So basically, this is a ternary operator. And if this statement is true, then this will be passed to the current weapon. But if this is false, then this one will be passed to the current weapon. And after we switch weapon, we want to run the current weapon, set up a weapon method, and we need to pass the camera. So this would be the CM here. And the next argument is the player script itself, so we can just pass this statement as an argument. And here, whenever we start, we want to run the switch weapon without argument. So we are assigning the default weapon to the carino weapon, and that is going to be the weapon that we are going to use inside the update method. Let's save this. And for the weapon data, I'm going to also use the switch weapon here inside this if statement here. So basically, if it's not the default weapon and we are running out of MO, then we want to switch back to the default weapon. So we can just access the player variable that we've prepared. And let's just call the switch weapon, and we don't need to pass the argument to set this back to the default weapon. Save this. Okay. So let's get back to unity here and let's give it a try. It's already finished compiling. So if we go to the main camera here, now we have a default weapon slot inside the camera or the player script. I'm going to create a folder. Oh, sorry, this should be inside the game, so I'm going to drag this should be inside the game folder. And inside data, I'm going to create a weapon data here. As you can see, we have this asset menu now, create asset menu. So let's click this, and this would be the default gun. And for the default gun, we can set this two single, and for the damage value, we can set this 21, and the maximum MO 210, probably, and let's check this default weapon. And for the default weapon, then we can select the main camera, and we can assign this to the default weapon here. Okay. So now I'm going to create another weapon and this will be a machine gun. And for the machine gun, we will have a maximum MO of 13. Set this type two wrap it and a greater damage value to chew, and I'm going to disable the default weapon here. Save this. Now for testing this out. Basically, this code here won't be working yet because we need to implement weapon pick up later. But let's just test this if you see that if we change the weapon data, will the player script works, let's just test this. I'm going to press play. Now I can only shoot once every click. And we need to shoot three times to kill the butt. Sorry, there is an issue with the butt here. I'm going to check this first. I'm not sure what causing the error before, but now it seems to be working fine. So let's just give it a try again. Now using the default weapon, default gun. I need to shoot three times one, two, three, one, two, three. Let's change this to a machine gun. I'm going to go back to the machine gun scriptable object here. I'm going to change the damage value to three. So we will see that we only need to shoot once to kill the enemy, but there is one thing that we need to modify in the script here. In the weapon that here, we have the damage value declared. But here, whenever we hit, we don't pass a damage value, so it will default to one, as you can see in the coat in there. So I'm going to add damage value variable as the second argument and safety, and this should work. And we don't need to test the default gun because it's Sorry, V. Yeah, because the default gun has a damage value of one. So it should behave the same as if before because we have the default value of one. And machine gun have have damage value of three. When the enemy came out, we can see that we can shoot once and it will kill the enemy right away. Oh, sorry. I forgot to replace this. We are still using the machine gun weapon data. So let's just change this to the machine gun and save the scene again. Okay. Let's write. You shoot these robots. There you go. One shoot, and it kills automatically. So yeah, there you go. We have a custom weapon, and we can create lots of different weapons depending on the characteristic of the weapon itself. 15. 14 Weapon Pickup: So let's continue on our custom weapon mechanism. And now we are going to create the mechanism to pick up a weapon from a bonus. So first, let's create a script, and this would be a new CH script, and let's call this weapon pick up and this would be a very simple script, actually. So I'm going to open this now here, go to the iso studio. Yeah. Now it's open. I'm going to resave the weapon data. And here, we need to create a new serialized field, and this will be a type of weapon data, and let's just call this weapon. And we also need a private variable of players script, and let's just call this player. And I start, we want to grab the player script from our scene. So let's just type player equal fine object of type and pass the player script as the type, and we want to remove the update method. And basically, we want to make sure that weapon pick up, implement the i hable interface. Let's just type the i hittable, and I'm going to implement the interface automatically here. And let's just delete the exception here. Okay. So basically, whenever we shoot this weapon pick up object, we want to run the player switch weapon, and then we want to pass this weapon variable here. So this will set up a new weapon on the player side, and we can use that new custom weapon right away when we shoot this game object. And then we want to destroy this game object. Okay. So let's go back to Unity, and let's just create a new cube, and I'm going to scale this down here, 20.6. Then let's add the weapon, pick up script. If we go to the data folder, we want to set this to the machine gun. And let's save this. If we go to the main camera, or if we select the main camera object, we want to set the default weapon back to the default gun here. Let's just save this and let's change the inspector to the debug window here so we can see our curent weapon over here. Let's rename this cube here that we've just created as the machine gun pick up. And let's save this as a prefab. If we go to the prefs, I'm going to drag this machine gun pick up as a prefs object, and let's just delete this one from the scene, and I'm going to duplicate this barrel object. But instead of spawning an explosion, I'm going to spawn the machine gun here, and I'm going to make sure it's destroyed on hit. Let's disable this one here. We can just test this weapon pick up prefs. Save this. Now if we press play, I'm going to try to shoot and I can only shoot once before I shoot the other weapon. And now it's empty. I cannot shoot anymore. If I right click, I should be able to to reload. I'm going to shoot this barrel, and you see it switched to our weapon, pick up and let's click this. Now, if I click this, if we go to the main camera, you see that our current weapon is machine gun. Let's just try to shoot this so many times, and I'm holding the mouse button now, as you can see. Now when it's empty, it automatically switch back to the default gun. Of course, we are going to implement the UI, so it will give the player an indication whether we are currently using the default gun or the custom gun, and also it will show us warning or a message if we need to reload our weapon. 16. 15 Weapon FX: Hi. In this video, we are going to create a weapon effect. So let's get started. First, let's go to the scripts folder under the scriptable objects folder, open the weapon data script. Now we want to create a new zero S field variable, and this would be a type of game object. Let's just call this muzzle ex. We want to also create a new float variable, and this would be the ex scale. Probably, we want to set this to 0.1 by default. Also we want to create a private particle system. Field here, and let's just call this cache effects. Here, inside the setup weapon, we want to add a if statement and check if the muzzle effect is not null. Then if it's not null, we want to instantiate this and then save the particle system component as a cache effect. First, we need to create a new temporary object game object, and we want to instantiate the muzzle effect. And here, we need to create a new method inside the player script, and let's just create a new public void. And let's just called the set muscle effects. Then we want to pass the transform of the effects. And we need to also create a new transform and let's just call this child effect. First, let's check if the child eff is not null, then if it's not null, we want to destroy the child game object. Then we want to set the object that we are passing from the weapon to set its to this game object. Then we want to set the child eff. To this current effects that we are currently passing. Save this. Let's go back to the weapon data here. And then we want to run the player script, which is the player here, and then we want to run the set muzzle effect method. And let's pass the tamp game object, but we need to pass the transform component. Let's just type the transform. Then here below, we want to cache the particle system that are attached to this game object. Let's just type tat component, and then let's just call the particle system. And now we need to go to the fire method here. Whenever we fire, we want to play the cache effect particle. In order to do that, I'm going to create a new factor three, and then I'm going to call this muzzle position. I'm going to use the camera object and then access the method that it's called screen two world point and screen two world point as for a factor three arguments. I'm going to create a new one and I'm going to grab the mouse position x on the x axis. For the Y xs, let's just grab the input most position Y. For the z xs, we want to set a very small value that are very close to the camera. For example, 0.2 should do, and then we want to end this line here. Another thing that we want to make sure is we want to create an if statement and then check if the cache effects is not. Then we want to run this code here. Let's just put the muzzle position inside the if statement. Then let's just set the cache effects, the transform do position. The muzzle pause that we've just created. Then let's set the rotation of the cache effect. Th quaternion rotation, and let's get the ray direction. We want to use the direction of the ray here. The last thing that we want to do we want to play the particles. Let's just call the cache effects play method, and save this. Now this should work. Let's get back to unity, and let's test this out. Inside the effect example, let's go to the weapon effects, and then under prefs we have this muscle flesh. Let's just duplicate this, and then drag this duplicate muscle flash into our prefs folder. And now I'm going to open the muzzle flash effect and modify this. If we go here, you see, it's actually already very nice looking muscle flash, but we need to change the settings a bit. Here, we want to disable the looping, so it doesn't loops anymore, only play once. Let's set the y rotation 20. Let's go out from the prefabs and I'm going to rename this object prefabs to muzzle flash only. Here inside on the data folder, we want to set the muzzle effects to that game object. Let's just open the prefects and then drag the muzzle effects here to the scriptable object of our weapon and for the machine gun, we can also use that for now. But later we can create eight different muzzle effects. Now let's test this out. If I press play, we should be able to see the. We have a issue here. As you can see here, if I select the camera, the clipping planes are set to 0.3 on the near properties, but here, when we position the muzzle flash here, you see, we have set this to a value that are smaller than the clipping planes. So in order to fix this, we can just set the near value to a very small value, type zero, and it will snap to 0.01 and save this. Now if we press play, again, we can but we have a very big muscle effect. So we need to apply the scale that we've declared here. If you see here under the serialized field, we have a fX scale fields declared, but we never used this. So in order to use this, we can just go here and then insert a new line and access the scale of our time game object, and then set this value to equal vector three dot one, and I want to multiply this with our f X scale. And for the default value is 0.1. So we are going to scale the particle by a tenth of its default size. Let's go back to unity here. And if we check the default gun and the machine gun, we have an effect scale of 0.1. So if we press play now, the muzzle effect should be smaller. Yeah. There you go. If we want to decrease this, we can just set this two even smaller values. And for the machine gun, we can set this to a slightly bigger one than the default one. So let's just type 0.07 here. Okay. Now if we shoot, you see we have a very small muzzle flash. But if I shoot this, and then I pick up the machine gun, you see we have a bigger muzzle flash. Okay. There is another thing that we need to fix here. If I press play, you see the impact particles. The decals is facing the wrong way. Basically, it has a cell rotation. We should align this particle to the wall here. Let's open the metal impact particle here, the p, open here if we expand this, go to the decal me object, and you see under the renderer here, we have the render alignment sets to view. Let's just change this to local, and let's go back. To the scene here and let's test this out. Now if I shoot here, the decals align perfectly. There you go. Yeah, that is basically how to create a weapon effects. 17. 16 Delay Action Extensions: In this video, we are going to create a set of tools in an extension script. In order to do that, let's go to the scripts folder, and inside the scripts folder, let's create new folder called extension. Inside this folder, let's create new Shop script, and let's call this extension. And let's open this. So for you who wonders about the extension script. Maybe some of you often see that whenever we create control or input detection, we are using the input class like this, and then we are running a method like get button or get button down. And this is basically an extension to do input related things. And we can also create our own extension for another set of tools that are purposed to do other things. So let's just delete this, and we are going to start and the upput method. And we're also going to delete the mono behavior inheritance there. And we are going to set this class to be a static class. And now we can create a static method that are going to be used on other class, and this script doesn't have to be attached to an object in the scene. So now I'm going to create a new public static method, and I'm going to call this delayed action. And we will be requiring a couple of arguments inside. The first thing, we are going to use this key word, and then the type will be mono behavior, and I'm going to call this B, and the second one will be an action, so we can pass a method or delegate into the second parameter. Let's just type system action. And let's just call this action and save this. And we also need to create a new static enumerator to do the core routine here. So let's just call this delayed core routine. And then we want to pass an action again. Let's just type system that action to declare the action class, and then let's just call this action. And we also need a float as a delay. And here we also need to pass a float as the third argument. And now inside the enumerator, we can just use the yield, return new weight for a second, and then pass the delay as the value. And after that, we can just run the action. We can check if the action isnull or not using the question mark and then type dot invoke. So this is basically check if the action isnull or not, and if it's not null, then we want to invoke the method inside of this action. So safety, and now inside the delayed action, we can just type the MV, which is our mono behavior, because start coroutine can only be executed from a mono behavior class, so we need to pass this, start co routine, and then we can pass the coroutine name, which is the delayed coroutine that we have below here. And then we can pass the action, which is the action, and for the delay, we can pass the delay. Safety. And this keyword will be as an extension of the mono behavior. So right now, if we go to the player skip, for example, we can use that extension by using the dis key word, and this will refer to this mono behavior right now that we have the player script, and then we can run the delay action. As you can see here, we now have this method, and it says it's an extension over there. And now we can pass a method. And then after we pass the method, we can pass the delay. So for example, if I want to run a certain method or a certain delegate, and then I pass five for the delay this delegate will gets executed 5 seconds after the start are executed. So now I'm going just to create a new delegate here. And then I'm going to create a code. Let's just type debug that log. And then let's just finish the code here. We can just type delayed action runs after 5 seconds and save this. And this resides on the players script. So now if we go back to Unity, and then we check on the console panel, and then if we press play, you'll see that we will have that message. In 5 seconds. There you go. Here, you see that that code inside the delegate gets executed after 5 seconds. Now we have created this delayed action extension, and this will be quite useful for running a delayed method or a delayed code if we needed, and this is how we create that extension. Basically we can extend any type of class, moo behavior, factor three, or any other object. 18. 17 Game Manager States: In this video, we are going to start creating our game manager, and we're also going to start to implement the game states. So each state, we can run a separate codes, like when we are starting the level, we can set the ready for probably around 3 seconds and we can show a text animations and then start the gameplay. And also at the end, we want to switch state to level so we can start calculate the score. So in order to do that, let's go to the scripts folder, and let's create a new C sharp script, and let's call this game Manager. You'll notice that once we created the game manager, it has a different icons, and this is the default icon that Unity has provided for any script that are using the name Game Manager. Now we can open this in fisial studio, and for the game manager, first, we want to declare a public static game manager, and let's call this instance. This will be a property, so I'm going to set a public getter. But for the setter, I'm going to set a private setter. And this way, this property can only be set from this script here, but it can be or it can be accessed from any other script. And the static reference, make sure that this variable only have one instance across in the project. So it's shared. And now we want to create a new void weight method, and let's initialize the instance variable or the properties and pass this script itself. Now outside of this class, let's just create a new public en and this will be the game state. And for the state, I'm going to set a default state and for the start state. And the gameplay state, and the last one should be the level and state. Now that we have declared the game state, we can use this in our game manager class. So let's just create a new sealized field, and for a type, this will be a game state, the um that we've declared here, and for the object name or the variable name, let's just call this state. And we will also need a reference to the player movement script. Let's just create a new serialized field. And I'm going to type player move for a type, and let's just call this player move. And now we want to delete the update method, since we won't be using it right now, and let's just create a new public void, and this will be a switch state method. And this method we'll handle the switching state of our gameplay. So for the argument, let's just type game state, and let's call this new state for the new state that we are passing. And we want to check if our current state is equal the the new state that we are passing when we are running this method, we want to return this method. So don't execute any code below here. And if it's different, then we want to set the state to the new state that we are passing. And here we want to use the switch case, and we want to check the current state value. So here, let's just open a bracket, and then if it's case game state start, then we want to run a certain code here and then add break. And then we can just duplicate this blocks of code and then paste it two times. And let's just change the state to gameplay, this one, and the last one should be level. So now we have a switch statement that handles three state of our gameplay. And right now we haven't set up any UI or text for the start state. So let's just run a debug log, and let's just type game Start. So we can see it in the console. And then here, we can use the delayed action that we've implemented on the last video, and then we can just pass a new delegate. As the action. And for the delegate, we want to run the switch state method. And then for the state, we want to change this to gameplay. And here as the second argument, we can just pass the duration. So we want to execute this code here after 3 seconds. And now we can just run a the back log here inside our gameplay, and let's just type state gameplay. And we can add time here. Time time. You see the time stems when this code gets executed. So now on start, we want to also make sure that the player move script is disabled. Oh, I've typed this wrong. It should be player move. So we want to make sure that the player move is currently disabled on this state. So let's just set the enabled value to falls. And we can just copy this line here, and up on starting the gameplay, we want to enable the script. Now we have this implemented. We are going to expand this later. But right now on the start method, let's just run the switch state and set this to gameplay start. We won't be using the default value, but we want to make sure that when we are running start the first time that this level initiated, the state and the new state will be different. It will default to the default state, and then when we execute the switch state start in the start method, I will switch Judi state here. So now let's save this. And since we created a static instance reference to this game manager, we can access this script from anywhere from any other script. And since this is also a public method, we can access this method from any other script. So later when we are finished the game, we can trigger this level and state from other script. Now let's get back to Unity. Once it's compiled, I'm going to create a new anti game object and reset the transform value, and I'm going to call this game manager, and then add the script, and I'm going to assign the player move. Direct the main camera to this player move and it will register the player move script that's attached to the main camera here. I'm going to put the game manager on top here so we can access it easily and save the scene. Now if we open the console here, I'm going to clear this out, and if we press play, you'll see that the game will start, and after 3 seconds, it runs. Here, when we start logging the gameplay state here, it prints out the time statem which is 3 seconds. So after 3 seconds, we can start the gameplay. In those 3 seconds later, we can create a UI animation like a ready text or something else. Later when we finish the game, we can switch to the level and state and start trigger the score calculations. So that is for creating the game state, and later, we are going to expand this game manager by adding a score calculation and life or health for the player. 19. 18 Game Manager Score and Lives: In this video, we are going to continue our game manager, and in this part, we are going to create the lives and the score. So let's go to the sal studio, and I've opened the game manager here. So now we need to declare a couple of private variable. So I'm going to create a new private integer, and the first one would be the enemy hit and then shot fire. And we also need a private float for our current health, for the player health. And here, both, we need to create a new serialized field, and this would be a type of integer, and let's call this player health and sets its default value to ten safety. Below start, let's create a new method called in it. Here, we want to initialize the current health to the player health that we've declared on the Ses field here. The next thing that we need to do is we need to create a new public void method. Let's call this shot hit, and we want to pass a bulion, and let's call this bulion hit. And if hit is true, then we want to add the enemy hit value. And we want to also add the shots fired value, whether we miss or we hit the enemy. And we are going to use this both variable to calculate the accuracy of our shots. The next method that we need to create is the public void player hit, and this is for the player to receive damage from the enemy. We want to pass a float damage. And upon executing this method, we want to subse the current health by the damage value. And make sure all of the methods are using the public scope modifier, so it can be accessible from other script. So let's save this. And now let's go to the weapon data, and inside the weapon data, we have the fire method. And here we want to check if we hit the enemy or not. So inside the four H, we can check if Our current hit object is an instance of an enemy script. So we can check by using the keyword and then type the type of the script. And here we can access the game manager instance and run the shot hit method and pass through as the argument. And make sure we return the method here. So it will skip the other hitables. Because if we found an enemy script in the hitable, then it means it must be the enemy. Here we can add an L statement because if we hit other instances of hitable that isn't the enemy script, then we want to pass false as the argument of the shot hit method here. And we want to make sure that we return the method when we hit something. So under this statement, the physics has brackets. We want to return the method. And here, if we don't hit anything, we also want to run the shot hit with false argument. So let's just copy this line here and then paste it here. So basically, what we are doing here, we are checking whether the hitable is an instance of an enemy script or not. And if it's true, then we are passing the true argument as the shot hit. And we return the code because we don't want to check for further hitable component. And if we don't found an enemy script at all, then we are running this code here. And here, if we miss It doesn't hit anything, then we still want to count the shot hit by passing the false argument. So let's save this, and let's head back to Unity. And here, we can select the game manager. Under the Inspector tab, we want to make sure that we right click on it, and then select the bug. So we can see the private variable in our inspector. So now let's press play and test this out. And now you see if I shoot on the air, we add the shots fire. And if I shoot on the wall, we also add the shots fire, but the enemy hit stays zero. And now if we hit an enemy, you see that we add the enemy hit and also the shots fire. And let's just try to kill the enemy here. And you see that we have six enemy hit and eight shots fire because we we have tried shooting on the scene because we have tried to shoot before we shoot the enemy, and we are shooting in the scene without hitting the enemy. So we have two additional shots fired compared to the enemy hit, and we can use this value to calculate the accuracy later. There's one thing that we need to do in the game manager script. Let's go to the Ficial studio. Under the game manager. On the start, we want to run the init method. Let's just type in it. And we want to make sure that the current health are sets to the player health value on start. Now if we try again, check on our current health, it should be ten. There you go. But we haven't implemented this yet, so we are going to implement this in the next video. 20. 19 Weapon Pickup Visual: In this video, we are going to continue to create a visualization for our weapon pick up. So in order to do that, first, we need to go to the asset store and download any weapon model. I've picked this one, the Sipi gun light, and I'll put the link in the description. So I've already downloaded and import this asset, and now it's under the Sipi gun light. So I'm going to drag this folder and put it inside our game folder. And just to make things even tidier, I'm going to create a new subfolder inside the game folder and call this models. And let's just put all of the models inside this subfolder that we have just created. For the Robot Kyl, I'm going to move that also and also for the Sipi gun light. Now we have put all of the models inside our model subfolder. Let's go to the game view here, and first, we need to modify the prefs object for our weapon pick up. Here we have the machine gun pick up prefs under the prefs folder. Let's just open the prefs. And if you go to the scene here, you see we are in a prefs mode. And now we can drag the prefe of our sci fi gun light that we have just imported. So I'm going to go to the prefs folder, and inside the gun light folder, the gun have five variations of color, so we can pick one of them. I think I'm going to pick this one or maybe this lighter one and set this as a child of our machine gun pick up game object prefps. And now it's on the scene, but the position is not zero out, so it's somewhere over here. In order to center the gun according to its parent position, let's just zero out the transform, so we can just click the **** wheel settings here and then set reset position. And let's go to the parent game object and just delete the mesh filter component and also the mesh render. And I'm going to increase the size of our weapon pick up scale by chew on every axis. And then let's just position the child object around the center of its parent object. So I think yeah, this should be enough. And if you having a hard time to reposition this because of the pro grid, just hold the negative sign on your keyboard, and you can change by pressing the negative and the plus sign near the back space keyboard. You can change the size of the increment or the snaps value of the grid. So now I've repositioned my gun here. I'm going to go back to our scene here. And now we need to modify the script. Of our weapon pick up and also the spawn on hit script. Let's just go to the script folder, and I'm going to select the weapon pick up script and open it in fis Studio. Now we need to create a new serializable field type of float, so let's just create that, and I'm going to call this rotate speed. Let's just set this default 290, and this is in degree. And since we are going to multiply this value by time Delta time, it's going to be per seconds. So now let's just create a FOID update method. And inside the update, I'm going to access the transform component and then access the rotate method. And I'm going to use the second overload of the method, which is a for an axis and an angle. For the axis, I'm going to type Vector three dot up, so it's the y axis, and for the angle, we're just going to feed the rotate speed, but we are going to multiply this by Delta time. So the speed of the rotation will be consistent, which is 90 degrees per second. So let's just save this. And the other thing that we need to modify is the spawn on hit script, let me just show you now if we press play, and if I shoot on this weapon pick up, you see that our gun is somehow submerged to the ground. This is because the gun is being instantiated on the zero position of our parent game object in this one here. So it gets instantiated at this point. In order to fix this, let's just open the spawn on hit script, and I'm going to add a new serialized field. And for the type, it will be a float, and I'm going to call this y offset. So this is the offset on the y position. And I'm going to set this two deft 0.5. And when instantiating the prefab spawn, we want to offset the y position here by adding with the factor three, and this is basically going to offset the transform position by one on the y axis, and then we want to multiply this value by the y offset. So Later we can adjust the height depending on our y offsets value. Let's just save this, and let's go back to unity. Now if we see the script, it's updated and have a new field, which is a y offset, and we can change this value according to our needs, depending on the size of the object or on the position of the object. I've test this out and 0.5 seems to be a good value in this case. I'm going to leave this as it is, and let's save our scene. Now if we press play, If I shoot the barrel, you see that our weapon is now on the correct position, and we can pick this up by shooting it, and now we have the machine gun activated. So yeah, that is how we change the weapon pick up model visualization, and with this, we can create as many weapon pick up as possible. 21. 20 Enemy Attack System: In this video, we are going to continue implement the enemy script, and this time we are going to create an ability for the enemy to shoot at the player. In order to do that, let's open the enemy script, and here we need to implement a new struck to hold the value of the enemy shoot interval. Let's go here below and outside of the enemy script class. We are going to create a new public struck, and let's just call this interval. Range. And let's make this serializable by adding an attribute system do serializable. Now let's create a new serialized field, so it's available on the inspector, and this will be a type of float, and let's just call this minimum and maximum. Then we want to create a public constructor for the struck. Let's type public, and then the struck name interval range. And then we open with a sets of parenthese and we need to pass the minimum and the maximum value here. And this is basically not this variable here. It's a argument for the constructor, and let's create an opening bracket. And here we want to set this minimum value by using the keyword this dot mean equal to minimum, and then this max equal to maximum and safe. Now we have the constructor. The last thing that we want to create is a public getter type of float, and let's just call this get value. Here we can use a getter. Since this is going to be only one line, we can use a direct or a Lamda expression. Then just type return random random range, and we can pass the minimum and the maximum. Oh, sorry, we don't need the written keyword here, just type random dot range. And the range will be the minimum and the maximum. This will return this value here whenever we call this properties. Let's save this. Now inside our enemy scripts folder, we are going to create a new serialized field of that struct that we have just created. Let's just type interval range, and let's just call this interval, and we want to set a new default value using the constructor with the default value of probably 1.5 seconds, 2.7 seconds. This would set the default value of our interval variables, but we can change this in the inspector. The next variable that we want to create is a float variable, and this is going to be the shoot accuracy. And let's just set this to 0.5 by default. So the accuracy will be 50% at this rate here. And now let's create a new header to organize the inspector better, and let's just call this shooting properties. And now we have declared the shooting properties. Let's start to create the co routine to handle the shooting. Here below the public void it method. I'm going to create a new core routine, and as with coroutine, we need to return the type of IE numerator. Let's just call this shoot, and we don't need any arguments or parameters in it. Now inside the shoot coroutine, we need to delay our core routine until the player arrive to its position. We can use the yield return and using the new Q word, we will have this wait until. Basically, this wait until method suspend the coroutine execution until the supply delegate evaluates Q true. And basically it asks for a delegates that return a type of boolean. In order to use this, we can just use a Landa expression, and it's quite easy actually using Lamda expression, we need to supply a sets of parenthese, and this would be the signature or the argument. Since it asks for a delegates that return a type of bull without any argument, we can just insert a sets of parenthese and then an equal sign with a aro sign. After the rosign, we need to put a set of brackets to define the condition. Now here we can create the condition for this weight until to evaluate. Basically, we want to check whether the enemy already arrived to its position or not. We can just grab here using the agent remaining distance, and let's just copy this line here, and then paste it here. But instead of checking whether the remaining descent is greater, we can just check if it's smaller. And we can increase the size here to increase the threshold and then add a semicolon at the end as usual. And now you see we still have an error because we need to use the return keyword. So we need to return the condition or the comparison of this statement here, whether it's true or false. And then if it's true, then we are going to execute the code further below here. And if it's false, then it will wait until this statement is true. Now, after the enemy arrive, we want to check if the enemy is not dead. We can just check is that is false. This exclamation mark, heck if this bulion is false. If it's false, then the code inside the bracket will gets executed. And if the enemy is dead or if that is true, then the code will get skipped or will not be executed, and the coroutine will stop. And now here inside the wil blocks, we want to generate a certain random value, random range, and we want to check 0-1, it's smaller than our shoot accuracy, then we want to damage the player. And we already declare how to damage the player inside our game manager by accessing the player hit method. So let's just use that type game manager and grab the instance or the static reference and then run the player hit method, and we can subtract this by one. Also, we can run a debug log here and then add a message that player has been hit. And after we shoot here, we want to delay the coroutine using the interval range value. Let's just type return, new weight for seconds, and it asks for a float value. And this will delay our co routine using the float value that we pass here in seconds. And we can grab our interval variable or object here. By typing the interval name, and we can use the get value property, and the property will return a random value between our minimum and maximum value. So now let's just save this. And the next thing that we need to do, we need to run this coroutine on initialization. So if we check here inside of the init method, we can run the co routine after we set the destination of our agent. And make sure the coroutine run after this line here. Why is that? Because here because here we are waiting for this value to become true. And if we have set a destination, then this will be true right away, and this will get executed right away. So now let's just start the Curtin by passing the Curtin name, shoot and save this. And now if we head back to Unity, we can check on the console. And also we can select the game manager and change the Inspector chew the bug by right clicking, and let's check our current health value. If we press play, and we can wait until the game start, and after the enemy arrived. We can check, there you go. We have been hit. We have been hit right away, and as you can see, our current health is now decreasing as we get hit. But there is an issue here because the shoot cotin runs right away. I found the issue here inside the shoot routine. We need to delay this code a bit. In order to fix this, we can just add a new yield, return new weight for second, and then pass a very small value. In this case, I'm going to pass 0.2 second. Why do we need to delay this? We need to make sure that the engine set destination has been run and it's already been initialized. Otherwise, if the co routine happens on the same frame with this code execution here, and this will return true straightaway. We need to delay that. And once we have a destination, the agent remaining distance will change to a quite large value depending on the position of the enemy to the target position. By delaying this, if we head back to unity, you'll see that if I press play now, Once the game started, we can see the bug log here, and it will tells us if the enemy has been spun and the first one already been spawn and the second one has been spawn, and it will start shooting when it stop standing or arrive to the destination. Now it already shoot the player two times three times and you see that our current health is currently six and decreasing further. So we have the enemy attack working, and later we need to create a visual to give feedback to the player that he or she has been hit. 22. 21 Enemy Attack Visual: In this video, we are going to continue to work on the enemy attack mechanism, and this time we are going to work on the visual aspect of it. So in order to do that, let's go to the models folder and to the Sipi gun light. And under the prefe we have a couple of variant here. I'm going to duplicate the red one, and I'm going to direct this to the pref folder. And now I'm going to rename this to enemy gain. After I've renamed this, I'm going to open this prefect and start to work on the shooting visuals. And with the shooting visuals, we are going to use a particle system. Now let's just create a child ob, an empty child object, and then for the child object, let's just call this shot X. Then let's add a particle system. The first thing that we want to do is we want to expand the emission tab and then make sure that the rate over time value sets 20, and we want to use the burst emission instead of rate over time. Let's just press plus here and then set the count 21. This will only emits one particle at a time. Let's set the duration one here, so we can see every one seconds. Let's move the position of the emitter around this position here to the barrel in front of the barrel position. And we want to make sure that the z position is facing forward. Next thing that we need to do is we need to expand the shape tab here and set the angle 20, and also the radius zero. So we will have a forward particles. Now, following the z axis here. Now let's go to the render tab here, expand this and change the render mode to mesh, and we can use the default mesh from unity, the capsule one. Let's just use this. For the render alignment, let's change this to local. The next thing that we need to do is we need to go to the main tab here and then enable the three d start rotation and set the x value to 90 degrees. Now the bullet aligns perfectly with the gun and also the particle direction. Right now it's too big, so we need to change the start size to a very small value and 0.07 so be a good starting size. And now we have a very nice particle bullet effects. I think I'm going to make this even smaller 20.05 k. And now we need to enable also the trail of this particle here. Let's just scroll down, and then under the trails tab enable this and expand this. Now we have a trail, but the size is about the same of our capsule diameter, so we cannot see the capsule anymore because it's overlap with each other. So let's just change the size by modifying the width over trail here. I'm going to set this two curve by clicking the drop down on the right side, and with the curve here, we can modify the n trail size to a very small one. Now you see that we have a very n and we can also decrease the start size a bit. As you can see, we have a very nice trail shape here. And now we need to create a material for this particle. Let's just go to the material folders, and I'm going to create a new material, and this will be the enemy bullet. And the second one would be the trail. Let's just create a new material again and then call this enemy bullet trail. For the enemy bullet, I'm going to change the material to particles standard let, and I'm going to enable emission. For the LBD, I'm going to change this to a color of red. For the emission, I'm going to set this to an orange color and set the intensities to 0.5. With the particle shot effects, game object selected, let's just direct the enemy bullet to the material over here. And I should change the bullet material, as you can see. For the trail, we are going to set up this as a t material and set this color to the bullet orange color. We can just use the color picker here and then pick the orange color over here. Let's set this enemy bullet trail as the trail material. If we go below in the particle system component here, we can direct the enemy bullet trail to the trail material, and now we have this. Okay. Now we need to set the start speed to a higher value, probably ten, so it's faster, and we want to also disable the looping and also deplay on a wake checkbox here. So it should play only once, and we are going to trigger this particle de script. So let's go back to the scene here and let's open the enemy prefects. Now let's expand the bone root here and further to the shoulder, the upper arm forearm and the wrist. Once we've seen the right wrist join here, let's just drat the enemy gun as the child of the right wrist join. And let's just reset the transform of the enemy gun here. And let's rotate this, it's aligned with the hand bones here. Let's just rotate this. By holding control, we can snap the rotation every five degree. I'm going to rotate also on the z axis here. Now we can move this, but since the progrid is enabled, let's just disable this first, so we can move this more accurate. And if we want to check if the gun is aligned correctly, while the post is aiming, let's just select the Robot Kyle game object. Go through the animation window here. And if you don't see the animation window, let's just go through the window. Under animation, just open the animation panel here. I'm going to this, this, and then lock the animation panel window here. Whenever we select other game object, the robot will stay in the aiming post. Now let's just adjust the rotation of the weapon here. And then let's just rotate the z axis also a bit and move this slightly upward and rotate this on the x axis here. Okay. So yeah, this should be enough, and now let's go back to the scene here. Now we are going to work on the enemy script. So let's go to the project tab here and then open the enemy script. And now we have the enemy script open. We need to create a new suized field. And this will be a type of particle system. And let's just call this shot effects. This will be the reference to the particle system of the enemy gun. Save this. And here below inside the shoot coroutine, we want to adjust the shot effects direction according to the hit status or not. So here we want to set the shot effects that transform the transform the rotation, and we are going to pass the quaternion look rotation based on the enemy transform forward, and then we are going to add a random value using the inside unit sphere. This will add deviation. Here inside the I statement, we want to override the rotation again. And this time, we need to make sure that the particle direction hits the camera. Let's just use the quaternion look rotation again. This time we are going to grab the player reference, and since we've already done that, so we can just type player, grab its position and subtract this with the shot effects, transform that position. And this way, the forward of our particle will line perfectly to the camera position, and it will give an illusion that the bullet is hitting the player. Save this. And outside the if statement, we want to access the shot ex particle system again and then execute the play method. And this will trigger the particle once and save this. Let's go back to unity here, and let's go to the prefe holder and open the enemy prefs. And here, under the enemy script, we should have a new shot effX field, and let's just open the enemy gun, expand the enemy gun here, and then drag the shot game object as the particle system of this shot effects. So let's go back to our scene here, and then let's test this out. Press play, and see if the enemy now have a visual representation of the attack. There you go. We have a fisial representation of our attack, but we need to modify the particle. Let's just do that. Now let's go to the project tab. Under prefs. Let's open the enemy prefs. Here, select the Robot Kyle and we want to play the aiming idol. And let's just lock the animation window again. And here under the shot effects, we want to select this shot effects, and we want to shorten the lifetime of our trail. Here, let's scroll down under the trail tab, open it. For the lifetime, let's just set this 20.1, or even shorter 0.08. The other thing that we need to change here under the main panel or the main tab here, for the simulation space, we need to set this two world. And let's just apply the enemy gun game o, press apply all, so the settings get safe to the prefeb. Now if we press play, the particle is much shorter the trail. And if we are currently moving around, the particle will stay on the world space. Doesn't get rotate with the parent game object. Now let's just head back to the scene here and test this again. Press play. And you can wait until the enemy arrive. And now you can see it shoots and it hits us. Currently. If we expanded debug, you see that our health is very low now. So, there you go with the enemy attack visualization. 23. 22 Player Damage FX: In this video, we are going to create an effect when the player are being shot by the enemy. So in order to do that, first, we need to import a new asset, and this asset is a Keno glitch created by K Jio Takahashi. It's an image effect, and I'll put the link in the description. So in order to don't note this, we can go to commit here and then select the Keno glitch unity package. Once we on the Kino Glitch Unity package page, just download the file here, and it will download the package. I've already downloaded. And now let's import that package. Back in Unity, let's go to the assets menu import package, click custom package, and I'm going to import the Kino glitch Unity package, and then press import. Now, after importing the kino glitch, let's go to the main camera here, and then add the digital glitch component. Now we are going to work on the player script. Let's go to the scripts folder and then open the player script. Here I have the player script open, and first, we want to create a camera shake effect. So in order to do that, I'm going to create a new cotin here below. And I'm going to call this do camera shake. I'm going to add a couple of arguments. The first one would be a type of float, and this will be a timer. The second one would be also a float, and this would be the amplitude, and the third one also a float, but this would be the frequency. Inside the c routine, we want to create a new vector t to store the initial position of our camera. So let's just type in it pause, and then let's grab the transform that position, and we want to also create a new vector t variable, and this will be the new position. But for starting, we are going to also use the transform that position. And below here, we want to create a new float called duration, and we want to pass the timer as the value of our duration variable. Below here, I'm going to delay the code here by a very small value, a 0.2 second. And then I'm going to create the loop here. So we are going to use the wild statement and then pass the duration value if greater than zero. So while the duration is greater than zero, we want to run the shake method here. And here, first, I'm going to subtract the duration by the time the Delta time value. And then I'm going to execute the yield return No, to look this while statement. And with substriting the duration with a time that Delta time, we are making the duration as a timer. So now, the first thing that we want to do, we want to check the distance between the new position factor with the current position. If The distance is very small, or the camera position is very near to the new position, then we want to calculate a new random position. So I'm going to set the new position to the init position again. But this time I'm going to modify the x position by adding a random range from negative one to positive one, and I'm going to multiply this by the amplitude. And for the y position, we are going to do the same. I'm going to paste this code here and then change the component to the y value and then use the same random range multiplied by the amplitude value. So basically, we want to check if the camera is a or almost arrive to the new position, then we want to set a new random position on the x and the y axis. And then we want to set the position of our camera to the new position. But we are going to use a factor three dot b to interpolate our previous position, which is our current position to the new position. And for the interpolation value, we are going to use the frequency argument that we are passing on the coroutine, and then we're going to multiply this with time dot delta T. So the frequency will be relative to time, not to frame per second. And after this wild statement, we want to set the transform that position back to the innate position. And now we need a public method to execute this core routine. So let's just create a new public void shake camera. And we need the same argument as our co routine. So let's just copy all of the argument here and then paste it inside the shake camera method. Inside the shake camera method, we want to start the co routine and then pass the co routine name, then we pass the argument, the timer, amplitude, and then the frequency. Okay. So now let's go to the game manager, and whenever the player hit, we need to run this shake camera method. So now we need a reference to the player script from our game manager. So let's just create a new serialize field and then type player script. And then let's just call this player script. And here, we can just run the player script method called shake camera that we have just created, and then pass the time, the amplitude, and the frequency value. For the timer, I'm going to set this two half second, and for the amplitude, I'm going to set this 20.2, units, and for the frequency, I'm going to set this 25. You may change this value to adjust the shake to your liking, but this is going to be my value here. And now let's go back to unity. First, in the game manager, we need to assign the player script reference. So let's just drag the main camera to this player script slot here on the game manager, and then sake the scene, and then press play. So after the game runs, I'm going to wait until the enemy shows and then wait for us to get shot by the enemy. There you go. We have a shake effect. And now let's open the enemy's script, and let's fix the shot F X direction when the enemy miss shooting us. So here inside the while is not that statement. We have this line here. And what we want to do is we want to multiply this random inside unit sphere with a very small value. So we have a very small deviation. Otherwise, we will have a deviation maximum of one unit, which is quite a lot if you see. So let's just multiply this by 0.1. Okay. And the next thing that we want to do is, we want to implement the digital glitch effect that we've just import in the beginning of the video. So in order to do that, go to the player script, and then on top of the player script, we are going to use the Keno name space. And then here, let's just create a new private digital glitch, and then let's just call this glitch ex. On start, we want to initialize this glitch eff. Let's just use the get component and pass the type digital glitch. And now we can use this inside our camera shake coal routine. Here inside the while duration, we can just access the glitch effect objects and then modify the intensity. But before we modify the intensity here, we need to create a curve for modifying the intensity of our glitch effects. Let's just create a new s field, and this will be a type of animation curve. And let's just call this glitch curve. And basically, with this curve, we can set a value in a curve manner. Then we can grab those value from our curve evaluated by the time or the duration of the shape. So here inside the coroutine, let's just grab the glitch curve and then run the evaluate method and then pass the time here. For the time, I'm going to use the duration, but I'm going to normalize the duration, so I'm going to divide this by the timer value. The timer is constant in this case, and the duration that we are modifying is the duration variable. Let's save this, and let's head back to unity. Now we're back in the unity. We need to set the glitch curve to a something like this, so it will start zero, and then over time, the glitch will raise up to one and then decrease again 20. And we can test this out, run the scene, and let's see the glitch effect. There you go. We have the glitch effect working, and if it's too strong, we can always adjust the curve to push down the middle position to some value that less than one, probably 0.7 here, and let's just adjust the basi tangent here. So it line, and let's test this again. Now you will see that whenever we are being shot by the enemy, the digital glitch intensity raise to 0.7. There you go. Now it's working, but we need to make sure that the digital glitch intensity B zero whenever we finish shaking the camera. So let's go back to the visual studio, the player script here. We want to set the glitch effects intensity here, zero. So that will be all for creating the damage effect for our player. 24. 23 Hostage Setup: In this video, we are going to create a hostage or civilian aspect of the game. So we want to create a new script to handle the hostage movement, and we want to also make sure that if we shoot the hostage or civilian, our lives get substrate. And the first thing that we need to do is we need to open the animations folder, and we need to import the animations file. And I've already prepared the FBX for this, and I also include the needed files in the video lessons. So let's just direct the hostage hands in the air FBX to the animations folder. And then let's go to the Models folder, Robot Kyle texture, and I'm going to import the robot color hostage. So let's just direct this. And now let's start implementing the hostage. Now let's go to the prefs folder, and then for the enemy, select the enemy, and then press Control D to duplicate, and let's just rename this hostage or civilian. And now let's open this Pref and let's modify this. So we won't be needing the gun. We can just remove the enemy gun. And then we want to create a new materials for the hostage. So let's go to the models folder under the Robot kyle folder. There is a materials folder. Let's just duplicate the robot color, and let's just call this robot color hostage. And let's change the base color or the albedo, to the robot hostage one. It's the green one. Let's just select this one, and it will create a new material. And then let's drag this color hostage to the robot model. Now we will have a robot with different color. So it's clear that this is the hostage. The next thing we need to do, we need to prepare the hostage script. Let's go to the script folder, and then let's create a new C sharp script, and let's just call this hostage script. Before we modify the script, let's go to the animations folder, and in the controller folder. I'm going to duplicate the base enemy controller, and let's just call this hostage Controller. And now we want to modify this. So let's just double click on the hostage Controller. And now we need to create a new layer, and let's just call this upper body layer. We want to also create a avatar mask. Let's just right click on the project, create, and then go to the avatar mask, and let's just call this upper body mask. Now with the upper body mask selected, expand the humanoid here, and we want to disable the ground, the leg, the leg and the body. We want to leave the hand at the IK and the head enabled. Now with the upper body mass, we can go to the cockweel of the layer settings here. We want to set the width to one and then choose the layer mass as the mass of our upper body layer here. Let's just press the circle here and then choose upper body mask. And now the next thing that we need to do is we need to set the hostage hands in the air FBX files. Rick type Q humanoid. So let's just set the animation type che humanoid, and then press a pie. And now, if we already set this humanoid, and then we unselect this and then reselect it, go to the animation tab. You'll see that we have this here. And the animations is only 50 frames long. So we need to change the n value to 50, and let's just call the clips or rename the clips to hostage. And we want to also make sure that the loop time is enabled. So now we press apply. After we prepared the hostage hands in the air, we want to create a new et state, and then for the state, let's just call this hostage pose. And let's expand the hostage hands in the air and direct the hostage clip to this motion slot on the hostage post state. Okay. Once we've set this up, we want to go back to our scene here under the prefs mode, select the root kyle, and then change the controller to the hostage controller one. So now we've set up the robot, let's start do the script. Now let's create the hostage script. So we already created the file. Let's open this in visual studio, and we want to make sure that the hostage script derived or inherited from the enemy script. Let's just rename the mono behavior here to enemy script. And now if we save this, Then we delete the void start and the update method. If we go back to unity here, you'll see that if I go to the prefax folder and the hostage pref, open it, I can delete the enemy script, and then I can add the hostage script. And the hostage script will have the same properties as the enemy because this hostage script inherits from the enemy. Later we are going to hide some of the options that we are not going to use for the hostage script. But now we need to modify a couple of things on the enemy script. Let's just open the enemy script here and modify those things. Top here, we want to make sure that the NMS agent, the scope access modifier are set to protected. So let's just type protected. This way we can use this agent on the child script. Otherwise, if it's private, then the agent won't be available on the child script or a child class. And here, in the enemy script, We want to exclude the start cotin shot from the hostage script. We don't want to execute this cotin in the hostage script. In order to do that, we need to create a new protected method, and this should be a virtual method and then void, let's just call this behavior set up. With this behavior set up, we want to cut this line here and then paste it here. Now we can call this method inside this if the agent is not now statement. Let's just call this behavior set up. The other thing that we need to do is here, under the hit, we want to change this for the hostage script. In order to do that, we need to extract this also out into a virtual method. Let's just type another protected virtual void, and let's just call this that behavior. And then here, we want to cut this and then paste it here. And then we want to run this method inside this if statement here. So let's just type that behavior. And now the next thing that we want to do is in the hostage script, we can overwrite those two methods that we've created. So in order to do that, let's just type overwrite. And then we can choose the method that we want to overwrite. We have created the behavior setup and the dead behavior. So let's just create the behavior setup first. And I want to remove the base behavior setup calls. And let's just overwrite this by typing agent set destination. And this would be the target position. And as you can see here, we don't have the target position because the target position is set to a private field. So in order to fix this, let's go back to the enemy script. And for the target position transform this one, I'm going to add a protected keyword. This way, the target post will still be serialized on the inspector, but the child class has access to it. So now we can just type target position position and safeties. This way, when the init method are called inside the hostage crit, The behavior setup that gets executed will be different than this one. And it's going to be this behavior setup. So we don't have to start co routine shooting method. This way, the enemy won't shoot at the player. Now the next thing that we need to do is we need to also override the other method that we've created, which is the dead behavior, and here we want to remove the base calls Instead of adding the enemy keel, like this one here, we want to substract the player health. So let's just type game manager, the instance, and then let's just call player it. And right now we can substract this by one, but probably we need to substract with a bigger value. So it's more punishing when we kill a hostage or civilian. Okay, let's just save this. And now let's head back to unity. And for the hostage here, I'm going to set the Mx held 21. So we only need to take one shot to kill the hostage. And now here, let's create a new shoot out area on the second shoot out point. We want to add the hostage here to test this out. So let's just drag the hostage to be the child of the shoot out 0.2 here, and let's position this. I think we can position the hostage in this area here. And rotate by 90 degree. And we need to create an empty object for the target position. Let's just do that, create a new empty game object. Let's just call this target position one. Let's put this around this position here. Okay. Now if we select the hostage, let's put the target position to the target pos slot here. Let's just drag this and then set this as the target position. Now, save this. Let's test this out. Now, let's kill this enemy here. There you go. Let's see if the hostage is coming out. Okay, there is an error here. The error was apparently, I forgot to put the hostage game object here to the enemy slot over here. So right now we are going to direct the hostage here to the enemy slot. And since the hostage script is the child class of the enemy script, that is why we are able to direct the hostage game object to the enemy slot and the hostage script gets registered by this enemy slot. And we need to make another slot for the enemy, and we need to duplicate the enemy. Let's just duplicate this enemy here and then make this the child of the second shootout point, and let's put this enemy here and rotate this 90 degrees on the y axis. Let's create a new target position by duplicating this one and probably put it here. And by selecting the enemy here, we want to set the second target position as the target position. Let's just rename this, select the enemy and drag this target position to the target position slot of the enemy script here. And now if we select the shoot at point, let's just drag the enemy game object to the second enemy slot over here. And save this and let's test this out. Right now, there will be an issue where we need to kill both the hostage and the enemies to pass the shoot out point area. And we are going to fix that. I'm going to kill this. And now here you see that when the enemy came. After we kill the first enemy, it won't progress because we need to kill the hostage and the shootout point register the hostage as the enemy. Now after we shoot, then we can continue. We need to fix this. So let's go back to the scripts folder and open the shootout point script. And here, Okay. Inside the enemy kilt method, instead comparing the enemy kilt value to the length of the enemy list, we need to create a new integer to account for the total enemy in that shoot out area. So let's just call this total enemy and create a new variable. And now when we are sending the enemy, let's add the total enemy variable depending of the enemy class over here. We can just use a ternary operator, and here we need to check if the enemy object and the enemy entry from the enemy object, which is an enemy script, d is not a hostage script. Now we have this exclamation mark, and this will check if this statement is negative, then we want to add the total enemy. Total enemy add by one else, we want you to add the total enemy by zero. This way, if the enemy is a hostage script, then the total enemy won't get add by one. And let's go below here, and now let's just compare the enemy killed with the total enemy variable. And now after modifying this, let's just add a debug log to see if this that is executed or not. So let's just print the game object name at A, string, clear, and save this. Let's go back to unity and test this out. So press play, and I'm going to open the console area here. So let's just shoot the enemy. And shoot out 0.1 is clear, and let's just kill the second enemy. There you go. The shoot out 0.2 is clear. So that is how we implement the hostage using inheritance, and we can behavior by overriding the method. 25. 24 Area Timer Setup: Hi. In this lesson, we are going to create an area timer for each shootout point. On each area, we are going to start a timer, and if the timer is finished, then we are going to proceed to the next area. And this will create a possibilities that the player cannot kill all of the enemies, so we can create a scoring system later based on that. Now in order to do that, first, we want to open Pis Studio, and then we want to modify the shoot out entry class. Let's just go below and the player move script here. We have a custom class for the shootout entry object. And here we want to create a new field type of float, and let's just call this area timer. And we want to also set the default value for the area timer. And I'm going to set this two 15 seconds. And inside the shootout point script, we want to add a new method for overriding the area clear. Let's just create a new public method called area Clear. Inside this method, we want to check first, we cannot use the area clear name because it's already been used by this property here. So let's just call this set area clear. And we want to check if the area clear bulion is true, then we want to return this and don't run the method further. And if the area is not clear yet, then we want to clear the area and we want to resume the player movement. Let's just access the player move objects or variable here, and let's just set player movement to true. And now, whenever the area is clear, we want to stop the enemy from shooting. So in order to do that, we need to add a new public method inside the enemy script. I'm going to open the enemy script here. Inside of this class here, I'm going to create a new public method, and I'm going to call this stop shooting. F stop shooting, we can just stop all of the cotins inside this mono behavior. Since we only have one coroutine inside the script here, we can just run this method from mono behavior, and it will stop all of the proteins inside this class. Okay, let's go back to shoot out point here, and we want to look through the enemy here. And for the able, let's just call this enemy. And for our enemy collection, it's called enemy list. Let's just type enemy list. For each of the enemy, we want to access the enemy sub object. And this enemy sub object is a type of enemy script, so we can access the stop shooting method right away. Hi, this is Rome from the future. And in this script, the shootout point, there is a bug that has been pointed by Matt Hills. Thank you so much for spotting this issue, and we need to check whether the enemy is destroyed or not. Because if we finish an area, when the timer goes to zero, but we haven't killed all of the enemy and we kill some of the enemy, that enemy will probably already gets destroyed, and this will throw an error. So in order to do that, we need to check if the enemy and this is basically the enemy entry, and each of the enemy entry will have the enemy script object in it, so we need to check that object. And we want to check if the enemy script that belongs to this enemy entry is nal, then we want to continue to the next iterations of this for each loop, so we can just type continue, and this will skip this code here. So for that enemy entry, if the enemy script object is already renewal or it has been destroyed, then we want to skip this code, and it will go to the next enemy in the list. So with this small code, we are going to prevent that bug from happening. Now we have this method declared. We want to modify the start shoot out method. And the first thing that we want to add is, we want to pass a float, and let's just call this timer. And inside this method, we want to use the delayed action extension that we've created. And with this delayed action, we want to run the set area cleared with the delay of our timer here that we pass on the method. Now if we save this, Let's go back to the player move, script here, and you'll see that we have an error because now the start shoot out a for a float argument. Let's just pass the float argument by accessing the shoot out entries index of I, and we want to pass the area timer. Now, basically, when this gets executed here, the shoot out point will initialize the needed value or variables, and then we'll delay the set area cleared method with the time as the delayed interval. Now, let's head back to unity, and let's test this out. So I I Select the main camera here. You'll see that now we have the area timer of 15 seconds. Let's make this a very small value. For example, 5 seconds. Now let's test this out, press play, and let's see when we arrive to the shoot out area. You see after certain seconds, it will start moving. There you go. It starts move. It means that the timer is already finished and it starts move to the next position. We are going to add a UI later. But now the next thing that we need to do is we need to create a new timer object to count the timer for the UI later. I'm going to create a new C sharp script, and let's just call this object. And I'm going to open this script inside Visual Studio, and I'm going to remove the mono behavior. So this will be a custom class. Inside this time object class, we want to create a new private co routine object, and let's just call this, and we want to create a new public method called starter. And since we are going to use a co routine here, we need to pass a mono behavior to this method. Let's just type a mono behavior as the first argument, and I'm going to call this B. And for the second argument, I'm going to pass the duration. And basically, we want to skip if the timer object is not null here or if we already start a, then this time object values should not be null. So let's just check if the time is, then we want to return this method here. I'm going to add a debug log here, so we can see if something happens. Let's just type debug log, and let's just tie timer already runs. We need to create the timer coroutine. Let's just type I enumerator for the written type, and let's just call this timer runs. We want to pass the duration here to the cotin Inside the coroutine, we want to create a wild loop with a condition if the duration is greater than zero. Then we want to start counting the timer. Here we can subtract the duration with a value of one, and then we can add a yield return. But instead of using Nu, which is going to return every frame. So the while loops is going to be executed every frame. I'm going to delay the loop for every second. I'm going to use new weight 4 seconds and set the value to one. This will work exactly like a timer. Every 1 second, we are going to substract the duration by one. If the duration is zero, then we want to break out of this wire loop and execute any code below here. When the timer runs out, we want to set the timer cotin back to null. And now we have this timer object. I'm going to expose a public integer, and I'm going to call this display timer, so we can see the timer on the inspector, and I'm going to pass the duration value to this display timer. So let's just set the display timer value to the duration that is currently running in the current loop. So it's a float, and this is an integer, so we need to cast this to an integer. I'm going to add a casting in front of the duration value. So it doesn't throw the error anymore. Let's save this. The next thing that we want to do is we want to add this timer object to the game manager. You may ask that why we create another script for the timer object. This is to comply with the single responsibility pattern. So I'm going to try to make every script to serve only a single responsibility purpose. So it's easier for us to debug later. When there is an error, we can isolate an error in a single script. Instead of putting the timer inside the game manager also with all of the co routines and the method. And this is very easy to use here. Since this is not a monel behavior, we can just create a new private field and with a type of time object. And let's just call this time object here. I'm sorry. And I'm going to initialize this. And save this. And now we can use all of the method inside the timer object. So here inside the game manager, we want to create a new public method to start the timer. So here below, I'm going to create a new public void, and I'm going to call this start timer, and we are going to ask for the duration of the timer as an argument. And now to start the timer, we can just access our time object, and then we can run the start timer method, and then pass the mono behavior. And since the game manager is a mono behavior, we can just pass this class here, and then pass the duration. Another thing that we need to create is, we need to create a method to stop the timer. So let's go to the timer object here, and I'm going to create a new public void or a public method, and I'm going to call this stop timer. And for the stop timer, we are going to ask for a mono behavior as the argument. And here we want to check if the timer is currently null or if there are no time currently running, then we want to return this method. Or we can just add a debug dot log here, and let's just say that there are no currently running. And I want to return this method. But if the timer is not null, then we want to stop the cotin using the mono behavior that we pass here and then run the stop cotin method. And for the crotin, we can just pass this ter cotin object here. Let's just set the cotin argument for the stop protein method. And then after stopping the cotin, we want to set the timer back to null. We have created the stop timer method. Let's go back to the game manager, and then we want to create a new public void stop timer. And here, we can just access the timer object, run the stop Ter method and then pass the mono behavior with this keyword. Okay, now we've created the start timer and the stop timer, we want to trigger this from the shoot out point. Whenever we run the start shoot out method for the shoot out point here, we want to also start the timer inside our game manager. Let's just access the game manager instance and then run the start timer. And this as for the duration, so we can just pass the time as the duration. And then here, we want to stop the timer if all of the enemy is already been killed. So here, let's just access the game manager instance and then run the stop timer method and save this. For the set area cleared, we don't need to stop the time because by the time the area is cleared, this means that the time is up, so the timer will stop by itself and save this. Now let's head back to unity. And I'm going to modify the timer again and make this probably to 10 seconds and save the scene. And if we select the game manager, we cannot see the timer object because we haven't set the class as a serializable class. So let's go back to the fisal studio and inside the ter object. I'm going to add a serializable attribute. So Type system serzable. Save this. Another thing that we need to do is, I forgot, since the timer object is private, we cannot see it. But if we want to see it, we can add a sized field attribute or we can just enable the develop view of our inspector. Then here we can see our timer object and we can see the display timeer field. Now let's save the scene here and let's play this. Now, if we arrive to the shoot area, you see that the display timer real start. Okay. There is something that I forgot you did, and that's why the display timer is not working. So let's go back to Fiscal studio here. And inside of our Tier object, we forgot to run the co routine inside the start timer method. So now we need to run the coroutine if the coroutine is. So let's just t equal to start co routine, and we want to run the runs co routine, and then pass the duration as the argument. Before this enumerator time runs, never gets executed because we forget to run this. So now I'm going to save the script here, and let's go back to Unity. Now, after the script is compiled, let's just run and see this value here. Take notice of the display timer value. Once we arrive to the area, it start counting nine, eight, seven, and when this value becomes zero, then it will continue to move one, zero. There you go. And on the next area, it will start to count the area. It will start to count the timer again. This is how we create a timer with a separate object, so it will handle all the time code. In the next video, we are going to start creating the UI for our game here. 26. 25 Game Play Statistic: In this video, before we continue to create the UI, we want to create the game stats first. So we want to record how many shots we have been fired and how many enemy that we've been killed and how many enemy are there in totals in the scene. So let's just start to that. Let's go to the visual studio here, and inside the game manager, we already create two integer variable for the enemy hit and the shots fired. This is basically for calculating the accuracy later, but we want to also add the enemy killed counter and the total enemy. Counter, and also hostage killed counter. So now we need to create a method to add this value here. So let's just create a new public method below here. The first one that we want to create is we want to create a register enemy method. And this is for registering an enemy, and to register, we only need to add the total enemy by one, and this will be called by the enemy script on start. The next method that we want to do is also a public method and called hostage kill. For this one, we want to add the hostage killed value. The next thing that we want to create is we want to create an enemy killed method. Et's just create a new public method and call this enemy killed. Let's just add the enemy killed variable by one. Now we've created this three new method. Let's go to the enemy script here, and upon initialization, on the behavior setup, we want to add the gay manager instance register enemy. Whenever the enemy is initialized, we want to register an enemy here. Below here, whenever the enemy gets killed. And I think Yeah, here, we want to register the kill. So let's just run the game manager instance dot enemy killed. Oh, sorry, instead of adding this here, we can just add this inside the death behavior. So let's just do that. And this will add the enemy killed counter. And for the hostage script, we want to add the game manager instance do hostage killed whenever the death behavior on the hostage script gets executed. Let's save this. Now let's head back to unity. With the inspector set to debug, we will be able to see those private variables that we have created. Now let's test this out. I think I need to increase the timer, so I'm going to go to the main camera here. First thing, I'm going to set the area timer to 30 seconds. So we have time to kill all of the enemy and save this. Now let's press play and test this out. Let's select the game manager and we will see the stats here. So now let's kill this enemy here. And we've killed two enemy. Now let's try to kill the hostage first to see and let's kill this enemy. I need to reload. There you go. Now you see that I've fired shots 15 times and I've hit the enemy 13 times, and also we have killed three enemies out of three total enemy in the scene, and we also killed the hostage. Later we are going to use this value to calculate the scores at the end of the gameplay. 27. 26 UI Health Bar: Hi, in this video, we are going to start working on the UI. And in this chapter, let's create the Health UI for the player. So in order to create the Health UI, I've already prepared a package. So let's just import that package. I'm going to go to the assets menu, import package, and choose custom package. And then here I have the UI Pa package. Once it's opened, the import package window, let's just import all. And I'm going to drag the UPAC inside our underscore game folder. Now, if you open the UiPaC, we will have a prefabs folder and inside this prefabs folder. I've already prepared a player HUD object, and we can drag this to the main camera. I'm going to drag this to be the child of the main camera. And now let's adjust the parameter. As you can see here, we have a help bar. We also have the MO counter and also the reload notification. The way the prefs set up is already facing the correct way relative to the camera. If you can see here, if we go to the game view, you see we have the UI following the camera because it's parented to the camera, and it is slightly rotated on the y axis. So now we are good to go. I'm going to also import a custom fund and for this step, you can just pick your own pond and replace the fund in the text after that step. Inside the underscore game folder, I'm going to create a new subfolder, and I'm going to call this funds, and I've already prepared a fun here. I'm going just to drag this fund that I'm going to use. And now once we have imported the fund here, I'm going to right click on the phone and then choose to create menu, and under the text Mash menu, I'm going to click the fond asset. So it will generate the fond asset for the text Mash pro. So now that we have generated the fond asset, we can just select the child object that has the text mesh pro components attached to it. And here we can pick the phone that we've generated. So now we have a better looking phone. And for the real text, I'm going to also change phone text here. There you go. And now we can start working on the script for the UI Manager. So let's go to the scripts folder, and I'm going to create a new C sharp script, and I'm going to call this UI Manager. And let's open this UI Manager. So now that we have opened the UI Manager script, I'm going to delete the start and the update method. I'm going to also delete the mono behavior inheritance here. And I'm going to add a system serializable attribute. And I'm going to use this UI manager class just like the time or object class that we've previously created. So let's go to the gay manager, and I'm going to move the game manager to be beside of our UI manager script, so it's easier to switch. And here we can declare the UI Manager as a field or object inside the game manager script. So here I'm going to add a serialized field. For the type, I'm going to use the UI manager class here, and I'm going to call this UI manager. Now that we've created this back to our UI manager class, we want to import the Tex Mash pro library first. I'm going to type using tex TM pro class, and then I'm going to also be using the Unity engine UI. Here, inside the UI manager class, we want to create a new serialized field, and this would be a type of slider, and this is for our health bar. I'm going to call this health bar. Then we want to create a public method for updating the health bar. But before we create that method, we want to create a new public void init method, and this is for initialization. And for initializing, we want to pass the maximum health that we have for this player. Let's just type float, and let's just call this float Mx health as the argument for the init method. And then here for the health Bar, we want to assign its x value to the Mx health that we've just passed through this method, and we want to also set the health Bar value to the Mx health Argument here. The next thing that we want to create is we want to create a new public method for updating the health. Let's just call this up date health. And then we can just pass a float, and let's just call this float value. And now whenever we call this method, we want to update the value of our health bar. Let's just type health bar, value, equal the value that we've passed here and save this. Now if we go to the gain manager, we want to initialize the UI manager. Let's just equal the new UI manager. Instance and save des, and here below. Inside the player health method, we want to update the current health to the health bar value here. Let's just type here below the current health substract by the damage. Type UI manager, update health, and then pass the current health value. And this will update the health bar value and save this. And now let's head back to Unity. Now if we select the game manager here, you see that we have a new field called UI Manager, and we can expand this, and we can see the field inside the UI manager class. Now we want to drag the health bar to the slot here. So just select the parent health bar under the player HUD here, and I've already prepared the slider component here and set its value ten, and you'll see that if we slide this value here, our health bar gets decreased. So let's just select the game manager again and then drag the Health Bar game object and save this. One thing that I forgot is we need to run this initialized method. So let's go to the game manager. Inside its innate method, we want to make sure that we are initializing the UI Manager. Let's just call the init method of the UI manager object and then pass the current health that we are initializing before. And save this. Now, let's go back to Unity, and now let's test this out. I'm going to press play and see if sorry, we need to hide the read text first, so I'm going to hide this. And now let's see that if the health bar gets updated whenever we get shot by the enemy. There you go. This is how we create the health bar. Feel free to explore the prefect that I've created and how I've lay out the UI here. Also for this reload, it has a animator component. Basically, it's just animating its Alpha value. Here, as you can see, it animates the Alpha value of the four te color of the text here. In the next video, we are going to continue working on the weapon information of our HUD. 28. 27 UI Weapon HUD: In this video, we are going to continue work on our UI system. And this time we are we want to change the weapon icon if we pick up a new weapon, and we want to also update the MO counter here and also enable the reload notification when the MO runs out. Now in order to do that, let's go to is Sudio, and we need to access to the weapon that first, and also the players. Inside the player script, we want to create a new public static event. So let's just create a new public static, and for the event, I'm going to set this to a system not action. And I'm going to pass a object for our event here. For the signature, I'm going to add the weapon data, and I'm going to call this event on weapon change. And I'm going to fill this event with an empty delegate. So we don't have to check for any subscriber whenever we want to invoke this event. Save this. And I purposely make this static. So it's easier to access this from any other script without having a reference to the player script. Okay. The next thing that we need to do is, we need to go to inside the switch weapon method. And here, after we set up the new weapon, we want to broadcast this event. Let's just invoke the weapon change event, and let's just pass the carbon weapon data. Because current weapon data, it's a weapon data, so we can pass this to our own weapon change event, and this event will broadcast this data, and the one that are subscribing to this event will receive a new weapon data. Now the next thing that we want to do is we want to go to the weapon data, and inside the weapon data class, we want to create a new public event, and this one won't be a static event. It's just going to be a public event, so we can just type system dot action. And we want to pass the MO as the signature or the object that we are broadcasting via this event. So let's just add integer as its signature. And then we can just call this on weapon fire, and we can just set up an anti delegate just like we did in the player script, safety and or maybe we can just call this on weapon fire. And we want to broadcast the on weapon fired event here inside the weapon update here and whenever we are pressing the mouse button here. So now let's just invoke the on weapon fired event here and then pass the car on MO. And for the machine gun here, we want to also invoke the event here. Now let's just save this. And we want to also add the weapon icon. Let's just go top here in our field declaration. And I'm going to add a new serialized field, and this will be a type of sprite. And let's just call this weapon icon. I'm going to expose this serialized field using a property. Below here, I'm going to create a new public property type of sprite. And then I'm going to call this GT icon. And then for the GT accessor, I'm going to return the weapon icon. Here. Okay. Now we can save this, and let's go to UI Manager. So now inside the UI Manager, we want to declare a couple of variable, and I'm going to add header attribute, and I'm going to pass a string for this header attribute. And I'm going to call this weapon HUD, and below here, I'm going to create a new image for the weapon icon. Then for the other fields that we need to create is a text Mash pro. Let's just search for the text Mash pro object, UGI, make sure the UGI one, and let's just call this MO tax. And the other thing that we need to create is a game object for the reload warning. Let's just call this reload warning. And here inside the in method, we want to subscribe to an event on the players script, the static event that we've declared. So let's just access the players script, and then let's just access the on weapon change event. We want to subscribe this method that we have here inside the UI Manager. So we need to create the method first. I'm going just to subscribe to a method. And I'm going to make iso Studio to generate this automatically. There you go. We have this at weapon and it already passed the weapon data here. So I'm going to remove the Trow new not implemented exception. And here we want to also create a new private variable to hold our weapon data. Let's just type private weapon data, and let's just call this current weapon. Here inside the update weapon method. We want to check if the current weapon is not null. Then if it's not null, we want to remove the on weapon fire event two a method called update MO, and we haven't created that yet, so let's just create a new void, called update MO, and let's just pass an integer for the MO. And here we want to update the MO text. Using the set text method from the text mesh pro and pass the O that we passed as an argument here in the method and convert this two a string, and I'm going to format this string two a two digit value here using the string argument of this two string method. Now here, if the current weapon is not null, we want to unsubscribe the weapon fired event from this method here. Let's just type negative equal up date MO, and this will unsubscribe because we are changing the weapon data to a new weapon that we passed by this event here. So now we want to update the Caron weapon to the new weapon object that we've passed in this argument here. And then we want to subscribe to this new weapon data event to our update MO method. And below here, we want to also update the weapon icon sprite by accessing the sprite properties and then pass the Caron weapon, get C sprite properties, and save this. Now that we have an event subscription, we need to also remove this whenever this UI manager gets deactivated. So I'm going to create a new public method and just call this remove event. And then I'm going to copy this line here, paste it here. But instead of using the positive sign, I'm going to change this to negative sign to unsubscribe this method to this event here. Let's save this and inside the gay manager, we want to create a new void on disable method. This is a built in method from unity. Basically, it will gets executed whenever this script gets disabled, whether we stop the editor or if the gay manager gets destroyed, this will also invoke. Inside the undisable method, we want to access the UI manager, and then we want to access the remove event method. Another thing that we want to add here, inside the UI manager. Whenever we update the O, we want to also enable the reload warning, whenever the O is zero. Here, before we setting the O text here, let's just access the reload warning game object and then run the active method. Then for the argument, the bully and value, we can just pass O less or equal than zero. So this will check if the MO is equal or less than zero, then this will be true and the reload warning will gets activated. And let's save this. And let's go back to Unity. I'm going to wait a while for the script to get compiled, and now it's finished. Let's select the game manager. And here we have a new fields for the weapon HUD, for the weapon icon, we want to direct this weapon icon object from our player HUD prefs. The MO text just direct this tax object, and for the reload warning, we want to dg the reload game object. Let's save this. Now let's test this out. Okay, there was an issue, and apparently, it's related to the race condition. So in order to fix this, we need to go to the fiscal studio, and basically, the switch weapon are executed from the start of our player script. And on the UI Manager, The init is also triggered from the start of the game manager. If the player script start happens to be earlier than the game manager s, then the UI manager won't get ahold of the new weapon data that the player script are passing. In order to fix this, we need to delay this a bit. I'm going to use this extension that we've created, the delayed action, and then I'm going to pass a delegate that runs this method. And then I'm going to pass a very small value, sample 0.1 second, and save this. Another thing that we need to fix is also on our weapon data. Whenever we update or we reload the MO here, as you can see, we want to also fire this event here. Let's just copy that line and then paste it here. So this will update the MO on our UI manager. Another thing that we need to do is, let's go back to Unity and inside the data folder, we need to add a sprite for the weapon icon. So I'm going to select the default gun here. And with the UIPac that we've imported before, we will have this gun icon, and I'm going to use this for the default gun. And for the machine gun, let's just use the other UI icon weapon here. And let's save this. Once we've set up the icon here, we also need to add a bit of modification inside the weapon data here, and let's copy this weapon fire line here. And we want to also run the weapon fired event whenever we set up this new weapon here. So let's just run it here. And after we fire the event on the set up weapon method, we want to go to the player script. And then we want to change the order of our event here. So we want to make sure that the event it's fired or it's broadcasted before we set up the carbo weapon data. So let's just paste it here and delete this empty line here. Save this. And now let's go back to Unity. Okay. So now let's test this again, and if this works, then the real text gets hidden right away, and the Oh gets updated right away. So let's just press play. And there you go. As you can see here, the O gets updated right away, and we can shoot and then when we reload it's update, and we can also pick this weapon, and it change the icon. Also update the O, but we cannot reload with this weapon. So if this weapon is empty, then it will return back to the default gun here. And let's just shoot out, and if the MO runs out, you'll see that the reload tax is enabled. And once we reload, it will gets disabled. So yeah, we finish with our weapon HUD system, and on the next video, we are going to work on other UI elements. 29. 28 UI Timer: In this video lessons, we are going to continue to work on the UI element. And this time we are going to work on the time. So in order to work on the timer, let's go to the gay manager here, and I'm going to create a new UI Canvas object as the child of our gay manager. Now with this canvas selected, I'm going to change its setting for the UI scale mode under the Canvas scalar. Let's change this two scale with screen size, and I'm going to set the reference resolutions to be a full HD 11920 by 1080. I'm going to set the screen match mode to 0.5, so it will be halfway between the width and the height and save the scene again. And now inside this canvass, if we go to the D view here and then we press F while selecting the canvass, you'll see that we have this very big canvass here. And every UI that we've prepared inside this canvas here will get overlaid in front of our camera in the game view here. So now I'm going to create a new child object, and it will be a type of text mesh pro. And if we zoom this here, this will be the timer counter. I'm going to call this timer, and I'm going to put this on top here, but I'm going to change its size first. I'm going to set its height to 75 and the width to 150. For the text, I'm going to set this 200 and also set the out of size to be enabled. I'm going to align this to the middle. And also change the phone assets to the rex LA that we've created in the previous video. Now we have this timer setup. Let's just line this by accessing the anchor presets and by holding the outt button on the keyboard, we can just choose this top middle one here, and it will snap our timer to the top of our canvas here. Now let's open the UI Manager script. Let's go to the FSO Studio and access the UI manager. And here, for the UI manager, we want to add a new field below our health bar. Let's just type a new Serialize field, and for the type, it will be a text mesh P UI, and I'm going to call this Tier tex. Now we want to modify the Tier object script that we've created before, so let's just open the Tier script. Here, we want to create a new public static event, static event is quite powerful. It makes us easy to communicate between script without having dependency on each other are usually called decoupling. Let's just type public static, and we want to set this as a system action, and then we want to pass an integer. Let's just add integer as its signature, and let's just call this on time change. And set up an anti delegate. With the static event, declare, we can go to our time runs here, and then here before we subtract the duration, we can pass this duration via our on time change event. Let's just invoke this or broadcast the on time change, and we want to pass an integer. But since the duration is a float, we need to cast this to an integer. I'm going to add a cast to integer type by using asset parentheses and then the integer keyword and then type the duration variable name here. This will convert the duration into integer, and the on time change event will broadcast this. Now inside the UI manager, we want to subscribe to this on time change event. Inside the init method, let's just add a new time object, and let's access the on time or change event, and we want to create a new method called update Ter. But we haven't created this, so let's just tell Visual Studio to generate automatically. And now we have this. I'm going to change the arguments name to current Ter. Inside this update timer, let's just update our timer text here. Let's just type time tax, set text, and then we want to convert the current time into a string using the string method, and then format this two a two digit number. Using the string argument. Save this. Now that we have a couple of subscription in the UI manager, we need to make sure that this also gets removed whenever the object gets de activated. Inside the remove event, we want to paste this line here and then change this to subscription type. And here, we want to also make sure that we are unsubscribing the weapon fired inside the remove event, so just copy that line and paste it here, and save this. Now let's go back to Unity, and let's test this out. First, we need to set up the timer text here, and we already create the TR game object with the text mesh component attached to this time game object. Let's just drag this to this Ter text slot here, and it will register the text Mash Pro UI component. Now let's save this and let's test this out. Now, when it arrives, it updates the timer, and it start counting the timer here, as you can see. So let's just kill the enemy, and let's go to the next area, and it will count down the area again when it arrives. So there you go, as you can see, it's quite easy to implement the I using the static event. 30. 29 UI Hostage Killed: In this video, we are going to continue to work on the UI, and this time we are going to add a text whenever we killed and hostage. But before we delve into the hostage kill text, I'm going to show you that I've created another shoot out point, the third shoot out point, and I've duplicated the third one from the second one. In the third Shula point, it consists also hostage and enemy, and I put it in this position here. For the hostage, I put it here, also the target position on this position. And for the enemy, I put it here, and the target position is run this position. So you can just do that yourself to follow this video. Another thing that we want to fix here, let's just run this game to test this out. But you'll see that at the end, the camera is a bit tilted. There you go. It's a bit tilted. We want to fix this. But before we fix this, make sure that the third shootout point are input to the player move script as the third shootout point. I've added an entries here, and then I drag the third shootout point object to the slot here. And then I set the distance at 17 here. Now let's fix this. We need to go to the scene view here and select the camera path movement. And then select the last point here. And if we select the individual point here, and if you select rotate, you'll see that we have this rotation gizmo, and we can rotate just this point to adjust the up vector. But I found the best value for this is 358, so I'm going to just input here the angle under the selected point options on the path creator component. Now if you select the camera again, and then I going to scrub this to update this, you'll see that we have a correct camera rotation, not slightly tilted. Let's just enable the back option and then I'm going to set the preview distance back to zero. Sorry, I'm going to enable this and then disable this. Now that we've set up the third shootout point, let's just create the hostage keel text. Under the game manager Canvas, expand this. And I'm going to create a new UI text mesh pro, and I'm going to go to view here and then press F to focus on this text mesh object. And on zooming out, I'm going to increase the width text, maybe around 350, for the height, I'm going to make this 100, and I'm going to type hostage kel. And now inside gamevi, we can see the text here, and let's just adjust so it looks better. I'm going to set the alignment to center and middle. Also for the verte colors, I'm going to pick a red color and then pick the font asset that we've created before. And then I'm going to set this out of size, but I want to make this bigger. So I'm going to increase the width to around 450 and then the height around 150. So we have a bigger tax here. And let's just increase the maximum. Okay. I think this is the maximum tax size according to the width and our height setting. So if we want to make this bigger, we need to increase the size here. So let's just increase it again. Okay. I think it should be okay. And let's just call this hostage kel. And now we want to modify the script. The first thing that we need to do is we need to open the UI manager. And here inside the UI Manager, we want to create a new serials field with type of transform. So I'm going just to type this. And then for the type transform. And for this field, let's just call this hostage killed text. And now inside this UI Manager, we need to create a new public void to show this text here. I'm going to create a new public void and then call the method show hostage kill, and we need to grab a position. So I'm going to pass a factor three as an argument. And we want to also pass a Bulion for showing this. And we want to enable the tax based on the bleion here. Let's just access the game object of the hostage keel tax variable, and then run this a active method and then pass the show bulion. And we want to check if the show is false, then we want to return this function, so we don't need to execute more code below. Now we need to create a helper function to keep our UI inside of our screen. Because if the hostage is at the very near of our screen, then we might show the hostage keel text here, but some part would be outside of the screen here because the position of the hostage keel. We need to count that to make sure that the UI doesn't going off screen. In order to do that, let's open our extension class here, and then let's create a new public static method. I'm going to create a new public static method, but this method will return a factor three Let's just call this get position inside screen. Here, we want to pass a vector through for the resolution, the base resolution. Let's just call this base res, and then we want to pass a vector two also for the anchored position. Then let's just create the method. Inside this method, we want to create a new float, and let's just call this with boundaries. For the width bound, we want to use the base resolution x. Substract with the re transform width. Instead of anchored pause, we need to pass a rec transform. Let's just change this to a t, and then I'm going to substract the base re x component here with the rectangle t width and let's just create the height bound. This will be the base S dot y, substract with direct dot height. We are grabbing the width and the height of our UI component. Also, we want to add a float for the offset, and then we also want to subtract this resulting value with the offset. We have some margin to the edge of the screen here. And then for the height, we also want to add the offset. So now that we have the width and the height bound, we can use this for clamping the anchored position of the rec transform here. I'm going to explain this a bit for this formula here. Let's head back to unity, and let's just create a new image. And now, as you can see, this image is 100 pixel width with 100 pixel of height. If we want to increase this size to cover the screen, then we need to insert the base resolution with Sizo. In this case, is 1920. And with this, we need to get the half size of the screen here. And then we need to take account of our width in half of our UI elements. So for example, if I put it this in the 960, which is the 1920 divided by, then this is our position. But this will result in the UI gets crop or some part of the UI is outside of our screen. So in order to fix this, we need to substract this with half the size of our width, which is 250. This is basically what we are doing. And for the left side of the screen, then we need just to multiply this by negative one. There you go. With this formula, we can calculate the UI element, so it will stays inside our screen. I'm going to delete this image here and head back to the fiscal studio. Now I'm going to create a new vector u, and I'm going to call this adjusted position, and I'm going to set the adjusted position value to be the rectangle, the retrans from object that we pass and its anchored position. I'm going to grab the anchor position as the base value of our adjusted position. Then I'm going to adjust the x component of the adjusted position variable using the math F clam, and for the value, I'm going to pass its x value itself. And for the minimum, I'm going to use the width bound, multiply this by negative zero, sorry, negative 0.5. Because we want to divide this by two, and for the minimum position, we want to multiply this by negative one. So we can just do this in one take by multiplying with a value of half or negative half. And then for the maximum value, we can just use the width bound again and multiply this by positive 0.5. So this way we will get the position inside our screen. And for the y position, we want to do just the same by modifying the y component, and then use the math f class here and the clam method and then pass the y position of our adjusted position, and then use the height bounds, multiply this by negative 0.5, and then also for the maximum y, we want to multiply this with positive 0.5. Now that we have the adjusted position, we want to return this adjusted position, type return adjusted position. Now we have this. We can use this to position the hostage killed tax. Let's go back to the UI manager, but I'm going to save this first. And inside this UI manager, let's just set the hostage k tax position, and this is the world position. To the position that we are passing here. And then let's just create a new vector two adjust position. And here we want to run the extension class and the get position inside script method. For the base res, I'm going to create a new vector two. And since we already declare this, let's just type the value which is 1920 by 1080, and this will be in flowed, so I'm going to add a F sign. For the second argument, I'm going to pass the hostage kel tax and for the offset, probably I'm going to add 25 pixel. Now save this. Once we've got this value here, we need to apply this value to the anchored position of our hostage kel tax here. I'm going to access the anchored position, and we are going to adjust this position here and save this. Now we've done with the UI manager Park. We need to modify the game manager to add the function to trigger this method here. Here I'm going to create a new private method, and I'm going to call this show hostage kel. And we want to pass a vector three position, and we want to also pass a bulion for showing the text here. And now inside this show hostage keel, we need to create a new actor three, and we can call this Vector three screen position. And for the screen position, we are going to grab the camera from the player move object. And since this is a player, we can grab this, and then we can use the gap component and then type camera. And here, we can use the World screen point, and then we pass the vector three that we pass in the method here. And we will receive this vector T position from our hostage position in the world. And then after we convert the world screen position, we want to run the UI manager, sorry, the UI Manager, and then run the show hostage Keel and we want to pass the screen position. And also the show bulion argument that we've passed in the method here. Let's just type show and save this. And now we need to modify the hostage keel. First thing, we need to pass a vector three world position. This is called this world position, so it's clearer. Then here below, we want to run the show hostage keel that we've just created here. And also we want to pass the world position that we've passed here. Whenever the hostage get killed, we want to set the B show t first. And then we want to run this delayed action. As usual, we need to create a new delegate here, and we can pass this line here inside this delegate. But instead of showing the text, we can just set this to falls to hide the text, and we can add a delay for 3 seconds. And then close this. Now we've modified the game manager and the UI manager. There is one thing that we need to fix here. Inside the hostage script, we need to fix the hostage heel, and this is quite easy. We can just pass the transform the position of the hostage. But since the pivot of our hostage is at its feet, so we want to add a factor three up and probably multiply this by 1.2. So the position will be probably at the chest of the hostage or at the torso of the hostage and save this. Now let's head back to Unity. The other thing that we want to do is here, we want to add an animation, a blinking animation, and we can just add animator. And then use the animator controller that we use for the reload text. So let's just grab the read animator controller here, and it will use the same animation here. It will make the text blinking like this. So now we have this setup. The other thing that we need to do is inside the UI manager, we need to make sure that this text gets disabled on start. Here inside the init method, I'm going to add this. But instead of setting this value show, I'm going to set this two false and save this. And now we can really test this. Okay, so I'm going to go focus on our camera here, and then inside the game manager, we also need to set the text here, here under the hostage keel text, we need to drag the hostage keeled object from our Canvas, and now we can save the scene here. Now let's play and test this out, and let's try to shoot the hostage. Let's try to so the hostage. There you go. We have the text here showing, and let's kill the enemy here. Now if the hostages appear here, let's shoot it and yeah, try to keep the text inside the screen. We can test this actually by changing the size of our hostage size to a very big value, for example, set this to one than and 500 on the height, and we can increase the max size here. And we can test this out just to test if the extension that we've created is working or not. So let's just give it a try again. Although we want to revert that after this. Re. There you go. And probably we can see it with this hostage over here. Let's just shoot. There you go. Try to keep our text inside the screen here. Now let's just revert this back. One thing that we need to adjust here, I think we need to adjust the height. I don't think we need to multiply this by 1.2, so let's just factor that up. And let's check the hostage pivot here because I'm not sure if it's on the feet or not, so let's just focus on and this is the pivot. This is the center, this is pivot. Yeah, we can multiply this with the vector up, but we need to make this even smaller. I'm going to set this to 0.4, Multiply this by 0.4. So we will see the text around the chest and let's give it a try one more time. Yeah. It's quite nice, the position correctly on the torso or the chest of the hostage. Yeah. Okay. Yeah, that is how we create a UI that can appear based on the world position, and we can also keep those UI inside our screen with the extension method that we've created. 31. 30 UI Intro and End Screen: In this video, we are going to continue to work on our UI. And this time we are going to work on the Intro UI and also the end screen UI. So now let's go to the review here, and then let's expand the game manager. Also the Canvas. And I'm going to focus on our Canvas here. And the next thing that I want to do is, I want to go to the UIP folder. Inside the prefabs folder, we have the nscreen prefab. So I'm going to direct this nscreen prefab to be the child of our Canvas. Now we have this n screen here. We want to modify the text first. So let's just expand this, expand the layout, and inside the layout, we have a lot of child object that holds an area for the title here. And under the title area game object, we have a text mesh pro. So let's just select the fun asset xia that we have created before, for the new text. And for the score area, let's just expand all of this. I'm going to collapse this and then hold out and then expand all of them. And for the subtext and value, I'm going to select all of them together. And also the title and rank, and I'm going to change the fund asset also to Raglea. So let's just do that. Now we have all of this. And the next thing that we want to do is, we want to create an animation for this. So in order to do that, Select the end screen game object. And under Window, I'm going to go to the animation menu and then create animation. And we will have an animation window here. And if it's appear floating, you can just click on the panel name and then direct this and then dog to this area here. Now with the end screen selected, we can create an animation. I'm going to press create here to create the animation for the end screen. And under the game folder animation, I'm going to create a new animation for the end screen fade in. And now we can move the end screen game object here. I'm going to use this move tool here and then I'm going to move this on the y axis. And I'm going to enable the record button, and in 1 second of duration, I'm going to slide this back inside. I'm going to round the number, the top view 2200 and the button view 2200 also. Okay, so we have this here. Let's press play and see it in the game view. There you go. I'm going to delete this keyframe here because we won't be needing it. Okay. Now we can go to the project view here and inside the animations folder, we want to make sure that the animation for our end screen fade in here, the loop times is disabled. So I'm going to disable this, so it's not going to be looping, and I'm going to disable the end screen here. And let's save the scene. And for starting the game, I'm going to create a new text Mash pro game object and set this to 500 or 600 and for the height, I'm going to set this to 150. And I'm going to type ready and change the phone to Axle. For this ready text, I'm going to enable the ato size and set the maximum to around 400. So we have a very big tax here. I'm going to set the alignment to center and also middle. For the color, I'm going to pick a orange color, perhaps this one. More orange. Yeah. And I'm going to eimate this text also. Before we animate the text, let's just rename the text two ready text. And we want to check on our script here on the game manager, we have the state, and we have the game start state, and it's delaying the S state to gameplay in 3 seconds. So we want to create animations with 3 seconds duration. So let's go back to unity here. And by selecting the ready text, let's go to the animation, and then let's create ready text animation. Now we have this animation clip. We can create an animation. Here, I'm going to record. I'm going to add a property of the wreck transform, and I'm going to grab the anchored position. So I'm going to grab the position here. And for the starting frame, I'm going to move this to the left side of the screen and probably set the position to negative 1,500. So we have something like this. And I'm going to keep this for 2 seconds. And let's just copy this keyframe here by selecting the key frame, press Control C, and then press Control V. So it's going to copy this keyframe here. Let's just delete this double key frame. S. Let's zoom in and let's just delete the second one here. And at 3 seconds here, I'm going to move this perhaps to one and 500 in the position. Now we have this animation. So let's save this and we can disable the DVU back to our set. Now we've prepared the UI, we can start modifying the code to create a score calculation method. So now let's go to the scripts folder. And first thing, first, I'm going to open the UI manager script. Here I have the UI Manager script open. I'm going to create a couple of variables. But before creating the variables, I'm going to create a new header, and I'm going to call this score properties. For these score properties, we need to create a couple of text mesh pro variable. Let's just create the first one. For the first entry, I'm going to add the enemy kill text. I've typed this wrong here, so it should be a serialized field. Let's just copy this line here and I'm going to paste this a couple of times. Now the second one would be the hostage kel. And the third one would be the shots. And the fourth one would be the if, and the fifth one should be the accuracy. And we want to also create a new serialized field with a type of game object, and this would be the end screen panel, and save this. Here below, we want to create a new public method to show those end screen values. Let's just create a new public void, and let's just call this show screen. With this method, we are going to pass a couple of variables. The first one would be the enemy kel. The second one would be an integer also, but this is the total enemy. The third one would be also an integer, hostage kill. The fourth one would be the shots, or we can just call this total shots. And the fifth one shod be the total hit. Now inside this method, first, we want to enable the N screen panel, so we can just run the set active method and then pass a through as the argument. For the enemy kilt text, we want to set its tax to the enemy kel value divided by the total enemy and we want to multiply this by 100 to get the percentage. Multiply this by 100, and after that, we want to convert this two A string using the two string method with a two digits argument here, and then we want to add a percentage sign. But since both of this value is integer, this will produce an integer. So we need to cast one of this value to a float. So we will have a fraction value. Then we can use those value to be multiplied by 100 to get the percentage of our enemy kl. So I'm going to cast the total enemy here to a float value. And for the next tex, I'm going to modify the hostage kel text. And we can just pass the hostage keel and convert this two a string. Then for the total shots, you can just grab the shot variable here, and then set its tax to the total shots, convert this two, for the hit tax, we can just modify the h variable, set its tax, and then pass the total parameter here, and then convert this two a string. The last one, we want to modify the accuracy text here. By using the same formula with the enemy keel here, we want to divide the total hit divided with the total shots, but we need to cast the divider into float, and then we want to multiply this by 100 and then convert this two a string. And then add this with a percentage sign. I need to convert this to a string. Okay. Let's just check for parent to C here. Okay. Let's add a parent to C here and see. We are one parent, so I've added, and now it's correct and save this. Okay, the next thing that we want to modify is we want to go to the gay manager and inside the game manager, we want to create a private void here. I'm going to create a new private void below. And I'm going to call this show screen. And for the end screen, we want to run the UI manager, and it's show en Screen method. And we want to pass all of this variable here. So let's just pass all of the neme kill. I think, no, Enemy kill. Yeah. Total enemy, and also the hostage killed. And for the total shots, it should be shots, I think, shots fired. And for the hit. I think yeah, it's enemy hit, and let's save the game manager script. After modifying the game manager, let's go to the player move script here, and we want to create a new method for clearing an area. So here we need to create a new public void, and let's just call this area clear. And above here, in the variable area here, we need to create a new private integer, and let's just call this area clear. Inside this area cleared method, we want to increment the area cleared integer variable, and we want to check if the area cleared is equal to the shoot out entries length. Then it means we've cleared all of the area in this level. So we want to broadcast an event here. We need to create that event. Here above, I'm going to create a new public static event with a type of system that action. And I'm going to call this on level finish and insert a empty delegate. And as I've explained it before, public static event is a very powerful feature that can make it easy for scripts to communicate with each other or one script to trigger another method in other script. But one thing that needs to be remembered, that static is a shared object. So when using static event, we should make sure that the scripts are only attached to one single object in our scene. If there are multiple script, then static won't work because it will only grab the first one, but it will ignore the other. So Make sure that use the static event correctly. So now we have this event created. I'm going to go back to the area cleared method, and I'm going to invoke this event. And then I'm going to return this method. And if we have still area left in this level means that the statement is false, then we want to continue the movement by running the set player movement to true. Okay, now we've done with the player move here. Let's go back to the game manager, and we want to subscribe this show screen method to the level finish method that we've just created. So inside the game manager under the I method, We want to subscribe the player move class here and the level finish event, and we want to subscribe the show and screen method to this event here. And on this able, we want to also remove this subscription. So I'm going to copy this line here and then change the subscriptions to unsubscribing method. Save this. And now the last thing that we need to modify is the shootout point script. So let's just open the shootout point script here. And now here below, whenever the enemy killed and we've killed all of the enemy, we don't want to resume the movement here, but instead of resuming the movement, we want to run the area cleared method. And with area cleared method, it will automatically resume the movement if there are still a shootout point that we need to finish. After we modified the player move line here, we need to also make sure that we modified the one in here here. So in the set area clear, instead of resuming the movement, we want to also clear the area, and this will be called when the time is over on a certain shootout point. So with these changes, even though we haven't killed all of the enemy, we should able to progress to the next shootout point whenever the times runs out. So let's just change this to the area cleared method. And this way, we can finish the level, even though we haven't killed all of the enemy, but at a risk of a lower score. So let's save this. Now let's head back to unity and set up the end screen. And once the script compiled, we can select the game manager, and under the UI manager of our game manager script here, we have a lot of new fields declared. So let's just drag the end screen as the end screen panel here. And if we expand all of the child game object here, we can drag the value of the hostile kilt as the enemy keeled here. And for the hostage kilt, drag its value to the hostage kt. For the shots, drag the value of the shots fired here. And for the shots hit value, we can direct this to the hit slot, and for the accuracy is direct to the accuracy slot. And let's save this. And now let's give it a try. So now we have this ready tax. Oh, sorry. We forgot one thing that by default, the animation that we've created is sets to looping. So we want to select the ready tax animation and disable the loop time total here. And then let's test this again. Let's try to kill one of the hostage. And let's wait for the enemy to show up and let's kill this one. There you go. We have killed 75% of the enemy. Okay, there is an issue. I need to check this out. There is a race condition where when we are showing the end screen and then start calculating the percentage of the total enemy, not all of the enemy kill has been registered. So to fix this in the game manager, we need to delay this method here. To make sure that all of the integer variable, which is the enemy killed, total enemy hostage killed, shows fire, and enemy hit, has been counted correctly and make sure there are no race condition. So let's just use the this delayed action extension and then create an empty delegate here. And let's just cut this code here and then paste inside this delegate. We are going to delay this code here by a very small value. For example, 0.2 second, and then let's clean this code a bit. Save this. And now let's head Unity. And I'm going to change the Inspector debug so we can see all of our integer fields here on the game manager and then press play. So let's just pick up the weapon here and let's start shoot the enemy. Let's wait for this enemy here. So far, we are 100% of all of the enemy. And let's just finish this up. There you go. We have the correct of percentage of enemy kill. 32. 31 Bug Fixes part 1: In this video, we are going to fix a couple of things and polish the codes. There are issues so far in our project here. So now let's inspect what are the issues. So I'm going to play this project, and let's take a look. Okay. The first one would be whenever we killed an enemy here, you see that we have this error. And basically, this error, it's telling that get remaining distance can only be called on an active agent. So somehow, the enemy scrip, it's remaining distance, but with the enemy already been killed, this is causing an issue. So we need to fix this. And let's just continue this. And the other thing that we have this, the hostage or the enemy is visible on start. So we want to make sure that we hype all of the enemy and hostage on start. So in the third shoot out area here, when we arrive to this position, We shouldn't be able to see the hostage first. And when we stop, then the hostage shook appear and then start entering the screen. We are going to also fix that. And the third one, it's regarding the total enemy counting. On our shootout point here, we are basically counting the total enemy here to compare whenever we killed all of the enemy, then we want to clear the area. But there is an issue here. Now let's test this out and take a look at the total enemy variable here. As you can see here, on start, we have total enemy of one. But actually, we have two enemies here. And the second one gets registered a bit later after the first enemy start moving. So we want to make sure that the total enemy get counted right away when the shootout point initialized or started. So we need to fix that also. So here, I've created a list. So basically, the enemies and the hostage should be hidden on start. And when the enemy killed, there is this error regarding getting remaining distance of the NAF Mash agent component, and we should make sure that the enemy counting happens earlier. So now let's just fix all of these things here. Let's go to isle Studio. Here in the shoot out point script here, we want to hide all of the enemy and the hostage on start. So in order to do that, let's just create a start method, and then let's look through the enemy list here. So let's just call the variable enemy and the collection, the enemy list. And on all my inside the enemy list, we want to hide the game object. Let's just access the enemy, and let's access the enemy game object here. But since the enemy is an enemy scrip, then we need to access the game object and then access the set active method and then set this two falls. After we are setting the enemy two false here, on start, let's just copy this line here, and we need to make sure that we want to activate the enemy inside the send enemies co routine here. So whenever the enemies gets initialized, we want to also activate it. So let's just paste the code here and then set this value true. And the other thing that we want to modify is inside the enemy script, we want to make sure that all of this initialization happens on OA. Because with the changes done in the shootout point, we are enabling the enemy game object and initializing the init method of the enemy script in the same frame. This can cause race condition, and it might skip the behavior setup method from running. If at the time, the agent has not been grabbed yet, causing the agent values still null. So this way we are make sure that this happens first, even though the object is disabled. For the counting of the enemy here, we can just copy this line here or cut this line, and we can paste this line here inside the start method. So let's just paste it here. We are going to count the total enemy when the scenes start. Let's save this. The next thing that we want to fix is this one here. In order to fix this, we need to go to the enemy script, and this is happens because the shoot protein are still running, and this code here gets evaluated, even though the enemy has already been killed. So now we need to make sure that we run the stop shooting method, which are going to stop the co routine inside this enemy script class. So let's just run this stop shooting method inside the dead behavior. So I'm going to add it here, stop shooting, and save this. And now let's go back to Unity and test this and see if all of the bugs are fixed. So I'm going to save the scene also. And I'm going to set the delay back to three or four and say this. Now let's take a look at the total enemy value here if we press play. Now when we press play, it counts right away. We have two total enemy. Now when the enemy appear, we can kill both of them or we can just shoot this barrel, kill using the explosion. And now you'll see that we don't have the hostage anymore. But when we enter the Shota point, the hostage arrive and we can just kill the enemy here. And now, if you take a look here, we don't have the get remaining distance error anymore. So we fix all of the issue regarding the enemy here. Let's just stop this. There is one thing that we need to fix here, a very easy fix regarding the UI. Let's just expand the main camera here and select the payer HUD here. If we go to the game view and then we select the main camera, I'm going to change this back to normal, and let's just enable the back option and let's just scrub this. As we move here, you'll see that our UI gets clipped by the wall in this area, this particular area. Let's just modify this here. And basically, we need to make sure that the HUD is much closer to the camera. Let's just move it. I'm going to change the z position to 0.2. And I'm going to scrub the x position so we can see it. There you go and scrub the y position. But now it's very big. So we need to make sure that the scale is much smaller than before. Let's just try a tenth of it. And now we need to scrub the I again to grab it. Let's take a look inside the editor here. There you go, so I'm going to move on the x axis. Let's change this to local and move it here. We have this pros enabled. I'm going to disable the prog and this manually. And we can use the scrub here to see the UI. Now we have this UI here and it's quite small, so I'm going to set this 20, and then I'm going to make sure it is much closer on the z axis. Make it slightly further and scrub position. Let's make this 23 or four, negative 0.0 45, and let's make this negative 0.08. I think this is a good position here. Now let's just select the main camera and let's just scrub the preview distance under the debug option, so we can see if our UI are clipping an object. Because it's very close to the camera right now. It's visible all the way to the end here. Yeah. The should fix the UI issue. And let's just save this. So yeah, we fix all of the small bugs inside this project here. And after this, we are going to work on the audio system. 33. 32 Custom Mouse Cursor: In this video, we are going to create a crosshair to replace our mouse cursor. Let's just go to the scene view here. And under the game manager, we want to go to the Canvas game object, and we want to create a new image object. So I'm going to right click here and then go to the UI menu, and then I'm going to create a new image. For this image, I'm going to call this crosshair. And I'm going to set its width and its height 250. And for the source image, I'm going to pick the UI cross hair that I've prepared in the UI package. So let's just pick this. And if you zoom in here, you see that we have the cross hair, and I'm going to change its color to red. So let's just go here and I'm going to pick red. And now we have created this crosshair. We need to make sure that the crosshair is on the most bottom order in the Canvas child. This will get rendered last. And now let's open the game manager script. Here, inside the UI manager script, we need to create a new variable, and I'm going to declare one with a serialized field attribute. For the type, I'm going to set this two transform, and I'm going to call this a crosshair. And here inside the init method. We want to check for the cross hair. If the crosshair is not null, then we want to hide our mouse. So we can just type cursor, the ysible, and then set this value to falls. And save this. And now here below, we want to create a new method to move the cross hair. So let's just create a new public method, and I'm going to call this move cross hair. And we want to pass a vector tree as an argument, and let's just call this mouse position. So here, basically, we need to check if the cross hair is not Null, then we want to move the crosshair. Let's just type cross hair, and then we want to access its position, and then we want to apply the mouse position that we pass through this method here as an argument. Now let's save this, and let's go to the game manager. And here inside the game manager, We need to create a new update method. So let's just create a new void, and let's just call this update. And basically, we want to run the UI manager method that we've just created, which is the mood cross hair, and then for the position, we can just simply pass the input mouse position. And let's save this. Okay. Now let's head back to unity. Once the code compile, we should have the cross hair parameters in our inspector, and now we can drag the crosshair game object and put it in the cross hair slot of our game manager script here. Now let's save the scene here, and if we go to the game view and let's test this out. You'll see that upon playing, the mouse is hidden and we can move the cross hair as we move the mouse and we can shoot exactly at where the cross hair is. So that is how we create a custom cross hair or a custom mouse cursor in unity. 34. 33 Looks Development: In this video, we are going to develop a looks for this game here by modifying the post processing filters and also modify the materials in our scene here. So now let's start. Here, I've import a new texture and material for the robot enemy and also the Robot hostage, and I'll put the package. And now let's replace the material to our enemy and also the hostage. So first, I'm going to go to the prefet folder and open the enemy prefe here, and I'm going to go to the updated folder under the Robot Kyle folder here inside the models. And we have two new materials, which is the robot updated and robot hostage updated. I'm going to drag the robot updated to this enemy here. And as you can see, we have a more shiny material, and this will look better once we apply post processing in our sine. And now let's go back to the prefs folder and I'm going to open the hostage prefs and this time, let's just drag the updated hostage material here. And there you go. Okay, so now we have modified both the enemy and the hostage. Let's go back to our scene here, and let's create a custom sky box to replace this original sky box. So I'm going to go to the materials folder and I'm going to create a new material, and let's just call this custom sky box. For this material, I'm going to change the shader into the sky box one, and under the skybox, I'm going to pick a procedural. I'm going to change a couple of settings here. If I go to the game view here, I'm going to change the ground color to be as close as possible with our grid object here color. Let's just use this color picker and then just pick the color here. In order to apply this custom skybox, we need to open the rendering and lighting settings menu. And I've already ducked my lighting settings here, so I can just drag this custom skybox to this skybox material, and it will change our skybox, as you can see here. So now we have apply the skybox to our scene here. We can modify the sky box further by going to the inspector and then use the color picker or the color swatch here to modify the value bit. So it's a bit seamless with our ground. Yeah, I think this should be okay. And now for the sky tin, we can change to a certain color if we want to. I'm going to pick a slightly purple blue and purple ish color over here, and then change the color to a darker one. For the atmosphere thickness, I'm going to decrease this value until we have a darker sky. Something like this. We can change the exposure if we want to. I'm going just to set this to the default value, which is 1.3. And now we have the custom Skybox applied and set up properly. Let's create the post processing profile. To apply the post process, we need to go to our main camera game object in the hierarchy, and then let's add a post processing layer component. Here in the post processing layer settings, we need to change layer to a specific layer that we want to use. Here, we already have a post processing layer, and if you don't have it, you can always go to the layer options here and then press at layer and then create a new layer. But since I've already have this post processing layer, I'm going to use this one. Go back to our main camera and I'm going to change this to the post processing layer. For the anti sing, I'm going to change this to temporal ants. Now we've set up the post processing layer. We need to create a post processing object to be applied to our camera here. We need to create a new anti game object. And I'm going to call this post process. Let's just zero out the transform, and we can add a post process volume component. And we need to also change the layer to post processing and make sure that is global is checked, so the post process folum will apply the scene globally. Now we can create a new profile here, but I prefer to create on our assets folder. I'm going to go to the game folder here and I'm going to create a new subfolder, let's just call this process profile. Inside this post process profile, I'm going to create a new post processing profile here. I'm going to call this game game play PP. Now we can assign this to our post process object here. Let's just direct this gameplay post process inside this profile slot here, and now we can add effect. The effect that I'm going to add are the ambient occlusion and also the blue. The next one would be the color grading. I'm going to add a screen space reflection, and also a fine. Now we can modify the post processing volume, each of rights. First, we want to enable the ambient occlusion. Let's just enable the mode here and then the intensity. Also, we can enable the thickness modifier if we want to. The next thing that we need to change is the intensity. As you can see here, the intensity default 20, so we need to increase this value and you'll see that we have a ambient occlusion applied to our scene. I'm going to make this value a very small one. Perhaps around 0.5 or one. Probably less than one would be better. Let's just set this 20.75. And we can see the difference whenever we disable and enable the ambient occlion here. The next one that we want to set is the bloom here. I'm going just to enable the intensity and the threshold of the bloom. Now we can increase the intensity here. But we don't see any bloom effect because our material doesn't have a high range MIF value here. So let's just test this out by setting the intensity first 24, and we can decrease the threshold. So let's just lower as we lower the threshold, you'll see that the bloom will affect more and more color in our scene. I'm going to set the threshold to 0.8. This should be enough. The next one that I want to set is the color grading, and I'm going to set the mode here to high definition range. And for the tone mapping, I'm going to set the mode to ACS, and we will have a very darker color of our scene here, but we can compensate this with the post exposure option. Let's just enable this and increase the post exposure to around 0.5. And we will have a much more contrast picture. And if we want to, we can also enable the track balls here by enable the lift, the gamma, and the gain. I'm going to enable the lift and the game here. And I'm going to change the lift, which is the dark area to a bluish color. And for the gain, I'm going to change this to the opposite direction of blue, which is the orange color to balance out the color of our scene here. So this is what we have so far. And if we want to have much more glowing lines here in our grid object, we can go to the scene here and select one of the cube object and modify the materials on it. So I'm going to go to the emission options here and then press on the, the HDR color, and I'm going to increase the intensity to 1.5. And as you can see here, as I increase the intensity, now the lines are more glowing. Okay. And as you can see here, we have the player HUD UI also applied by the glowing filter, but we don't have this ready and hostage kilt applied by the bloom filter. B for the canvas, the main canvass here is set to screen space overlay, and for the player HUD, the UI render mode is set to world space. So that's why this is affected with the post processing filter. So in order to make sure that this canvas is also affected, we need to change the render mode to screen space camera, and then we need to pick our camera as the render camera of this canvas here. So let's just direct the main camera to the camera slot here. And now we cannot see the UI anymore because it's very far away in the distance from our camera, so it's actually behind of our game object here. So I'm going to make this a very small valley, which is 0.1. And you see that our UI is messed up. So in order to refresh this, we can just disable and enable this. And as you can see, we have an updated UI, and it's glowing now. And because we are changing the UI render mode to screen space camera, the custom crosshair won't work anymore, so we need to separate this object into a new canvass. So I'm going to create a new UI canvass here. Let's just call this cross hair Canvas. Let's put the cross hair game object under the child of this cross hair canvas. Let's set this canvass into a scale with screen size under the Canvas scale and set this to a full HD resolution, and set the match 20.5. For the crosshair, we can set the scale back to one, and let's just zero out this value here. So we can see it here in the middle. And the other thing that we need to modify is the hostage keeled tax because the way we show the hostage keeled tax, similar to the crosshair. So in order to fix this, we need to put the hostage kilt also in this canvas here. So let's just drag this. And put it above the cross hair. So the cross hair gets rendered less. So this should fix the issue with the UI. Another thing that we need to modify. We need to make sure that the hostage keel transform is back to the default value here. So let's just select the hostage keel, and as you can see, we have all sort of numbers in the position rotation and the scale. So I'm going to set the position back to zero. And for the rotation, I'm going to also set all of the axis back to zero. And for the scale, we want to set this back to one. Because before the hostage keel text was on this screen space camera canvas, and it has different values for the direct transform. When we switch back to the screen space overlay here, the direct transform value gets transferred from this here to the crosshair canvass. So we have different transformation. And that's why we have all of the wrong values in the transform of our hostage keel text. So now let's save the scene, and let's test this out. And as you can see here, we have a working cross hair. And now let's take a look if the hostage kel are positioned in the correct position on the screen. Okay. And now we have another issue here. If we shoot the enemy, you see that we don't have the electric effects. With the hostage, we still have those electric effect, but with the enemy, we don't have those effect anymore. And this is a quick fix actually. We need to go to the prefe folder and open the enemy prefs. And here, if we select the enemy, we need to move the hit effects to be on top of the enemy script here. So let's just move this up and make sure that the hit method inside our hit effects also gets executed whenever the enemy receive a shot or a damage. And now let's go back to our scene and test this one more time. And I'm going to try to shoot the enemy. And there you go. We have the effect. And let's just shoot this bomb here. And pick this weapon up and kill this enemy. Yeah. Okay. So everything works good so far, and with applying post processing filters, you can see that we have a much better looking game. So I encourage you to experiment with the post processing filter and also the material settings to achieve better looking. 35. 34 Enemy Upper Body Fix: This video, we are going to fix the enemy upper body motion. And here, if I press plea, and you'll see that currently our enemy when moving has a strange motion on the hand, the hand holding the guns. As you can see here. It's weird. And we also want to fix the dead animation, sometimes didn't get triggered correctly. So let's just do that. I'm going to stop this. And now let's go to the animator window, and if the enemy animator is not open, we can just go to the animations folder under the controller and then double click the base enemy controller. And now here in the base controller, first, I want to change the transition for the dead state here. So I'm going to change the condition to use the inside of the dead trigger. We are going to use the dead bulion, and set to true. And under the settings, we want to disable can transition to itself. So let's just disable this. So the transition only happens once when the enemy is dead. And then we want to create a new layer for the upper body. So I'm going to call this upper body. And for the settings, we want to increase the weight to one, and for the mass, we want to use the upper body mass that we've created for the hostage. So let's just use this. And here, we need to create three new state. So I'm going to call this idol. I'm going to duplicate this, and the second one will be the hit reaction, and the third one will be the den. Since we are overriding the upper body part of the animation, We need to make sure that we have each animation for each condition. So if I go to the base layer here, you see we have three states, and we want to replace all of the upper body motion inside the blend tree with this idle state here. And for the hit state, it's going to be synchronized with the hit state of the upper body area, and the dead state will also be synchronized with the dead state of the upper body layer here. So now let's just create a new transition from any state to the hit state and also from any state to the dead state. And we want to create a transition from the hit back to idle, just like our base layer here. So now inside the idle state, we want to use the rifle aiming idle animation, and for the hit state, we want to use the hit reaction. For the death state, we want to use the death from headshot. And now for the transition settings, for the hit, we want to set a condition whenever the enemy is shot or the shot parameters gets triggered. And we want to set if the dead bulion is currently false. Meaning that the enemy is still alive, and as you can see here in the base layer, we have the same transition settings. So we want to make sure that the transition settings is the same as the base layer one. So this is already correct. And we want to make sure that from the hit to idle is using the exit time. So this is also already correct. And now for the death, we want to make sure that I that Ban triggers this animation. Let's just choose is that Ban and then set this to true. And then we want to also disable the transition to self options here. So now we have set up the animator here. I'm going to save the project one more time to save all of the changes in our assets. And now let's just double check. H we put? We already put all of the animation, the correct animation clip. Let's test this out. And let's take a look when the enemy are moving, it should have the correct upper body animation. Okay. There you go. It's much better, and we can kill this. And as you can see, that animation is more reliable now, because when I was testing before, sometimes it gets triggered, sometimes it doesn't get triggered, or maybe there is frame skip whenever that trigger gets triggered. So now we have the correct animations, and it is much better when moving sideways, the hand position that holding the guns. So, yeah, that is how we fix the enemy upper body motion. 36. 35 Audio Library Setup: In this section, we are going to work on the audio system. And in this episode, we are going to define our audio library script. So in order to do that, let's go to the underscore game folder and go to the scripts folder. And here, I'm going to create a new scriptable object for holding the data of our audio library. So let's just create a new CHO script inside the scriptable object folder, and let's just call this audio library. Another script that we need to create is the audio data holder. I'm going to create a new CHR script, and I'm going to call this audio data. And let's open both of the script here. Now I have the Audio ta and the audio library open. I'm going to work on the Audio library first. Here in the Audio library, we need to change the base class into a scriptable object, base class. And we want to also create an asset menu. So let's just add the create asset menu attribute, and then for the argument, we want to set the file name to Audio Lib. And for the second argument, I'm going to set the menu name to Audio library. And I'm going to delete the start and the applet method. Now we want to define the audio data that we can populate inside the audio library. Here inside the audio data, let's just delete the base class here because this is going to be a custom class for holding a data, and I'm going to delete all of the method inside. The first thing that I want to create, I want to create a serialized field, and this will be a type of string, and I'm going to call this field audio name. And for the next method, we want to create a array of audio clip. Let's just create audio clip array, and let's just call this audio clipse. And the other thing that we want to set up is we want to create a new float variable, and this is going to be the minimum pitch. And the second one would be the maximum pitch. We can set a default value here. Let's just set this 20.9 float. And for the maximum pitch, let's set this 21.1. And we are going to use this variable to randomize the pitch of our audio whenever we are playing the audios. Thus it will make the sound more dynamic. And since all of the field is private, we need to make a public getter. I'm going to define the public getter below here, as this type public, and I'm going to create the audio name getter. And this will return the audio name field. I'm going to also create the audio clip gather, and this will be the single audio clip, not an array. Let's just call this Get audio clip, and we can return the random clip from the audio clips array. Let's just type audio clips. For the index, we can use a random range and for the minimum should be zero, and the maximum would be the audio clipse dot length. This will grab the audio depending on the number of member inside this audio clip array, and it will pick randomly one of the audio clips in this array here. So we can define more than one type of sound for a gunshot, for example, and it will play randomly different audio, and also it will play with a different pitch here. The last one that we need to set up is the float getter for the maximum pitch. And here, let's just call this get pitch. This is the net thing with Getter. We can create a simple expression for returning some data. With the Audi clipse, we can return random clips, and with the get pitch, we can return a random value between this minimum and maximum pitch. Let's just use a random range method, and then pass the minimum pitch. As the minimum value and pass the maximum pitch as the maximum value. Okay, now we are done with the audio data. We can go to the audio library, and we can create an array of this audio data that we've just created. So let's just define a serials field here, and I'm going to create a new audio data array. And I'm going to call this Audio list. Inside this scriptable object, we want to create a public method for returning the audio data by its name. I'm going to create a new public method, and this will return an audio data. And I'm going to call this get Audio by name. And here we want to pass the name as the argument. Inside of this method, let's just create a new audio data. Let's just call this value and set this to null by default. And we want to look through the audio list here. Let's just call the variable member audio. And for the collection, we can just pass the audio list. And we want to check if the audio name, it's equal to the name that we are passing here as the argument, then we want to fill the value with this audio here with the correct audio here. And then after that, we want to return the value. So with this method, we can just pass a string of the audio name, and this method we return the correct audio data value based on its name because we declare the name here. So it will compare the string with this field here. Okay, let's save this. And now let's head back to Unity and create the audio library object inside our data folder. I'm going to go to the data folder here, and I'm going to create a new audio library and just call this audio lab. If we select this, you'll see that we cannot see the variable yet because we need to make sure that the audio data is serializable. I'm going to add a attribute system that serializable here and save this. Now if we go back to Unity, we should be able to see the data. There you go. We have the audio list, and we can expand the size. So for example, I can set the size 21, and here I can fill out the name. So for example, this would be the gunshot. And we can expand the audioclipse, and then we can fill the audioclipse. And I don't know why the minimum pitch and the maximum pitch is set 20. So let's just set this manually. I'm going to set this 20.9 and 1.11. And I've imported a couple of sound inside the audio here, so we can pick one of the audio. For example, this sci fi gunshot, and we can pick this one here. And this will be the first audio data that we have, and for the second example, we can expand the size here, and it will duplicate the first one, and we can change this value. For example, let's say let's just call this electric ZP. Sorry. Should be electric ZAP. Then for the audioclipse, we can change this to the electric crackle here. So now we have set up the audio library. In the next video, we are going to continue to implement the audio. 37. 36 Audio Player Setup: In this video, we are going to continue work on the audio system. And in the last video, we already create the audio library. So now we need to create the functionality to play this audio. So let's go to the Asset folder and inside the scripts folder, I'm going to create a new subfolder. And I'm going to call this folder Audio. And I'm going to create a new Cc and I'm going to call this audio player. And let's open this audio player script. First, I'm going to delete the applic method here. And then I'm going to create a new serialized field, and this will be the type of audio library, and let's just call this Audio ib. And we want to make sure that this script here is available globally in our project. So I'm going to create a static reference, a public static, and the type would be audio player. And I'm going to call this instance, and this will be a public getter with a private set. So only the script that can set this value, but all of the other script can get the value inside of this static reference. So let's create a wake method. And we can fill this instance value with the script here. Let's just pass this keyword as the value. And we put this inside the ak, so we want to make sure that this instance is available before any other script start. Now inside the start, we want to initialize the audio sources that we need to play an audio in this project. But first, we want to create a integrer, variable, and this is for defining how many sources that we want to have in our sc. And I'm going to set this to six by default. And we want to also create a audio mixer group for differentiate the audio sources for sound effects and for music mixer setting. We need to use the Unity e s, Unity engine Audio, and let's create a new serialized field. And this would be the audio mixer group. And let's just call this sound effects group. And the second one would be the Background music group. And now the next thing that we want to create, we want to create a private Q. And why I'm using Q because it's much lighter than lest. Let's see the short descriptions about Q. Q represents a first in first out collection of an object. It is used when you need a first in first out access of items. So let's say we have a queue of objects called M Q, and we fill it with an object. When you add an item in a list, it is called Q and Q adds an element to the end of the queue, like this example here. When you remove an item, it is called the Q. The Que removes the oldest element from the start of the queue, and to put the object with the queue, we can just use and queue. And this will put the object back inside of our queue as the last element. The other way to get reference to the oldest element is by using pk. Pak returns the oldest element, that is at the start of the, but doesn't remove it from the queue. And let's get back to our project. For the type, it will be an audio source, and let's just call these audio sources. And let's initialize this. And now we want to populate these audio sources with the game object that has audio source component attached to it. Let's just create a new in method. But before we continue in the init method, let's create another private audio source, and this one would be a single audio source, and this will be the BGM source. So now inside this init method, we want to create a new game object and then set that game object as either the BGM source or the audio sources, and then make sure those game objects are set to be the child of this audio player game object. So first, let's just create a new game object, and let's call this BGM object. And I'm going to create a new game object and we can pass its name here. So let's just call this BGM source. And for the BGM source audio source field here or Audio source object, we want to add the Audio source component to this BGM game object. Let's just type at component. From the game ob object here at component, and then we can pass the type, which is the audio source, and this will create a new audio source attached to this game object. And the next thing that we want to set is we want to set the BGM source spatial blend value 20, so this will be a two D sound. And we want to also set the output mixer group value, just the output audio mixer group, to be the BGM group. And the last thing that we want to set is, we want to set this game object to be the child of our audio player game object. So let's just access the BGM object, transform component, and then set the parent to this object transform. And now we want to create the sound effect sources inside a loop here. So we want to loop, and we want to loop this amount of time here. I'm going to copy this integer name and paste this as the length, and we want to run this code inside six time based on this audio source number, and we can change this in the inspector, so we can have more audio sources in our scene. So let's just create a new game object. And this will be the sound effect object. And I'm going to create a new game object and pass a name, which is the sound effect source. But I'm going to add the index i plus one, so it will start from one in set from zero, and I'm going to convert this two string with a format of two digit here. The next thing that we want to create is we want to create a new audio source We can just call this temporary, and then we want to add audio source to this effect, not the sound effect group, but the sound effect object. We can use the at component method and then pass the type, just like we did with the background music game object here. Okay. So now we have the audio source. We can set up this audio source and then put this audio source inside the pool of our audio sources. So let's just set the T spatial bland one this time because we want to create a three D sound. And then the next thing that we want to set is the output audio mixer group, and this should be the sound effect group, we want to also set the parent of this sound effect object to this game object here. Let's just access the transform set parent method and then pass the transform of this audio player game object. And the last thing that we want to do is we want to put this audio sources inside of our audio source Q here. So we can just access the audio source Q, and then we can run the n Q method and we can pass the T game object. So this will fill the audio sources queue with the audio source that we've just created inside the sloop here. And if the integer value is six, then we will have six audio sources inside our audio source queue here. And now before we continue on working the audio, we need to create an extension method to play the audio data object here via our audio sources. So let's just open the extension script. I have it here. And I'm going to create a new public static. And return type should be filed. We can call this play audio data. And we want to extend the audio source. So we need to use this keyword here and define the class or the object that we want to extend, which is the audio source, and let's just call this A source, and let's start the method here. Another thing that we want to pass is the audio data. So let's just pass the audio data here, and let's just call this audio data. And now because we are extending this audio source, we can use this to set up the pitch and the audio clips and play that audio clips. So let's just type A source and access it Pitch properties, and we can pass the audio data get pitch property or access or getup. And this will return a random value of the audio pitch that we've set up in this audio data here. And for the clip, We want to also assign this with the audio data Get audio clip. And this will return the random members of audio clip inside the audio clips array of our audio data here. Now after we set up two different properties here, we want to play the audio clip. Let's just access the A source and then run the play method. Now that we set up this extension method inside the extension, we can go back to the audio player and then start creating a method to play an audio. Here we want to create a new public void. And let's just call this play sound effects, and we want to pass a string audio name because we are going to refer the audio using its name instead of its clips. And if we open the audio library, let's just open the audio library here. You'll see that we have this function, get audio by its name here, and it will return the audio rata. We are going to use only the name to play an audio. In order to do that, first, we need to create a temporary audio source here. And we can get this audio source from our queue of audio sources here or the pull of audio sources inside the Q audio source. So let's just type audio sources, and let's just use the D Q method, and this will return the earliest audio source in our queue. And here we want to also pass the transform of the color. So let's just call this audio location. And we want to set the position of our audio source to this position here. So let's just grab the position from the audio location. And then we want to play the audio data. Because we extend this, we have display audio data method now for our audio sources. So let's just use this and we need to convert the string into audio data. Since we already have reference to our audio lib here, we can use the method by typing the audio lib that get audio by name, then we can pass the audio name string that we passed inside this method here. Let's just use that audio name. And close this. And this will play the audio data by selecting its random audio clips and also its random pitch. So we will have a different audio every time, and this will make the sound more dynamic. And then the last thing that we want to do is we want to put the audio source back to its pool by using the NQ and pass the Tam audio source here. So we will shuffle the earliest audio source before playing it, and after playing it, we will put it to be the most latest audio source inside our pool. And this will repeat over and over every time we play sound effect. And let's save this. So now we have this setup. We need to create a new custom we can create a string actually for this, but I'm going to create a new custom object to define the audio that we want to play. And you'll see why I've created this custom object in the next video. First, I'm going to create an attribute a serializable attribute. And this would be audio getter. And inside this audio getter, we will have a public string audio name. Okay, now we have this. We can open the weapon data. And inside this weapon data, we can create a new serialized field, and the type so be the audio getter. And let's just call this gun shot sound effects. And now we want to play this sound effect. Inside this fire method, I think it's Yeah, it's in the weapon update method. We want to play the sound. So whenever we are firing, or we can just run the sound effects inside the fire method because we have this fire method shared by these two different weapon type. So let's just go to the fire method here. And now we can access the audio player that instance since we already create a static reference, and we can run the play sound effX method. And this a for a audio name. So let's just pass the gun shot sound Audio name. And then we want to pass the transform of our player. And since we already have a reference to the player inside this scriptable object, we can just pass this transform from this player component here. So let's just type player do transform. So now we have a working sound effect for the gunshot sound effect. We are going to expand this in the later video, but let's just try to set up this inside unity. So let's go back to Unity. And now for the audio player, I'm going to attach this audio player to the game manager. So I'm going to add the audio player component here. And we want to grab the audio library that we've created inside our data folder. So let's just select this option here and then pick the audio library. And we can just leave the sound effects group and background music group empty for now. So let's save the scene here. And now to set up the audio. We can go to the data folder and check the audio lip and remember the name here, the gunshot and electric zap. I'm going to copy this name here. And we can go to the default gun, and for the gun shot sound effect, we can just paste the gun name inside the audio name field. And for the machine gun, we are going to use the sound effect. In this example, but we can change this later. Okay. So now we already set this up. Let's test this out. I think I need to make sure that the audio is not too loud. So I'm going to go to project settings, and I'm going to decrease the volume to 0.1 here. And let's test this out. There is an issue here. I forgot to run the init method inside the audio player. So let's just do that. Go to the audio player, and we want to run this init method. Let's type in it. And now let's go back to unity. Now if I press play, and if we pause this, you'll see that we have a lot of game object below here. And this is for the audio source that we want to use to play sound effects, and this is for playing the music. Now if I press play, let's test. There you go. Yeah have sounds, and it's different every time. Yeah. It has different pitch. So now we have a working sound effects, and the sound effects will be also dynamic, which is a good thing. And we want to simplify the way we pick the audio name here using a custom drawer. So in the next video, we are going to do that. 38. 37 Audio Getter Custom Editor: In this video, we are going to create a custom property drawer for our audio gator class. Right now, if we go to the data folder and if we select one of the weapon data scriptable object, either that de false gun or machine gun, you'll see that whenever we want to define the sound effects that we want to use, we need to type the audio name. And this is prone to error or mistake whenever we are typing the sound name. In order to make this easier, we need to create a custom property drawer for this class. In order to do that, we need to create a new script for overriding the editor. I'm going to create a new subfolder inside the scripts folder and I'm going to call this editor. And all of the CSR file that lies inside this editor folder, will not be included in the bill. So for every editor functionality, we should be putting the scripts inside the editor folder, and this editor folder can be created anywhere inside our project folder. Here I'm going to create a new CHR script, and let's just call this Audio gather drawer. And let's open this. Now if we go to the audio library, this is why we create a custom class for the audio name string. Otherwise, we can always use a string directly inside the weapon data, for example, for defining the audio sound effects ID or the name. But now, since we want to overwrite the display or the inspector, this is why we create a custom class for it. So now let's go to the Audio getter drawer and we need to delete all of the built in method. And we need to use the Unity editor library. So let's just type using Unity Editor, and we want to replace the inheritance to a property drawer. And here we want to add an attribute called custom property drawer. And inside the argument, we need to add a type of keyword here, and then we need to target the class that we want to modify. In this class, we want to modify the audio gather. With property drawer, it's actually quite simple. First, we need to override the method. So let's just type ongoing method. And as you can see here, the ongoing method have three arguments. The first one is a rectangle called position. The second one is serialized property, called property, and the third one is Gu content, called label, and label is basically the label of the name that we've defined in other script. Whenever we are showing a field, label is the name of the field. Okay, basically, this based on UI with the argument position property and label is drawing the normal inspector, and if we want to overwrite this, we need to delete this. So let's just give it a try here. And for drawing a custom inspector for property drawer, we need to access the editor GI class. We cannot use the editor U layout or the editor GUI utility. So here, for example, if I use label fiel, As you can see here, it asked for a position, rectangle, so we can just pass this position and it will know where to put this text. And for the second argument, we can use a UI content label or we can use a custom string label here. So I'm going to create a custom string, and let's just say that we've modified do gether. And let's close this and save this. Now, if we go back to Unity and after the script finish compiled, if we go to the data folder and select the default gun, you'll see that there is a text here that saying we've modified the audio getter, and we cannot change this. This is not we one actually, but just to show you how we modify the custom property drawer. And now let's just remove this. And now we want to create the prefix label. So I'm going to type position. And then I'm going to fill this with the editor I, and we can use the prefix label. And this prefix labels return rectangular class or object here. That's why we can fit this to the position. And this will make sure that this label gets drawn before any croised property that we want to modify. Okay, so let's just pass the position. And for the label, we can also pass the label. For the audio getter, we want to create a drop down menu where we can list all of the audio names that we've populate inside the audio library here. In order to do that, we need to create a couple of modification on our audio library and also on our audio getter. Inside the audio getter, I'm going to type public integer ID, and this will hold the index of the list of string that we are going to create inside our audio library. To make it easier to access the list of string inside the audio library, we need to create a new public list of string. Let's just create a new public static, and the type would be list of string, and let's just call this Audio names list, and let's initialize this. I make this static in order to make it easier to access this variable from any other class because we need to access those list of string from this custom property drawer script. We want to change this value every time we made changes on our scriptable object. We can use the method called valid date. Let's just type void valid date. This is actually a built in method. Somehow it's not marked as built in, but we can test this out. Let's just type the bug log. Let's just say that Audio library modified. Let's save this. Now if we go back to unity, and let's select the Audio library, and then go to the console here. If we try to modify one of the value inside the audio inspector here. For example, let's change the maximum page for the gunshot. You see that the valid date gets executed here and the back log gets printed in the console. So we can use that to modify static list of string that we've just created in the audio library. So I'm going to delete this here. I'm going to clear the audio name list and run the clear method. And I'm going to look through the audio list here. And let's just call this audio for each of the member, and for the collection. We want to pass the audio list collection. And here, we want to fill the audio names list with the audio names from each of the audio inside the audio list here. Let's just type audio audioam. This way, whenever we change the audio library in the inspector, it will update the audio names here. Save this. Okay. So now we've modified the Audio gather and the audio library. We can continue work on the Audio gather here. So to create a pop up or a drop down menu, we want to use the editor GY dot pop up, and for the pop up, it ask for a position, so we can just pass the position. And the integer for the selected index. And we can use this ID that we created in the audio gator because basically the value that are going to be safe for the pop up is the integer. And using that integer, we can grab the string from this static list of string here. But in order to access the integer that we've created in the audio gator, we need to access the property here, which is the series property, and then we need to use the fine property relative method, and it asks for a string name of the relative property path. In this case is the variable name, that's just type ID. And then for the last argument, we want to use a string array. So we can just type Audio, Audio library class and grab the audio nameless here. But since this is a list, we need to convert this to an array. So we can just use the array method to convert this two and array. Here we have an error because fine property relative return a serialized property. So we need to grab the integer value. Here. And all of this code here needs to assign into an integer value. In this case, we want to assign back to the ID value. So I'm going to copy this integer value here and then paste this in front of the RGI and then assign this. So whenever we change the pop up, we want to grab the new integer value and those integer value are going to be safe to the ID integer value. So we are overriding it. And whenever we change the pop up here, we want to modify the string value of the audio name. So let's just grab the audio name variable, Let's check if the variable called Yeah, it's audio name, let's grab the variable, and since this is a seriS property, we need to grab the string value and then assign this value using the audio library, the static string of list, which is the audio name list. And for index, we can just pass the integer value of our ID fields here. Let's just paste this here. And close this with Sam Colm. Now let's save this. Now let's get back to unity and see if this code is working. I'm going to clear the console here and let's select the default gun. And as you can see here, now we have a nice drop down for the gunshot sound effect. So we can change this to the electric z. And whenever we change this, we don't have any error. So that is a good sign. And let's just give it a try. Let's go to the audio lip here, and let's add a new sound. And let's just call this gun reload and change the audio clip to the sci fi gun reload. Now, we've add this new audio name. Let's see if the audio name list gets updated. Select the default gun and open the drop down here. And there you go, as you can see, we have a new sound. Now let's give it a try of our modification here. Let's change the gun shot sound effects to the electric zap here and press play, see if this modification works or not. Okay. There you go. It's working. And if we change to the gunshot, you can see we've changed the audio. And this makes selecting sounds much easier. 39. 38 Optimizing Audio Workflow: In this video, we are going to continue to work on our audio. And there's a couple of thing that I want to show you to make setting up the audio much easier. And first, we want to change the reference to the audio sound effect name. Instead of using a string, we want to use the ID. So here inside the audio get drawer, we don't need this. So let's just comment this out for now. And then let's go to the Audio getter. It's under the Audio library. And here we want to create a new public getter string. So I'm going to change this to audio name with capital A and set this as a gator. And let's just return the Audio library audio name list with an index of our ID. Okay, now save this. So now the audio getter will save our index ID based on the pop up that we select when choosing the sound effects, and whenever we want to refer to the sound effects, we are actually returning the string from the audio name list here. Now let's go back to Unity. And you will see that we have an error here because we changed the variable name, using a capital A here. And now if we double click on this error here, you'll see that it cannot find the audio name variable, because we changed this. So instead of using the string name, I'm going to delete all of the audio string here. And let's go to the audio player. And we want to use the audio getter. So this will make typing the code much faster. And instead of using a string, we want to grab the string from the audio getter here, so let's just type that audio name here. And we can just rename these two audio SFX and change these two audio S effects. So it's clearer. And save this. And now if we go back to Unity, we should have cleared out the error. There is still an error. Let's check this. Okay, save this. I forgot to save the weapon data. So let's go back to Unity. And now I finish compile, it clears all of the error. And if we press play and then test this out, You see, we still have a working sound. And the reason that I change the Gether drawer using the ID. Later, when we are populating our audio library and then setting the name for each of the audio data list here, we don't need to reassign the sound effects on every entry of the audio gather or every script that are using the audio gather as the audio sound effects reference. And this way savor, and it will be less prone to error than the way we are doing it before. And the other thing that we want to do, we want to add an option to set the sound effects as a two D sound. Currently, if we go to the audio player, you'll see that all of the sound effects, spatial blend are set 21. And for example, if we have a very low volume sound effects that we want to play on a distance object, we cannot probably hear this. For example, a weapon pick up sound effects. Probably that sound doesn't needs to be a three D sound because it's not a sound that are related to the immersion of the game, such as a gunshot or explosion. It's more a audio feedback for the game. We can set the sound 2a2d sound. So here, under the play SF X method, we want to add a default value for the audio location and set this channel. So with this set, we can just ignore this parameter if we don't want to pass a transform of the audio location. And here we want to create an if statement if the audio location is not null, then we want to set this audio source to be A three D audio. So let's just cut this line here where we're setting the position and paste it inside the I statement. And then we want to set the T spatial bland back to one. And we want to create an L statement. And this is when we are running this method without audio location argument. So here we want to set the spatial blend of our audio source back 20. So this will be a two D sound. And let's save this. Another thing that we want to create, we want to create a method to play the music here above, we want to set the audio source for our background music, loop option to be true, so let's just type BGM source loop and set this to true. For playing music, let's just create a new public method, written type of void, and let's just call this play music. We want to pass the audio gather also, and let's just call this music. But we don't need any other parameter. Here, we can access the BGM source right away, and we can use the play audio and let's use the audio library, get audio by name method, and we grab the string from the music Audio Audio Name. And here we want to make sure that the pitch is set back to one. We want to ignore the random value of the pitch here because we want to play the music at its original pitch and safeties. Let's go back to Unity and see for any errors. There are no errors, so it's a good sign, and in the next video, we are going to start populating the audio 40. 39 Applying Sound FX: In this video, we are going to start assign the sound to every object in the scene that needs the sound. So now let's populate our audio reliability first. But before I'm going to show you settings for our audio here. So if you have imported the audio files in the previous lesson, you'll see that we have a couple audio files inside our project here. So for all of the audio effects, I'm going to select all of them together. And I'm going to make sure that the load type is set either to decompress load or compress in memory, and we want to set the quality 290. And for the compression format, for this should be okay. So let's just press apply. And you see that right now, the original size is 1.7 megabytes, but the imported size is 400 kilobytes, so we already save around 75% of the original size. And for the audio music, the BGM file. We want to set this to streaming, and for the quality, we can just leave it 100 and press apply. Since this is an Petry file, there are almost no compression, but with streaming, the Petry file wouldn't be fit into a memory. It will be streamed from a disc. And basically with a streaming load type, we need to make sure that are only one audio source that are streaming from the disc. Otherwise, it could cause leg, especially on mobile devices. So Streaming usually are used for music because usually we only have one music in our scene. Now let's go to the data folder and set the audio library, and I've already created a couple of entry here, but I'm going to populate this with the rest of the audio that we have in our project. So I'm going to add maybe 212, and then I'm going to set this one by one, and then I'm going to speed up this video. And for BGM, let's just set the minimum pitch and the maximum pitch to one, so we would have pitch variation. And now I've already set all of this up here. I'm going to save the project so the scriptable object gets saved. And now we need to create a couple of scripts. So let's go to the scripts folder under the Audio. I'm going to create a new CHR script called play Audio action, and the other one should be the play music action. Now let's open the play Audio action script. Here in the play audio action script, we want to delete all of the built in method, and let's define the variable first. Let's create a serialized field, and for the type, this would be an audio getter. And let's just call this audio sound effects. And the second option will be a bulion, and I'm going to call this two D sound. And this is for enabling or disabling, whether we want to set this audio as a two D sound or a three D sound. And the last one would be a delay. So we want to add, sorry, not delay, should be flowed, and let's just call this delay. So we want to add a feature where we can delay playing the audio. So now let's create a new void on enable method. Why are we using enable method? Because enable gets triggered when the object gets activated and can run multiple times. Since some of the objects in the scene are de activated on start. If we use start method, we might never hear the audio playing because the start method has already been executed, and when activating the object later, the action won't gets executed. Here, inside the unenable method, we want to use the delayed action that we've created in our extension, and we want to pass an action using delegate here, and then after passing the delegate, we want to pass the delay here. Let's just pass the delay and then close this. Now we can type our code inside this delegate here. So inside this delegate action, we want to access the audio player, and then the static reference, and we want to play the audio sound effx, using play SFX method. And then we want to pass the audio geter. So let's just pass the audio Sound effx. For the location, we want to use this bleion to determine whether we are going to pass a transform or not. So let's just type to the sound, and then question mark. And if it's true, then we want to pass Null. But if it's false, then we want to pass this transform of the object the script are attached to. Now, basically, if we enable the d sound, then the sound will be a D sound when it's playing. But if it's disable, then it will be a three D sound. For the play music action, we can just duplicate all of the script here. And I'm going to open this. And here, I'm going to paste the script that we've copied before, and we are going to create a modification. Let's just delete the bullion here, and we can remove the second argument, and we want to run the play music method. Okay. Let's save this, and let's head back to Unity. Now, we want to open the weapon data script, to add the gun MT and the reload warning sound effect. Let's just open the weapon data here. And if we scroll up here under the gunshot Sound effect Audio gaor field, we want to add a couple more variables here. Let's just add a reload effect, the empty sound effects and reload warning sound effects. And here, if you scroll down below, we want to add a sound whenever the MO runs out. But we want to play the sound only if we press the mouse button. So we are going to change this statement to an if statement. So let's just type input the GT mouse button down and we want to grab the left click. And here we want to add a condition if the MO is less or equal than zero. If it runs out, then we want to play the empty sound effect. Let's just access the audio player instance and the play sound effX method. For the name, we can just pass the empty sound effect. And for the location, we can just use the player script reference and access the transform component. Let's just copy this line here and paste it here below, and I want to also play the reload warning sound effect. And we can copy this line here and then paste it on the machine gun code here, and we want to also check this statement. So let's just copy the first two condition and paste it here below and add the end sine. We create a similar condition, but with the current O equal or less than zero here below. Save this. Whenever we reload the MO, we want to play the reload sound. Let's just copy this line here, and here below, I'm going to play the reload sound effects and save this. Now let's open the player script. Here on top here, we want to add a new serialized field, and the type should be audio gather, let's just call this damaged sound effects. And basically, we want to play the damage sound whenever we start camera shake. Here, we can just put the audio player instance, play sound effects. And then we can just pass the damage sound effect audio getter, and for the transform, we can just pass the transform of this object here. Save this. The next one that we need to modify is the it effect script. Let's just open the hit effect script, and let's add a ers field of audio gather, and let's just call this hit sound effects. And whenever we hit something here, under the hit method, we want to play the sound effects. So let's just access the audio player. Instance, run the play sound effects method and then pass the hit sound effect fields. And for the transform, we can just pass the effects cache particle system, but we can pass the transform component here. So the sound will originate depending on the particle position, and this will be a treat sound. The last one should be the weapon pick up script. So let's just open the weapon pick up script here. And basically, whenever we hit the weapon, we want to play a bonus sound effect. Let's just add a size field, Audio gather, and let's just call this pick up sound effects. And we want to play the sound effect using the audio player. And let's just pass the pick up sound effects field that we've created, and for the audio location, we can just leave it null because we want this to be a dy sound and save this. Now let's go back to unity, and we are going to set these things inside unity. So here, if we select the main camera, let's go to the players script component and select the player damage sound effect. And let's go to the data folder also and select both of the default gun and the machine gun. And we want to populate this, let's just select the gunshot for the gunshot sound effect. For the reload, we want to select the gun reload. For the empty, we want to select the gun empty, and for the reload warning, we want to select the reload warning. And the other thing that we want to set up under our prefect folder, we can select the machine gun pick up here, and now the weapon pick up will have a pick up sound effects field. So we can just select this and then choose the weapon pick up. For the hostage, we want to modify this, let's just select the hostage. And here, I'm going to add the play audio action and add hostage don't shoot sound effects, and let's set this to the sound so we can hear it better, and let's just add a delay for 2 seconds. And now we need to modify the enemy wherever enemy gets hit. Let's just select the enemy prefect, and under the hit effect, we have the hit sound effect fields enabled. Let's just select the electric zap. For the hostage, we want to also set this to the electric zap. Then for the big explosion here, We want to add the play audio action, and we want to set the delay C zero, and we want to disable the D sound. We don't want this to be a CD sound. And for the audio SFX, let's just select the explosion. And now inside the scene here, if we expand the environment, select all of the cube object here. All of them should have hit effects script attached to it. Let's just select the hit impact slot here. Save the scene. And then we want to create the music for our scene, so let's just create an empty game object. I'm going to reset the transform, and I'm going to call this music, and let's just play music action and set the delay 20, and we want to play the BGM audio sound effects. And let's save the scene. And now let's press play and test this out. So there you go, we have a music, and we can shoot and we have a sound. And as you see, as you can heart, if I I shoot near on the edge you can hear the impact sound. And if we get hit by the enemy, we have this damaged sound, and if we shot the enemy, we can hear the electricity. And we can also hear the explosion. And we can kill the hostage, and we can hear the hostage voice and also the electric and the weapon pick up. There are a lot of sound happening right now. But basically, all of them are working and we don't have any error in our console. So, that is basically how we assign the sound to the objects in our scene. 41. 40 Shots Calculation Bug Fix: I found a bug regarding the shots fired and shots hit calculation. And in this video, we are going to fix that. So to check for this bug, we need to select the game manager and change the inspector type to D bug. And now we can see all of our private variables here. So let's press. And now you'll see that I'm going to mute the audio. And now you'll see that if we shoot the enemy, we will increase the enemy hit and the shots fired. But the shots fired always shoot times the enemy hit. And this is happening because inside our code here on the weapon data, if you scroll down, whenever we fire the weapon, it run this method here, and it runs this method for every hits on the object. So for example, on the enemy here, let's just select the enemy. And now if you sell the enemy, you'll see that we have two hitables, which is the hit effects and the enemy scripts. And we can confirm this by checking the script on the fiscal studio. If we open the enemy script, you'll see that this class here, implement the hitable. And the same goes with the hit effects. It also implement this hitable. So this may gets executed multiple times, depending how much hittable does the game object have or has. So in order to fix this, first, we need to separate the shot hit method with the shots fired. So if we go to the game manager here below, we have the shot hit method with a bleion argument. We need to separate this. So I'm going to create a new public void. And let's just call this shots fired, and we don't need to pass any parameter. I'm going to cut this shots fired line and paste it here. Basically, whenever we fire a weapon, we want to increase this value here. And whenever we hit something that we want to count, we run this method here. Let's just remove the argument and remove the if statement here. Let's clean this a bit. And save this. And now let's go back to the weapon data, and we can just delete all of this here, the statement and delete the return statement. And now the shot hit doesn't ask for argument anymore, so let's just delete the bulion value. And I'm going to delete also this return statement. And basically, This is all we need to do here. But whenever we fire a gun or fire our weapon, we want to run the shots fired method. So we can just run the shots fired method here above. So let's access the game manager, instance, and let's just run the shots fired method. This way, whenever we fire our gun, the shots variable on the game manager will increase, and whenever we hit something that we want to count, for example, the enemy scrip, then the enemy hit variable will increase also. If we go back to unity here, let's just stop this. If we select this barrel here, You see that we have this spawn on hit. And this creates explosion, and the other one spawn the machine gun. So we want to take this into consideration, the spawn on hit as an enemy hit. Otherwise, whenever we shut this both items, it will count as a shot fired, but not as a enemy hit, and this will penalyze our accuracy. So we need to go back in the script here and in the weapon data. Under the if statement here. We want to add a second condition, sorry, not n, but using the operation, and we want to compare or check if the itable is a spawn on it. Another thing that we want to check is, let's go back to Unity first and select the barrel white machine gun. And we need to check the pref two spawn here. If you select this, we can check the object. And here, the machine gun also have a itable script, which is the weapon pick up. So let's just open the script here. And we want to also check for this. Let's go back to the weapon Data and add another statement. If the hitable is a weapon pickup, then we want to also count the shot hit. Let's save this. Now let's go back to unity and let's play. Now if you select the game manager, we should be able to see the variable, and let's try to shoot the enemy. Now we have one shots fired. But if I shot the enemy, now we have two shots fired and one enemy hit. So the shots that we aim to the enemy are count as one, both the hit and the shots fired. So let's just top this and then test this again, and let's try to not miss the shot. There you go. Let's shot the enemy three times to kill it. And now we have three enemy hits and three shots fired. So with this change of code, we have fixed the bug issue where the shots fired is always two times larger than the enemy hit. 42. 41 Rank Calculation: In this video, we are going to create a rank calculation system. So if we go to the UI here and if we expand the game manager Canvas, you see if you select the n screen here and enable this. You see that we have a rank UI here, and it always display A currently. So we need to implement this. In order to implement this, let's go to Fico Studio and open the UI Manager script. And for the UI manager script, first, we want to create a new serialized field. And this should be a type of tex mesh P GUI, and let's just call this rank tax. And basically, we need to create some formula to calculate the score, to convert this to the rank. So the max ratio of the enemy kel is 100%. Also the Mx ratio for shuts accuracy, it's also 100%. With this two score or two measurement, we can decide on creating a rank system. Now let's just define. For getting rank of A, we want to make sure that the enemy kel is above, let's say, 90%. And since accuracy is a bit harder, we want to lower this value. So let's just check if the accuracy is above 80%. And for B, we want to set if the enemy kill, it's greater than let's say 75%, but at the same time, less than 90%, and with accuracy, let's say greater than 70%, but less than 80%. For C, let's just copy this line here. I'm going to paste it, and let's just modify this. For, we want to set if the enemy kill it's less than 75%, and it's greater let's say 60%, and for the accuracy, we want to make sure that this is than 70, and if it's greater than 55%, then we want to give it rank of C. And if we copy this line, paste it here, then we want to set the rank D. Let's decide that D is the lowest ran. So if it's less than 60, the enemy kel, and if accuracy is also less than 55, then we want to give it rank of D. With this here, we can create a total average. We are going to create a new variable. Let's just call this total average. And this should be the total amount is divided by two. This is 170/2, and we get 85. It means that total average should be greater than 85 to get rank of A. This one, we want to have a range, which is if the total average is greater than the lowest value here, so we can just grab the average 72%. And at the same time, it is less than 85, then we want to give it rank of B, and if we duplicate this and then pace it here for ran C, then we want to calculate the lowest value, which is 6055, this should be 57, and for the maximum, it's always the lowest value of our previous ran. So let's just set this if it's less than 72, and here if the total average is less than 57. So now we have this formula here. We can add a penalty value for whenever the player kill a hostage. For example, hostage kill will penalize point by 15. So one hostage kill will subtract all of our average by 15. Okay, with this formula here, let's just copy this note bit here, and let's go to Visual Studio and with the UI Manager script open, we want to scroll down. And then go to the show and screen method here, and I'm going to add a new method below. Let's just call this void calculate score. I'm going to paste the calculation that we've created and set this as a command. So we can see it here while we're writing our code, and let's just clean this up. Now we have this Calcate score method. Cleanup. We want to pass the argument of all the argument inside our show and screen method. Let's just select all of the argument here, and I'm going to copy this and then paste it here. Okay, basically here, we want to declare a couple of local float variable. The first one would be the hostage penalty. And we can just calculate the hostage keel, multiply by ten. We get the value. Sorry not ten, it should be 15 here, as you can see, then for the float enemy keel ratio, we can just calculate the enemy keel divided by the total enemy. But since both is in integer, we need to cast one of them to a float, so I'm going to cast the divider, and then I'm going to multiply this by 100. We'll get the percentage, and if we enclose this, want to subtract this with the hostage penalty value. Then let's just calculate also the accuracy ratio. And this should be the total hit divided by the total shots. And also, we want to cast the divider to a float and multiply this by 100. And don't forget to penalize the point by the hostage penalty. And now we have this. So let's just calculate the total average. And this is quite simple actually. We just need to add the enemy kill ratio with the accuracy ratio. And then divide this by two. Now we've calculate all of the formula here, we want to show the rank depending on this classification or the specification that we've created for the score. Let's just create an if statement and if the total average, it's greater than 85 here, as you can see, then we want to print out A on the rank. So we can just access the rank tax and run the set tax method and then insert a string as the argument. And we want to check if the total averages greater than 72%. But at the same time, it is less than 85. Then we want to print out B But one of the comparison here needs to have an equal sign, so it will include all of the range. So I'm going to add include sine, so it means that if it's equal or greater than 85, then we want to print this. Otherwise, if we don't use this, then if it's exactly 85, then both conditions will not be executed. So let's just add the equal sign. Oh, sorry, I've typed a percentage here. It should be F, so let's just fix that. And now we want to print on the rank text a character of B. So let's just copy this to make it faster, and I'm going to copy the less one for the rank D, and add an L statement and then paste it here. For C, we know that if it's greater than 57, and at the same time, it is 72, then we want to print C. Here for the greater value, I want to include the 72 float here, so I'm going to add an equal sine and also add equal sine two, this one here. And for D, we want to check if it's less than 57. So let's just type D here. Let's save this. And now we have this method created. We need to run this method inside the show en screen method. So after we set up the accuracy text here, I'm going to run the calculate score method and then pass all of the argument here. Let's just pass the enemy kill, the total enemy, the hostage kill, the total shots, and also the total hit and save this, and let's go back to Unity and test this out. Now here inside Unity, first, we need to select the game manager, and then open the end screen object here, open the lay out. And for the score area, we want to open the rank and it has a title and a R game object. We want to direct this ring game object as a rank tax of our rank tax field under the game manager component. Let's just direct the rank tax here. And it has a text mesh pro, so the fields register the component right away. And now let's save our scene here. Now let's test this out. And I'm going to try to play as fast as possible without shot mist and hostage kill. Let's just use this to kill the enemy, use explosion. And let's just enable the debug here, so we can see our stats, and let's kill the enemy. There you go. We have a perfect stats over here, and now let's kill the enemy here. Now as you can see here, we have a very nice stat and we have R A. But if we test this again and now try to do our best again, but kill the hostage this time. And now, as you can see here, even though we have 100% hostile accuracy or enemy kill accuracy, and also the accuracy. But since we killed two hostage, we have a rank of C. So killing hostage will penalize by a large amount, which is 15 points. And now let's test this one more time for the shots accuracy. Let's just try to shots e, so we have a very bad accuracy, and let's try to kill the enemy. And as you can see here, even though we kill of all of the enemy, our accuracy is very low, so we have rank of C. Okay, so that is basically how we calculate the n of the gameplay. 43. 42 Pause & Volume Setting: This time, we are going to discuss a past mechanism and also create a folum settings when we open the past panel. So in order to do that, I've already prepared a pause panel UI package, and you can download it in the resource of this lecture. So after you don't know this, just import the package, so I'm going to import a custom package, and I'm going to import the PUI package. And now just import all of them. Once it's imported, you see here under the U PAC folder. Under the prefbs, we have a new prefps, and it's called pause screen. So now let's just drag this prefs onto the cross hair Canvas. If we go to the scene view here, if we want to see the pos screen, we need to enable it first because it's disabled by default. Let's just enable this and you'll see that we have this pus UI and it has two volume slider, which is a slider object, and we are going to tie the audio mixer groups with this slider. The next thing that we need to create is, we need to create the audio mixer. But before that, let's just disable the Po screen again, and let's go to the audio folder, and let's just create a new audio mixer. I'm going to create a new audio mixer, and I'm going to call this main mixer. Now let's double click the mixer here. Once the audio mixers windows is open, we have this few here, and we need to create a couple of groups here. So let's just select the master and then press the plus button here, and let's create a sound effects group. And select the master again. And the next group that I want to create is the Begron Music Group. So now we have two additional volume here. And now if we go to the game manager under the audio player, it has two fields called Sound Effects Group and Background Music Group. We need to assign this object to the slot here. So let's just bros this, and then select the sound effects group for the sound effect group slot. And for the Begron Music Group, let's just select the background Music group mixer. Okay. Let's save this. And now we need to create a new script. So let's go to the scripts folder. Under the audio. I'm going to create a new script called Volume settings. And let's open the script. Okay, now we've opened the script here. Let's create a couple variable first. But before that, we need to import the Audio name space and the UI namespace. Here above, let's just add using Unity Engine not editor engine, and let's just import the Audio namespace and also the UI namespace. And let's just remove the mono behavior inheritance here because we are going to instantiate this script or class on the game manager like the UI manager class and the timer object class. And let's just delete the built in method. And now we need to declare a couple of variables. I'm going to create a new serialized field. And this would be a type of game object, and let's just call this panel. And the next field will be a slider. And this would be the sound effect slider and the BGM slider. And the last field that we want to create is the audio mixer field. And let's just call this main mixer. We also need to create a private string for saving the value of our volume to a player preference. Whenever we restart the game or we enter a new session, it will load the previous volume setting. Let's just create a new private string. The first one, I'm going to call this sound effect key, and the second one would be the Background music key. We want to also create a getter for the panel. I'm going to create a new public game object geter here. I'm going to call this panel with capital P, and inside the getter, I'm going to retrieve the panel field. So we can access this panel from other script, but other script cannot change the value. So the next thing that we want to create is we want to create a new method to modify the sound effects and the background music. So let's just create a new void, and let's just call this aj sound effects. And we want to pass a float as the value here. Because this method will be called by the slider, both of the slider on change event. We need to pass a float value here, and this parameter, we grab whatever the slider value whenever we change the slider. Before we can modify the mixer, we need to expose some of the parameter on the audio mixer. Let's go back to Unity, and let's go to the audio folder. And let's just select the main mixer here. And if we open the mixer, we can select the sound effect group and the background music group. And now we want to expose the parameter. Here, as you can see, we don't have any expose parameter yet. So in order to expose a parameter, we can select the mixer, and then under the volume name here, under the inspector, we can right click this, and then we can expose the volume to a script. And if we have this arrow sign, it means that this parameter is expose. So now if we press the post parameters button, we can see an post parameter. We can rename this. So I'm going to double click on a name and then rename this to SoundEx volume. And then I'm going to select the Background Music Group and also right click here, and then I'm going to expose this. Now we have two exposed parameters. For these new parameters that we've created, the volume of the Bagrand music group. I'm going to rename this two Bagran Music volume. Now we have two parameters. We need to remember the name and the capitalization of the name because it's important. Now let's go back to the script here. Now we have expose those parameters. We can access the main mixer, and we can set its float, and it as for the exposed parameter name here, the string name. Let's just pass the sound eff volume name. And for the value, we want to pass this value here. So let's just pass the value. This way, when we are changing the volume by dragging the slider, this method will gets executed, and the value of the slider will be passed via this parameter, and this parameter will modify the sound effects volume. The next thing that we want to do is, we want to save the value of the slider. Let's just use the player prefs class and it has a set float method, and it as for a string key, and this is where we are going to use the string that we've created. For the sun effx key, we are going to use the key here. And we want to save the value. And after that, we want to save the player prep. So let's just run the safe method from player prefs. We need to insert a string here, I'm going to create a string. Let's just call this sun effect key, and this would be the Background music key. I purposely make this as a private, so the value can only be changed inside the script, cannot be changed in the inspector. And this way, the value will be more consistent. The next method that we want to create is we want to create the a Bground music volume here. Let's just copy all of this here. And I'm going to paste it here, and then I'm going to rename the method to adjust Bground music, and we want to change the float, which is the Background music volume. And for the key, we want to use the Big GM key here. So we want to save the value to a separate key in the player prefs. So let's just paste this here and save this. Now we have this two method. We need to assign this method to the slider, so we need to create a new public init method. And this needs to be public because this init method are going to be executed from the game manager. So here, first, we want to access the Son effX slider object, and then run the value change event, and we want to add listener. And we can pass the method to his listener here. So let's just run the S Soon effX. And you see that this ad listener has a float signature. Unity event float, and we need this method to have a float parameter because it asks for a float here. For the Background music slider, we want to do the same, so let's just access the on value change event, and then add the listener, which is the JS Background music here. Okay, now we've created this. This should work, but there are still things that we need to add here above, we want to load the volume settings that we've saved from the player prefs. So in order to load the volume, we can just run the adjust method, which is the sound effects, and then we can pass the value here. So in order to load the player prefs, we can just access the player prefs class, and then use the GT float method, and we need to retrieve by using its key here. Let's just pass the Sound ex key string. And there is overload, which if I just select the overload here, you'll see that we can pass a default value. So if there are no value from the player prefs, we can just pass the default value, which is it can be anything, but I'm going to set this 20. And I'm going to run the jazz Background music method, and I'm going to pass the player prefs, also the Get float method. And here, I'm going to grab the Background key and then set the default value also to zero. And now with this setup, we load the default value or the safe value of our volume both on the sound effects and the background music. But we want to also adjust the slider value to this float value here. Let's just access the sound effect slider and grab the value properties and then pass the value of the player perps here. I'm going to copy this line here and then paste it here. And for the background slider value, I'm going to pass the second get float here. Okay. Now we've set up the folum setting script. Let's go to the game manager and create a new SS field to instantiate this class here. Here below the UI manager field, I'm going to create a new suralS field, and this will be the Folum settings, and I'm going to call this all setting. And then let's just initialize this and save this. Here in the game manager, we need to create a new public properties type of b. Let's just create that. I'm going to create a public b and I'm going to call this game paused and this will be a public get, but a private set. It can be only set from this game manager script, but all of the other script can get its bulion value. And here inside the init method. We want to initialize the volume settings. Let's just access the val setting and then run the innate method. And this will execute this innate method. And now we want to modify the update method of our game manager class. So let's just crawl down here, and we've already have a update method. Here, let's just create an I statement, and we want to check for a key down. So let's just use to get key down method. And I'm going to pass the key code escape for pausing. And here we want to modify the time scale of our game here. Let's just access the time scale. And we want to check if the time scale is equal then zero, then we want to set the time scale back to one. Otherwise, if it's not zero, then we want to set this 20. And whenever we are pausing, we want to enable the panel of the volume setting. Let's just access the fs setting object here, and we have the panel properties. Let's just run the set active set and then pass the time scale equal zero. So this means that if this conditions is true, that we want to activate the volume panel, and if this falls, the volume panel will get the activated. And we want to also set the game pas bulion properties to this value also. I'm sorry, there is one thing that I forgot here, in the volume settings. We need to mark this as sterilizable. Let's just use the system s attribute here and save this. Now this should work, and let's go to Unity. And here, once the script compiled, You see that we have this volume settings field, and it has a lot of fields. So first, for the panel, we want to drag the pus screen panel. And for the slider, let's just open the pus screen, open the layout object, and we have the slider for the sound effect. So I'm going to open both of the slider game object and then drag the slider for the sound effect to the sound efflder slot. And for the Background music, I'm going to drag the slider to the background slider slot. And for the main mixer, we need to browse this from the project. So let's just use this circle button and then pick the main mixer from the assets. And save the scene. And now let's give it a try. Let's press play, and see if we press escape, the game pause, and I can change the volume here. I can still shoot because we haven't prevented that. But in a moment, I will show you how. Now let's just try to lower the music. There you go. If we Push the slider. You can see we have lowered the music volume, and we can increase it. So I'm going to set this to this position here, and let's set the sound effects to a louder volume. Yeah. And we can also make it smaller. There you go. And if we sat at this position here, and then we stop. And if we press play, and then we pause again. The value gets loaded, as you can see here. It gets the volume settings from the player craft. So we can save this. And this settings is also safe throughout different session. Okay, let's check the console for any errors. So far, no errors. That's good. The next thing that we want to do is we want to prevent the player from shooting when it's passed. So let's open Visual studio, and let's open the player script. And if we go to the top here under the update method, we have this line, and this is actually executing the update from the scriptable object of our current active weapon. And we can add a condition here. We can check if the game manager instance Game pause is false, and we can just add an exclamation mark in front here, and this means that if this value is false, then we want to run the method update. But if this value is true, then we want to skip this code here. And let's save this, and let's head back to unity. Now, when it's finished compiled, let's test this out. And let's try to pause a bit later when the enemy arrives. So now it's pause. All of the element game is pause here, and we cannot shoot. As you can see, there are no shooting sound, and the mo also doesn't decrease. Okay. Yeah, that is basically how we create a pause mechanism and also a volum settings. 44. 43 Player Dead Setup: Now in this video, we are going to create a death mechanism. Currently, we don't have that, so whenever our health goes to zero, the game continues, we need to add those features. So let's go to the fisal studio. And the first thing that we want to modify here, we want to go to the game manager. And inside the game manager on top here on the field area, we want to create a new public bull properties for declaring whether the player is dead or not. So let's just create a new public bullion, and let's just call this player dead, and we want to also set this to a public getter, but a private setter. And here, inside the hit method, the player hit method, we want to check if our current health is zero or not. Let's just create an if statement, and if the current health is less or equal to zero, Then we want to run the show and screen method, and we want to also set the player that bul thru. And this will be set to false by default. So we need to change this two true whenever the player is dead. We need to modify a couple other script, and I'm going to modify the enemy script. So let's just open the enemy script. And here inside the shoot t here, inside the wil loop, I want to check for the player is that state. Let's just access the game manager. Statics reference, which is instance, and we can just check for the player that value. And if the player is dead, we want to stop shooting, and the stop shooting method will execute the stop all co routines method actually. So this co routine will gets canceled, and the enemy will stand idle. Save this. The next thing that we want to modify is the player script. Basically, here, we want to also add a condition when the player is alive, then we want to run the weapon update. Let's just add an N condition and check if the game manager, instance player is dead is false. This way, when the player is dead, the player won't be able to shoot anymore. Want to also stop the player from moving whenever the player is dead. Currently here in the shootout point. You see that whenever this gets triggered, the player will continue moving. And this is a problem because when we enter the shootout, we have a delayed action to run the set area cleared method. And this won't be canceled if the player is dead currently. This will be still running this core routine here. So we need to cancel this here. We can just add a condition here, A or condition. If the game manager instance and player is dead, then we want to return this. The method will still get called by this delayed action. But when it's called, if the player is dead, it will return, then all of this code here will be skipped. Let's save this. The next thing that we want to modify is the time or object here. Here inside the timer object, we have this core routine that runs the timer. This also won't be canceled whenever the player is dead at the current state. So we need to add that here inside the wild statement, we can just check if the game manager instance and player is dead, and if it's dead, then we want to break this core routine. We can just break the cotine using the yield break statement here inside the coroutine, and this will cancel this core routine here. Now let's continue modify the last script that we need to modify, which is the UI manager, so I'm going to open that. Here inside the UI manager, we have this show end screen, and we need to fix this. Because basically whenever we finish the game or whenever the player is dead, we are going to show this end screen. And there is a possibility that this total shots value will be zero, and this will cause an error. So we need to check if sorry I'm going to create a new sets of parents here. And I'm going to check if the total shots it's equal to zero. Then I'm going to pass value of one But if it's not zero, then we want to pass the value of the total shots. So let's save this, and this is a ternary operator. And here, we also need to fix the accuracy ratio on the calculate score. Let's just copy this line here, and then paste it here since it's used the same variable name, so this should work right away. And now we want to create another LSF statement. But I'm going to create this above the rank D here. So let's just create new LSF statement, and this time if the total average is equal to zero, Then we want to pass n of E. So let's just define that this is the lowest ran possible. Let's save this. Now we modify all of the script here. Let's test this out. Let's go to Unity and let's run the game. I'm going to pause and then lower the music and then continue. And now let's just stay still and receive enemy shots as much as possible. So we can test if the player is dead. There you go. Now, we've been killed and the enemy stop shooting. The times stop. We cannot shoot anymore. And since the times stop, the game will not progress. So this is how we create the dead feature. 45. 44 Title Menu Scene: Now let's create the title scene. In order to create a title scene. Let's create a new scene here under the scenes folder. So let's just create a new scene, and let's just call this title scene. Let's open the title scene. With the title scene open, I'm going to select the camera, and I'm going to set the clear flag to solid color. And I'm going to change the breakdown color to black. We won't be seeing the sky box, and now let's save the scene. The next thing that we need to do is we need to create a Canvas. I'm going to go to the UI menu here and then create new Canvas. For the canvas object under the Canvas scaler, let's change this to the scale with green size and set the resolution to 1920 by 1080. This is the re resolution that we are using, and for the match properties, let's set this to 0.5. It will be balanced between the width and the height. And I've already prepared a couple of prefbs for the title scene. So let's just import that. I'm going to include the file in the resource, and here I'm going to import package, and it's called Title UI package. And when importing this package, make sure that you don't import the funds, just select this, and just unselect sprite also. Because we already have this in our project, it might mess up the project. So let's just import the UI pack folder here. Now that we have import the prefabs, let's go to the U IPAC. Under the prefe we have a new prefs. One is O option menu, and the other one is title menu. We want to put the title menu first. Let's just drag the title menu to the vas game object, and you can see the object here. There is an issue with the button. In order to fix this, let's just expand the title menu prefs, and it has these three buttons, the start Option and quid, and it's missing sprite. So we need to generate a transparent sprite. In order to do that, let's go to the Sprite folder under our UI sprite. We want to open this sprite editor, and I'm going to drag a new sprite here to an empty area, and size. It doesn't really matter. And I'm going to rename this sprite to UI underscore sprites, underscore transparent. Then once we've renamed this, let's just press apply. Now that we have a transparent sprite, we can use this transparent sprite. As you can see here, because I put the same name with the one where I set up this prefabs here. Now it occupies automatically. But if you are using a different name, you can just select all of the button here from the start to qui button and then just pick the source image using the transparent sprite that you've generated. Now this button already set up properly, it has a different selected sprite here. If we press play, you'll see that if we click on the button, it has a border. We are going to use this to move using the keyboard up and down. Now, let's stop this. The next thing that we want to put is the options menu. Let's just put the options menu to the Canvas game object, and now we have this nice options menu. Here under the option menu prefep, we have a lot of child object. Here under the options, we have an entry, the first entry, which is the resolution, and the second entry is the quality. And here we have a drop down for the resolution and also drop down for the quality. We are going to populate the drop down using a script, and we are going to retrieve all of the resolution supported on the player PC. And for the quality, we are going to grab the quality settings from our project setting. If we go to the project settings here, and under the quality, you see that we have this. We want to grab this and then fill this dropdown based on this value here. And we want to make sure that this dropdown can change the resolution and the quality on the final built of the game. Now let's save the scene and we need to create a new script for the title scene. Now let's go to the scripts folder. I'm going to create a new subfolder, and I'm going to call this title scene. Here under the title scene, we want to create two new script. The first one will be the title menu manager. Let's just create that one. And the other one would be the option script. Now let's open this script here. I'm going to open the option script first. Here inside the option script, we want to create a new variable for holding the drop down. Let's just create a new serials field. For the type, I'm going to type the name space of the text Mash pro because the drop down is the text mesh pro dropdown, and here we can just use the TMP dropdown class. And let's just call the first one resolution drop down, and the second one, quality, drop down. Then we want to create a new private variable for holding the resolution data. Let's just type private resolution. And this will be a array, and I'm going to call this resolutions. Here inside the start method, we want to grab all of the supported resolutions on that PC. Let's just type resolution, the array that we've created here, and then we can just fit this with the screen class resolutions. This will return all full screen resolutions supported by the monitor. Let's just use this. Here we want to create a new list of string for holding the options or the resolutions in the string format, so we can fit this list of string to the resolution drop down. Let's just type these options and let's just initialize this. And then we want to look through the resolutions that we've just grab here. Let's just pass the resolution and grab its length. And for every resolutions, we want to create a new string to be added to the options list of strings here. Let's just call this rest, and for the string, we want to grab the resolution index of I width, and we want to add this with a string x with a space on the both sides of the x character. And then add this with the resolutions index of I and it's with value. The next thing that we want to do is, we want to add the string to this list of string here. Let's just add the rest string, and this will fill up the list of string options with this string, but with all of the resolutions that the current monitor supports. Here below, we want to grab the resolution drop down, and then we want to run the clear options method. This will clear any previous options. Then we want to fill the drop down with a new options using the At options method, and it asks for a less off sprite or less off string. So we can just pass the options here. And now we want to set the resolution drop down value to the current selected resolution or the current active resolution on that monitor. In order to do this, we need to create a new integer variable, and let's just call this current screen resolution ID, and set is 20. And here we want to check if the screen and let's just grab the current resolution and grab its width, and we need to compare both of the width and the height with the resolutions value at index of I. For the width, we need to compare with the width of resolutions index of I. If the value is equal, we need to also check the height. Let's just add an n operator, and let's check for the screen current resolution equal to resolutions, index of it. I'm going to break the line here, so it's easier to read, and if both of the condition is true, then we are at that resolution. We want to set this current screen resolution ID to the value of I. Now we have set this value. We want to go here below and access the resolution drop down, and we want to set its value to this integer here. Let's just pass this here. And this will set the drop down to the active resolution. And now we want to populate the quality dropdown. This is much simpler, so we can just access the quality dropdown and we can clear the options. For adding options, we want to access the quality dropdown again, run the add options method. Then we want to pass the quality settings, and Quality settings class has an array of string called names, and this is the index list of available quality settings. But since it's a string array, we need to convert this to a list because at options as for a list of string. And if we just pass the array, it will throw an error here. In order to convert this to a list, we can use a namespace system link inside the link namespace, we have a two list function. We can use this and this will convert this string to list. Here, we want to set the quality drop down value to whatever quit settings that we are currently set at. Let's just set the value here to equal the quality settings class, and we want to get the quality level. And this will return an integer of the index, the quality that we are currently set at. Let's save this. And here, let's go back to unity, and let's give it a try here. First, I'm going to put the option script to the Canvas game object here, and let's just open the option menu, and for the resolution drop down, we want to pick the first drop down, and for the quality drop down, let's just drag the second drop down. We cannot test the resolution dropdown because it only works on a build, but the quality dropdown, we can test this on the editor. So let's just open the project settings. Currently we are at fantastic if we press play Now, you see that we have a lot of resolution here. And we also have all of the quality settings, which is the fastest, fast, simple, good, beautiful, and fantastic. And we are currently set two fantastic. And here, if we change this, nothing will happen right now because we need to register a method where we are going to change the quality settings to this dropdown listener. So let's just do that. Here we want to create a new public method. Let's just delete this update method. We are not going to be using it. I'm going to create a new public method, and I'm going to call this set quality. And I'm going to pass an integer variable. Let's just call this quality ID. And here we want to access the quality settings, and we want to set the quality level, then we want to pass this quality ID here. And save this. And now we want to assign the listener for this quality dropdown, whenever the quality dropdown gets changed, we want to run this set quality method. And whatever the value gets changed in this quality drop down, we want to pass that value as the quality ID here. So here on the start method down below, we can just access the quality drop down, and then we can search for the on value change event here. And then we can run the ad listener method, then we can pass the set quality method. And here, as you can see, it asks for an action with a signature of integer. So it's a method. But with an argument, that is an integer. So if we have another method that doesn't have an integer as the argument, this will throw an error. And the way this work is, whenever we change the quality drop down, are changing the value. So when we are changing the value, we are actually changing the integer, representing the options from zero to the maximum length of the options. And whenever we change those value, those value are being sent to this method here to the set quality method. And when we run this method, those new values are going to pass as an argument here, and this argument will change the quality level on our quality settings here. And now let's create a set resolution method. Here, let's create a new public void and let's just call this set resolution. For the resolution, we also want to pass an integer. Let's just call this resolution ID. And save this. And for the set resolution, we want to create a temporary resolution data. So I'm going to call this RS, and I'm going to grab the resolutions array, and we want to grab the ID that we've passed here. So let's just pass the resolution ID. And this works exactly like the Set quality method. This will be registered to the resolution dropdown on value change listener. And now once we've grab the resolution, we want to apply this to the screen Set resolution method. For the set resolution method, it asks for a integer of width integer height and the Boolean full screen option. Let's just pass the rest width and for the height, we can just pass the rest height. For the full screen, we can just access the screen f screen. Let's save this. And we want to also register the set resolution to the resolution drop down. Let's just type resolution drop down and access the value change event and add the listener and pass the set resolution method. And now we've set up the listener for the resolution drop down. I've noticed there is an error in my code here, here, in the string res. This should be the height. Let's just change the second resolution parameter to the height value and save this. Now if we go back to unity here, and then if we try to run this, let's open the project settings. And let's try to change the quality here. If I change the quality to simple, you see that we've changed the quality settings on our project settings. And this will affect all of the visual fidelity that we have set up here or that Unity have set up here. It will lower the texture depending on the quality that we've. Yeah, we are going to continue finishing the title scene on the next video. 46. 45 Title Menu Continued: Now, let's connect all of the button, so we can start the game or we can open the option panel, or we can quit the game. In order to do that, let's open the title menu Manager script. Here inside the title menu Manager. Let's create a new variable, and let's set this two game object, and this would be the option panel. And the other variable that I want to create is a string variable, and I'm going to call this game play scene. And we want to also add a serize field, and this will be a button. But in order to use button, we need to import the UI namespace. Let's just automate this here and need to automatically create this. I'm going to create a new start button, option button, and then option close button, and the last one would be the Qi button. Let's delete the update method. We won't be using that. Here we want to create a couple method. The first one would be the start game method. And the second one would be the open option panel. The third one would be the closed option panel method, and the fourth one would be the quid game method. For the Quid game is quite easy, actually, we can just access the application class and then run the QID method, and this will quit the game on the built standalone game. It won't do anything on the editor. And for the start game, we want to load the gameplay scene based on its name here. So we need to import the scene Manager Name space. I'm going to type using Unity engine Scene Management. And here inside the start game, I want to make sure that we cannot start game if the option panel is open. So we want to check if the option panel is active in hierarchy, then we want to return this. But if it's not, then we want to access the scene manager class, and then we want to run the load scene method, and we can pass either the scene built index or the sen name, and we are going to pass this string here. So we can fill the scene name on the inspector and save this For the open option panel, I'm going to access the option panel, and I'm going to run the set active method, set the value to true for closing the option panel. We can just access the option panel game object again. Run the set active method and then pass the false value. Whenever we are closing the option panel, we want to select the option button. Let's just access the option button and then run the select method. And select method will set this button to be the selected button on the scene here. On start, we want to set the start button to be the selected one, using the select method. Then here we want to assign all of this method here to this button here. We can just access the start button, and then we can access the unclick event. Then we can add listener. And here we want to pass the start game method. For the option button, we want to also access the click event at Listener, and we want to open the option panel here. For the option closed button. We want to pass the closed option panel method. The last one for the quid button, we want to pass the quid game method as the listener here, and save this. Here inside the start method, we also want to hide the option panel right away. Let's just access the option panel on start and then run the set active method, past the false value as the argument, and save this. Now we've created the Title menu manager script. Let's go back to Unity, and let's add the script to the Canvas game object. Set the Canvas game, direct the Title menu manager, and now we need to populate the variable on the inspector. Let's go to the scenes folder and I'm going to type the scene where our level is, which is the sample scene. For the option panel, we can just drag the option menu here. As the game object. For the start button, we want to open the title menu and drag the start button here. The option button, we want to drag the option button. For the quid, we want to drag the quid button. For the option close button, we want to pick the button from the option menu prefabs here. Let's just drag this button here. This is actually this button here. We want to close the option panel whenever we click this button. Let's save this. Now let's give it a try. It will start the scene with the start button selected, and if we go down, we can select other options, and if we select the options, this will open the window here. If we press okay, it will close this again. Let's stop this, and let's fix one thing here inside the title menu manager, whenever we open the option panel, we want to select the option close Paton. Here I'm going to access the option close Paton, and then I'm going to run the select method here and save this. This time, whenever we play this, and if we open the option panel, This will automatically select this patent here. If we press enter, it will close again automatically. We can navigate the menu of the title scene without mouse. Now let's test this again, and let's press start. Currently, the load scenes won't work because we haven't set the scenes that should be included in the build setting. In order to fix this, we need to go to the file menu under the build settings. Let's just drag the scenes that we are going to include in the build. I'm going to drag the title scene here and also the sample scene. I'm going to save the project. Now if we press play and if we press enter on start, you see that it will load the scene here. Now if we go to the sample scene here, we need to also have a way to go back to the title menu or the title scene once we finish the game. In order to do that, I'm going to open the game manager script, and let's just go to the UI Manager script here. Here under the sore properties, let's just create a new serialized field, and this will be a type of button, and let's just call this back button, and we need to create a new method to go back to the title scene. Let's just create a new private method, and let's just call this go to Title scene. And we want to use the scene Manager class. We need to import on top of our class here. Let's just type using Unity engine scene Management and below the button variable here, we want to create a new string field, and let's just call this title Scene name. Here below on the go to Title Scene method. We want to access the scene manager, Load scene, and then we can just pass the Title Sen name here. We need to register this method to the back button that We've created here. Inside the init method, we can just access the B button on click event and then add listener, and then we can just pass the method go to Title Sen Method here. And save this. Now if we go back to Unity, we need to set this back button and the title C Name. For the title C name, we can safely type title scene, and for the button, we want to expand the game manager and open the Canvas. Under the end screen here, we want to expand this, and we want to drag the button as the back button here, and save this. Now let's just play this to test this modification that we've just created. And this is not working because the crosshair is blocking the cast. So we won't be needing this cast target under the crosshair game object. We can just safely disable this. Now if we disable this and then we try to click the back button, you see that it will work. So I've stopped the game here, and since I've changed the options on the run time, we need to set this back here. Let's just select the crosshair and check the RC target. Okay. Now here, we can go back to the title scene and from the title scene, we can also go to the gameplay scene. 47. 46 Build the Game!: Now we are going to finalize the game. We want to build the game into a standalone apps. It's quite easy, actually. We can just go to the file, build settings, and then press this built button here. We can decide whether we want to set the architecture to, the 64 bit or 32 bit. This all depends. If you are using two bit, you will have a wide range of audience that are using windows two bit also included. Because if you built to 64 bit, then the built won't run on Windows 32 bit. In the future, I think all of the user will switch to 64 bit. So I'm going to lift this 264 bit in my case. And the next thing that we want to do is we want to open player settings here. And here we want to change the company name. So I'm going to change the company name to my name here. And for the product name. I'm going to change the product name to the name of the game, which is nexus. Version, you can just set this 21. We will also need to apply the default icon. I've already prepared the icon. I'm going to go to the texture folder here and I'm going to open my icon here, and I'm going to include this icon in the resource folder, and let's just track this icon into the Textures folder. Now we have import the icon. We can pick the default icon and pick the app icon here. And the next thing that we want to set up is here under the resolution and presentation. We want to disable the display resolution dialogue. Let's just disable this. And now that we have set up the player settings, let's just check for the other settings. A looks good. And if you want to change the bundle identifier, you should do it here. So we can just set this to the company name, which is my name, and then for the game name, you can just type the game name. That will be all for setting the player settings. And now let's just save the project, so all of the player settings get saved. I'm going to import a free asset from the asset store for the bugging on the build. If you go to the asset store, you can search for log fewer. And this is a really good asset. You can use this, No this one, but this one here, the log pewer, it's free. And basically, we can show the console on our built. This is really helpful when you are debugging your built. So let's just import this. And now once we have impart the package, we can go to the Unity logs viewer here and we can check the Rhythm. So let's just show in the Explorer and let's just open the Rhythm file. And here, as you can see, in order to use the console logs, you can just make a circle gesture using your mouse, click drag or your finger on the mobile. Now let's add the assets into our start scene here. Here we have a new menu called Reporter, and let's just press create, and this will automatically create a game object to enable the logs on the build and save the scene here. Now we've add the reporter to our scene. Let's just create a sound modification on our option script and the title menu manager. Let's go to Fis Studio, and I'm going to add a sound for the clicks here. Here on the option script, let's just create a new Sudo S field, and this will be the Audio ger. And let's just call this click sound effects. Here, whenever we change the resolution or setting the quality, we want to play that sound. So let's just access the audio player instance and run the play sound effects method, and then we can just pass the click sound effects without transform. This will be a two D sound and we can just duplicate this line here, and then paste this here inside the set quality method. Now we want to also add the sound into the title menu manager. Here, whenever we start the game, we want to play the click sound. And also we want to play the click sound whenever we open the option panel. Also whenever we close the panel and whenever we quit the game. But we don't have the click sound effects variable defined here. Let's just copy the one that we have here, and then paste this here as a new field and save this. Now let's head back to Unity, and we need to import the click sound also. I'm going to go to the game folder under the audio. I'm going to open the file here. And I'm going to include this new sound on the resource folder. So here we have the UI button dot wave. Let's just direct this to Unity, and then put it the file inside the audio folder. And now we have this new sound. Let's go to the data folder and update the audio library. So I'm going to add a new entry, and for the last entry, I'm going to set this. I'm going to call this UI button. And let's just pick the UI button dot wave here. And let's save the project. Here in the title screen, we want to create a new empty game object for the audio player. I'm going to call this audio player, and I'm going to add the audio player component. For the library, I'm going to pick the audio library. And for the audio source number, we don't need six audio sources, so we can just set this 21, and we can set the mixer to the mixer that we've created before, and save the scene again. Now if we go to the Canvas game object, we'll see that we have the click Son effect. Let's just change this two DUI button, and for the title manager, let's just also change this two DUI button, So effect. Now save this, and now let's build the game. Press bill settings, and then press bill. And here we can just select the built folder. I've already created folder and choose select folder. You can just create the built on any folder that you want. Create a new folder and select that folder. Now it's building. I'm going to cut the video and we will continue after the building is finished. Okay, now it's finish built and Unity automatically open the folder. So now we can test this. And now let's try the option panel. And somehow it doesn't work. Let's try to quit. Okay. There is an issue here, and we need to check for the issues. That's why I've installed the log viewer. We can just create a circle motion using the mouse by click and dragging and once There you go. And as you can see here, there is an issue here. You see we have an error, and let's just check this here. Okay. There is an issue with the audio getter sound effect here. So when we run the open option panel, somehow it cannot play the sound effects. So we need to fix this, and there is a couple of error here, as you can see. So let's go back to Unity. I'm going to quit the game by pressing F four. Okay, so I suspect the issue is on the audio getter class. So if we open the audio library here, in the audio getter, whenever we retrieve the audio name, it actually retrieve from the audio names list of string here. And this is actually a static class, as you can see here, and if you go above here, you'll see that it's actually a static class. The problem with this code here, the unvalidate only runs on an editor, whenever we change the value in the inspector or whenever we select the object in the project panel. But this never gets executed on the build. So we need to make sure that we execute this code here on the build. Luckily, in a scriptable object, we can force this by adding the awake method. And inside the await method, we can just add the validate method. So this will call this method here, and then we'll populate the static audio name list here. So once it's populated, whenever we are retrieving the audio name to play the sound effects, this static list of strings will be available, and it will return the correct string. And there is another issue that I've noticed on the built. On spawning the enemy here, we will have one frame of missing reference of the ym component here. And this is happening because the animator move can be executed before start. So we need to make sure that whenever the animator move is executed, we need to check for the anim object reference here. So here I'm going to add an if statement and if the enim is null, then we want to return this method and save this. I've know this because I've checked the built before, and this will cause a minor issue. It's just a message, an error message, but it would be best to also prevent this kind of error. So let's just add this line here and save this. Now back here in the unity. I'm going to try to build this one more time. But before that, I'm going to go to the project settings folder and under the audio. I'm going to set the global volume back to one. I've set this to 0.05. So on the editor, it doesn't chow out, but I'm going to set this back to one. And I'm going just to meet the audio here on the editor. It's okay, and I'm going to save the project. And now let's just build the game one more time. Now the game is built, and let's just run this. And now I'm going to try to press the option, and there you go. We have the sound playing. And now if you change the resolution, you can see that it lowers the resolution and we can just switch back to the maximum resolution. You can pick a resolution, for example, this one. And we can also change the quality. Here. I'm going to change it to fantastic and press. And now let's start the game. Watch. Watch it. Now, let's test this. Let's go back to the yeah, there is one issue though. When we go back to the menu, we cannot see the mouse cursor here. Let's just fix that. And here if you go back to Unity, go to the is studio here. Under the UI manager, we are hiding the cursor on start of the level. So let's just copy this line here, and we want to make sure that the cursor is back visible on the title screen. So we can just add this line here to the Title menu manager. And inside the start method of Title menu Manager, we can just add that line and set the cursor back to through and safety. Okay. So yeah, that is basically how we create a real shooter games in Unit, and that is basically how you prepare the build. One tip from metho, whenever you finish testing the build, you should remove this rapporteur game object. So the player cannot enable the console debugging on the built by accident. But for the development built, you should leave this portur game object on the scene, so you can always debug the development built. I want to thank you all for enrolling in this course. If there are any issues or any bugs in the game, please report to me, and I will update the course to fix the regarding bugs because I know as a person, I'm not a perfect person, I can make mistake in this course, so I really appreciate any input from all of you guys. Thanks again, and I hope I'll see you on the next course of mine. 48. 47 Area Cleared Bug Fixing: Hi, in this up date video, I'm going to show you a fix of a bug that has been reported by Kyle Cooper. Thanks a lot for reporting this. So basically, in the shooter game that we have here, the area clear mechanics has a bit of issue. That is, if we select the main camera and we set the Inspector bug here, we can see that the area clear is not clearing correctly. So for example, if I press play now, And in this example, I've set our health to 100. So it took a while before enemy kills the player just to debug this. And here, I'm going just to kill one of the enemy here. And I'm going to lift the time as it is until it runs out and we can check the area cleared value here. So here you see that the area cleared doesn't get increased. So now we cannot finish the game in the state, even though we have fh cleared all of the area. And this will cause a game breaking bugs, actually where the stat panel doesn't get shown, and we cannot progress further in our game. Because we have in this scene, I have three shoot out groups and the area cleared only increased to two so far. So the value never gets equal, and this never triggered the UI. So in order to fix this, let's go to the Fisial studio here, and on the shoot out point script here, Basically on the set area cleared method, we need to call this player move area cleared. So basically, this is calling this method on the player move script here, and we need to do the same in this code here. So I'm going just to copy this line here and paste it here above the area cleared equal to true method and safety. And this will fix this issue because whenever the timer runs up, we are going to call this set area cleared method. And now let's give it a try. And take a look on the area cleared variable here. Let's just kill one of the enemy and leave the other ones alive. Okay. Now you see that the area cleared gets increase, but there is another problem. If we kill this enemy, then our area cleared increase 22, even though we haven't cleared the second area, and this will cause issue where whenever we cleared the second area, it will show the end game screen, and we don't go to the next pine here. So in order to fix this, Basically, we need to go to the player move script here, and we need to add a Boulan in this method. I'm going to add a Boulan argument, and I'm going to call this previously clear. Basically, I'm going to check if the previously cleared value is true. I'm going to return this function. So now we need to pass a bulion into this method here, and we will have an error in our shootout point script. Here in our shootout point script, basically, whenever we call the area cleared method, we need to pass this area cleared bulion properties. So I'm going to pass this here. And basically, this will pass the bulion to this method here. So if we haven't cleared the area yet, then this bulion will be false. And whenever we run this method, all of this coat heil will gets executed. So we are going to increase the area cleared value, and we are going to trigger the event and we are going to continue the player movement. And if this, for some reason, gets executed again, for example, if we cleared the area, then this method will gets called, and the area cleared will be passed, and this will be false because we haven't changed this value true, and we changed this after we are calling this method. But for some reason, during the transition to the next area, we killed an enemy and we finished killing all of the enemy. This will get called either. But now with this bulion check, the area cleared will be true previously, even though we are setting this to true because it has been already changed to true previously here. So if this value is true, then basically this will skip all of the code below, and this will not be called anymore. And this will prevent the area cleared increasing more than once in a same shoot out point here. So if we go back to unit here, I'm going to run this again. Now we can take a look on our area clear variable. And let's do the same here. I'm going just to kill one of the enemy here on the first shoot out point and leave the other ones alive. And once the times runs out, let's try to kill the enemy. So now the area cleared is increase here, and let's kill the enemy. And now once I've cleared the enemy, the area cleared stays 21. It will be only increase on per area, and now I can kill this one here, and now we have cleared two area. And then for the third one, if we kill this enemy here, it will show the stats. And now let's make another try. And this time, let's just leave the second enemy alive on the first area here and don't kill it, even though we are transitioning to the second area. So I'm going to check against every possible scenario in our game. Now the time is runs up. Let's continue playing the other area here. And it counting correctly. The area clear variable here. Let's just kill this one. Yes, there you go. So basically, we succeeded to fix this bug here. And thanks a Kyle Cooper for reporting this issue. And if you guys found any other bugs, please just report it on the Key A sections, and I will try to address this quickly.