Unity 2D: Creative Game Development Deep Dive | Frank Dvorak | Skillshare

Playback Speed


1.0x


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

Unity 2D: Creative Game Development Deep Dive

teacher avatar Frank Dvorak, Creative Coding

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.

      Introduction

      1:10

    • 2.

      Project Setup

      2:52

    • 3.

      Parallax Backgrounds

      17:18

    • 4.

      Player Movement and Animations

      23:07

    • 5.

      Energy Management

      10:57

    • 6.

      Asteroid

      14:44

    • 7.

      Object Spawner

      23:23

    • 8.

      Player Health and Collisions

      14:54

    • 9.

      Pause Unpause

      12:15

    • 10.

      Main Menu Screen

      10:43

    • 11.

      Game Over Screen

      3:36

    • 12.

      Particle Smoke

      5:39

    • 13.

      Mission Complete Screen

      4:51

    • 14.

      Win Condition

      9:55

    • 15.

      Music and Sound Effects

      15:23

    • 16.

      Flash on Hit

      6:48

    • 17.

      Phaser Weapon

      9:41

    • 18.

      Object Pools

      8:52

    • 19.

      Particle Trails

      5:02

    • 20.

      Destructible Obstacles

      10:34

    • 21.

      Harmless Space Critters

      17:29

    • 22.

      Plasma vs Critters

      8:20

    • 23.

      Heat vs Critters

      7:37

    • 24.

      Secret Boss

      27:20

    • 25.

      Cleaning and Refactoring

      5:24

    • 26.

      Boss Behaviors

      6:34

    • 27.

      Utility Functions

      14:04

    • 28.

      Code Consistency

      16:43

    • 29.

      Debugging and Game Balance

      8:49

    • 30.

      Export and Deploy your Game

      5:23

    • 31.

      Get Github Source Code

      2:30

    • 32.

      Performance Optimizations

      22:32

    • 33.

      Everything is an Object Pool

      25:05

    • 34.

      Weapon Leveling System

      26:48

    • 35.

      Experience Bar

      27:44

    • 36.

      Swarms of Enemies

      31:47

    • 37.

      Enemies and Sine Waves

      11:08

    • 38.

      Enemy Motion Patterns

      15:49

    • 39.

      Charging Enemy Type

      27:32

    • 40.

      More Boss Types

      6:50

    • 41.

      Boss that Cruises Along

      18:33

    • 42.

      Enemy that Follows the Player

      19:08

    • 43.

      Enemy that Shoots

      19:08

    • 44.

      Boss that Shoots

      19:31

    • 45.

      What's Next?

      0:19

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

18

Students

--

Projects

About This Class

Learn how to create dynamic, animated 2D games using Unity. Starting from the basics, I'll guide you through setting up scenes, adding animations, and implementing game mechanics. By the end of the course, you'll have the skills to bring your own 2D game ideas to life.​

What You Will Learn

  • Setting up Unity for 2D game development

  • Creating and importing 2D assets

  • Implementing character movement and animations

  • Designing interactive game mechanics

  • Optimizing games for performance

  • Building and exporting your game (Windows .exe build, web game webGL build)​

Why You Should Take This Class

Whether you're a beginner eager to dive into game development or someone looking to enhance your Unity skills, this class offers a hands-on approach to learning. You'll gain practical experience by building a complete 2D game, making the concepts more tangible and applicable.​

Who This Class is For

  • Aspiring game developers

  • Artists and animators interested in game design

  • Anyone passionate about creating interactive experiences​

Materials/Resources

All you need is a computer with Unity installed. I provide you with a full set of premium quality art and audio assets and resources to help you get started.

Meet Your Teacher

Teacher Profile Image

Frank Dvorak

Creative Coding

Teacher

Hello, I'm Frank. I'm a front-end web developer, owner of Frank's Laboratory YouTube channel. Come explore creative coding, game development and generative art with me.

See full profile

Level: Beginner

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. Introduction: Welcome to the full course on two D Game Development with Unity. We'll start from a blank project and end up with a fully playable game, both as a native Windows app and as a browser based web game. After creating hundreds of minigames in various programming languages, I've compiled the most common two D techniques you'll need, simplify them, and designed a project around them. We'll go through each technique step by step and build everything you see on the screen together. The most challenging part for beginners is not knowing where to start. So let me guide you through the entire process from the very basics. Let's build a two D sit scrolling game together. But this won't be just any basic game. We'll focus on animations, particle effects, and visuals. We'll also create an enemy and weapon system that you can keep expanding even after the class ends. With the skills you learn, you'll be able to design your own unique enemies and weapons, and I'll provide you with bonus art assets to help you do that. There's much more included, as you can see in the previews. This class is for beginners, but I do expect you've completed at least one or two simple unity projects before. Let's get started. 2. Project Setup: So I create a new Unity project using Universal to the render pipeline. I'm working in Unity six, but you can use any Unity version you want. It doesn't really matter. I start by right clicking here in hierarchy, and I select Create Empty. This will create a new game object. Unity is all about game objects. Game Object is a container with position, rotation and scale that we can fill with components to make it do anything we need. You can see that my game object already has a transform component which determines position, rotation and scale. Unity has many different components. For example, we can give our game object a sprite renderer component to display an image, rigid body component to give it physics, or even a custom script component to control the game object with code. We will do all of that and much more today. I will rename it to background. Down here in my Assets folder, I right click and create a new empty folder. I will call it art. You can download these background players in the video description. All art in this project was created or commissioned by me. You can take it, modify it, and use it for your own projects in any way you want. You can credit me if you are using my art, but it's not required. You can use this little handle down here to scale the icons up or down. When I select any of these images, Inspector tab will give us more information about the files. If I click this little arrow, you can see that Unity auto sliced my background image into individual stars. Sometimes this is useful, but in this case, we don't want that. I select all four images at the same time by clicking the first one and then Shift click on the last one. With all four images selected, I can change their settings for all of them at the same time. In this case, I don't want these images to be sliced. Each image is only one sprite, Sprite mode, single. If you are using large images, you might have to increase max size value here. For me, this is enough, so I click Apply. Now if I expand these sprites, you will see they are made up of only one frame, which is exactly what we need. There is one more thing we have to do. I want to make sure I can measure the width of each image because we will be animating them out of view and back into the view once they reach a certain point. To be able to do that, especially with images that have some transparent parts, I select all my images one more time, and I set mesh type on all four of them to full rectangle like this. This will set the sprite size of each of these images to a full rectangle that wraps the entire image. I click Apply. 3. Parallax Backgrounds: We processed the images and we are ready to import them into the game scene. I have scene tab open here. If I drag and drop image from my assets folder into the scene, Unity will automatically create a game object for it. Unity can see that this is an image, so it will give it a transform component that every game object has, and it will also give it sprite renderer component. If I right click here and reset transform, position will be set to 000. We want to make sure everything is centered here. We will be moving the images horizontally like this by accessing this transform position X value. Why value can move the image up or down? I drag Layer two image into the scene. Unity creates a game object for it, and again, I reset its transform to 00. Layer three, reset transform. Layer four reset transform. I select all four layers here and I parent them under the background game object like this, mainly just to keep our game scene clean and organized. I make sure that background and all four layers have transform position of 00. In your project, you might see something a bit different in the scene view because we are placing all of these images on the same default sorting layer, and Unity decides randomly what order these objects are drawn in. We need to make sure that layers are always drawn in this order with layer one all the way in the back. On any of the layer objects, I go to Sortinayer drop down and I click at Sartin Layer. Inspector will now show me tags and layers manager. Here, under certain layers, I click Plus, and I add custom sorting layer called background. Certain layers in unity allow us to set the render order of different sprites in our two D project. They determine what gets drawn behind and what's in front. In this case, background layer will be drawn in front of default layer. I select layer one and I set sorting layer to background. Notice that order in layer here is set to zero. Layer two will also have sorting layer set to the same background, and order within the background sorting layer will be set to one in front of layer one. Layer three will also be on background sorting layer. Order in layer will be two. Layer four, background sorting layer, audio in layer three on top in front of all the other layers. Here in game view, you can see that game camera field is too wide, and we see bits outside the background images. I set aspect ratio to full HD, 1920 times 1080. Back in scene view, this white rectangle is what the game camera can see. Inside my assets folder, I right click and I create an empty folder. I will call it scripts. In unity, we can write scripts in C Sharp programming language. Let me show you how simple it can be to write a small script that can do really cool things. To create a script, I right click, create scripting and mono behavior script. Monobhavior is a special class in unity that allows us to attach our custom scripts to game objects. It's very simple. Let me show you. You will use monobhavior all the time. It's one of the most fundamental things when working with Unity. I will call it parallax background. When you create a script like this, Unity will automatically create a class with the same name you give to the script file, and it will make that script inherit from monobhavior, which means that we can take this script and we can attach it as a component to any game object. So I select layer one game object. Here and I drag and drop my script here to attach it as a custom component like this. If I go to edit preferences and external tools, here, I can choose my default external code editor. Whatever you choose in this drop down will be used when you open a script in Unity. I'm using Visual Studio code, but you can use any code editor you prefer. So when I select Layer one Game Object, I can open Parallax Background script. I attach to it as a component by clicking here or here. Both of these will open the same script. By default, Unity creates syntax for start and update methods. Start method runs just once when the object is created before the first goal of update. Update method runs over and over for every frame as the game animates. All we have to remember here is that anything we want to happen just once when we create the object, we put it here. Anything that needs to be happening over and over, we put it here. Example, we want to move the layer one game object this script is attached to. To declare a variable in C sharp, I first have to specify the data type. Float is a floating point number, a number that can have decimal points. I will set it to one. Then I take transform dot position of the object this script is attached to. Back in unity, layer one game object selected, this script here and transform position values are here. Notice that position has X, Y, and Z components. To update position value of this game object, I need to keep that in mind. Vector three is a simple data type that has three components, usually for X, Y, and Z axis. If I pass it one for X and one for Y, because this is a two D game, so we care only about two dimensions, the third value of Z will default to zero. I'm saying, take the transform position, which is vector 300, zero, and for every animation frame, add plus one horizontally and plus one vertically to the current position value. Or instead, I can use my move X variable as X component of the vector, and as Y, I add zero, meaning that Y component will remain unchanged as this code runs. It will stay at whatever value it is. So as the game runs, for every frame, I'm adding plus one to this X value and plus zero to this Y value, making the object this script is attached to move to the right. I save changes, and I can test this by clicking the play button. I enter the play mode. That happened extremely fast because plus one doesn't mean one pixel per update. It means one of these blocks you see in the background grid in unity. I can fix that by dramatically reducing this value of one to make it move slower. But the right thing to do here is to actually account for real time that is passing by. First, let me show you this. We are increasing horizontal position by a very small value for each co of update. This method will run probably something like 60 times per second. I drag game view somewhere here because I want to see the scene and game at the same time side by side. To achieve repeating endless backgrounds effect, we want to at some point, reset the position back to zero. Let's say when X reaches plus five, set transform position back to zero, zero. We are not doing anything with the vertical Y component of the vector, so I might as well just set it to whatever value it currently is. It will always stay at zero anyway. If I save changes and enter play mode, layer one selected here, you can see that X is increasing. When it reaches five, it resets back to zero. So the important thing to remember here is that if we want to move something, we can do it by accessing its transform position, but we have to do it through this vector three data type. Setting this move step to a hard coded number will work, but it's not the best practice. We should always account for real time time Delta T. Update method runs over and over. Delta time is the amount of time it takes our machine to call one update. It's the time that passed between the previous frame and the current frame of our game. The game will run on many different devices. Some of them can run faster, some slower. Always want to account for delta time to make sure the movement is the same on any device. On a slower device, Delta time, the time between frames will be higher and therefore position will be moving by larger steps. Faster device on the other hand, can call update more often, but less time will be passing between frames and position will be increasing by smaller value for each update. All you have to remember here is that we never want to tie any movement in our game to frame rate. We always have to tie it to real time that is passing by to make sure that things in our game are happening at the same speed on any device. Delta time is the amount of time in seconds that passed since the previous call of update. This value will need to be larger now. Instead of hardcoding it here, I can put it in a variable I call move speed. I want the value to be visible in Unity editor here so I can set it as public. But even better practice would be to keep it private but give it serialized field attribute like this. When I do this, my move speed variable is private and not accessible from other scripts, and at the same time, it will be visible and editable in unity. I use move speed here on line 16. I save changes. Now we get the field for move speed here. I give it some value and I play. We move by two of these blocks per second, and when we reach five horizontally, we reset it back to zero. I can also go in the other direction by setting move speed to a negative value. But when I do that, this will never be more than five. So position will never reset back to zero. I exit play mode because most changes we make to the project while in play mode will not save. I can delete these comments. So if you want your repeating backgrounds to work in both directions with positive and negative move speed, instead of checking if position X is more than five, we can check if the position is more than five away from zero in any direction positive or negative. I do that by wrapping position X in math absolute, built in function like this. Absolute value of five is five, absolute value of minus five is plus five. I will disregard the minus. So here I'm saying if the position moved by five away from zero in any direction positive or negative, reset position back to zero. I can also write it like this. If the difference between position X and five is more than zero, if we move by more than five units away from zero, we reset. Now if I save changes and I enter play mode, we reset if move speed is positive, and also when it's negative. So you can use this repeating background for a game where your character moves both left and right. I don't want it to reset back to zero when it reached five units. I want it to reset when it reached the full width of the image when the layer image completely disappeared off screen, only then I wanted to reset back to zero. If I try something around 19, my image is 1,940 pixels wide, and each block in this grid is 100 times 100 pixels. So I want to say, when we moved more than 19.4 away from zero, then reset, I would work if I put 19.4 here instead of five. But what if I want this grip to be more flexible and usable for any image size? And also, we are doing multiple layers. What if each layer image is a different width? So instead of hard coding this value, we will measure the width of the image with code, and we reset when the image scrolled away from the screen by that width. Start method runs only once when the game object is created before the first call of update. We are inside Parallax background script, and from here, I want to access this Sprite property that holds layer one image. I do it by creating a helper variable. Type is Sprite. My custom name for the variable is, for example, Sprite lowercase S, and it will be equal to get component sprite renderer dot Sprite. From this script, I'm accessing Sprite Renderer component on the same game object, and it's Sprite field. Now that I have it, I can create a variable. Type is float. I call it background image width and in unity. Inside Assets art, for all my layer images, we are setting pixels per unit to 100. So the image that is 1,940 pixels wide will take exactly 19.4 of these units in the grid. So back in my script, after I have a reference to this field, I want to know how many of these blocks in the grid, how many units does the image have to move before it's moved completely off screen, and we can reset it. What value does position X have to be before we can reset it back to zero? It will be the width of the image. In my case, 1940 pixels, we are taking that texture width from here. Divided by pixels per unit, in my case, 100. 1940/100 is 19.4. When the image moved 19.4 units away from zero, reset its position back to zero. I use background image width here. I save changes and I play. When the image moves all the way out of the screen, it resets. Perfect. The code I wrote will work in both directions, and for any image width, you might use. The image should be wider than camera view to get the right effect. I go to Assets script and I attach Parallax background script to layer two game object as well, and move speed will be three, for example. Layer one move speed will be zero. I also attach the script as a component to layer three game object, and I set move speed 26. And finally, I attach it to layer four, and move speed here will be ten. I save and I play. We have four layers, each moving at a different speed and resetting when fully moved off screen. I exit play mode. I select all four of them at the same time and I set draw mode to tiled. This shows me that each layer is 19.4 units wide and 11 units tall. Just to check, I can go back to my script and I can deba lock background image width. Save that and play to run the code inside start method. And in console, I can see that image is indeed 19.4 units wide, same as the value we are getting here. I delete that log. With all four layer objects selected, I set draw mode to tiled, which allows us to easily create repeating tiled textures. We just have to tell Unity what size we want to cover. In this case, I want to have the same copy of each background layer to the left and to the right of the screen. So 19.4 times three. Now each layer was duplicated to both sides. And if I wanted, I could also tile vertically, but we don't need that for this project. As you can see, as the layers slide and reset that extra side layer comes in place when needed to create an illusion of seamlessly repeating endless background. I think seeing the game preview here and sneview here shows clearly what is happening. This technique is great for any type of endless runner game for platformers and many other projects where you want a static game camera and seamless backgrounds that endlessly repeat. This will work in both directions. So let's try and give layer two negative move speed value. Layer three is on top of it, so it needs to be faster to create the parallax effect and illusion of depth, and layer four will be the fastest. For example, minus one. This motion is for a game where your character is flying through the space to the right. This code base will also work for games where you allow players to move both left and right. For that, instead of hard coding move speed, for each layer here, we would tie that value to player movement direction in our code. If I put scene and game view side by side like this, I hope it's clear and easy to understand how the layers sliding and resetting creates a perfect, seamless, endlessly scrolling effect. And how set in different move speed for each layer creates parallax. 4. Player Movement and Animations: C. I go to assets scenes and I rename my sample scene to level one. You can download player SpaceShip Sprite Sheet in the resources section below. I made that one. Feel free to use it for your other projects as well if you want. I drag and drop the image into Assets art with PlayerSprite Image selected. Inside the Inspector tab, I click Open Sprite Editor. Unity already auto sliced this for us, but I want to move the pivot point to the tip of the spaceship to make the transitions look better because as you can see, the last frame is wider than the rest. I go here to slice. I set pivot point to right, and before I confirm that, you can see Pivot is in the middle now. When I click this, it moved to right center. I click Apply and I close Sprite Editor. If I click this little arrow, I can see the individual frames we just sliced. The images are similar but different things are happening with the engines. We will do some subtle lightweight animations that react to player movement. I take frame zero and I drag and drop it into the game scene. Unity will automatically create a game object for it here. I rename it to player. I click Add Sartin layer plus, and I call it player. It will be on top of the background and in front of it. I select player again and I assign it that new sorting layer we just created. I right click on transform component and I reset it to 00, zero, and I move the player to the left. So maybe minus three units horizontally. If I play, we have our little player spaceship traveling through space. Let's start by adding some animations. I always have to exit play moode before making any changes to my game. I go to window animation animation. I can dock the animation panel anywhere I want. I like to keep it here. If I expand this, you can see that this word changes based on what object we select here. I go to assets and I create a new folder I call animations. I select the player game object, and I want to create an animator and animation clip. So I click Create. In this window, I navigate to the animations folder I just created. I will call this animation player discoreU and I click safe. I go to Assets Art. I make sure I still have player up animation selected here, and I drag this frame on animation timeline. If I click Play here, you can see that when the player moves up, the spreadsheet will show the top engine stopping and the bottom engine engaging more, which is what would happen if we wanted the spaceship to go in that direction, I guess. I select the player again. I click here and create new clip. I make sure I'm inside Assets animations folder and I create another dot anime file called player Down. Save. This image will be player moving down. I played to check. Yes. Create New clip, play right. It will be just this first image. Yes, I create new clip, player left, and I find this image where the engines switch off. Yes. If I go to Assets Animations, we have four animation files we just created, and we also have this player animation controller. I can double click it or I can go to Window Animation Animator to open the player controller file. So keep in mind that inside Animations panel, we create timelines for individual animations. Inside animator, we have a very simple state machine. Here, we define how those animation states transition from one to another. Hey, I like to do this is to use something called a blend tree where we merge all four of these animations, and based on what directional inputs are being pressed, Unity will automatically decide which animation to play. I delete all of these. I right click Create State from New Blend Tree. In Spector tab here, I rename it to player fly. I double click it and we get one layer deeper. I will rename this one to fly. I go here two parameters and I click Plus and I want to create a float parameter. I call it move X. One more parameter, this one will be called move Y. With my fly blend tree selected, I set blend type to two the simple directional. The first parameter will be move X, the horizontal input, the second parameter will be move Y, the vertical input. Based on the values of move X and move Y, we will let the blend tree determine if the player controller should play left, right up or down animation. I click this plus, add motion field, plus, and I add one more. I add two more, so now I have four in total. Let's set all of this to zero, zero. I click here and I select the first motion. Let's start with player we animation sequence. This one will play when horizontal motion is plus one and vertical motion is zero. The next one will be player left, minus one horizontal, zero vertical. I can also do it by drag and drop in these, so I take player up and I put it here. This one will play when horizontal inputs are zero and vertical are minus one, and player down, drag and dropped here will play when horizontal is zero and vertical is plus one. If I select the player game object here and fly blend tree here, I will get this little preview of player spaceship. If I start changing move X, we can see how the blend tree is deciding which animation to play based on the conditions we defined. Move Y should actually be the other way around. I always confuse the vertical direction in unity because it's the opposite of HTML canvas. In unity, positive plus one is up and negative minus one is down like this. Now it works as intended, perfect. So we created a blend tree, this little brain that will automatically decide what animations to play based on the conditions we defined. Now we want to connect move X and move Y parameters to input values coming from a keyboard. We will do it by writing a small script. I go to edit project settings. I will use this quick and easy input manager. If you are making a multiplayer game, I would recommend using the other input system, which is also very easy to implement. I have many videos on it. I will link some of them in the description. This is a simple single player game, so I will use the old input system. Unity has this built in system that automatically captures inputs from keyboard, mouse, and game pads. It's extremely easy and quick to set up and connect to our game objects. Let me show you. Have this horizontal block here. I can see by default, horizontal controls are set up as left arrow or a key on the keyboard to move to the left, negative on the horizontal axis, and right arrow or D to move to the right. I will also connect my Xbox controller to my PC later to test this, and these inputs will already be compatible with all of that as well. We don't have to do anything special here. All I have to do is to note this keyword horizontal. We will use it to access this Vertical is down and up arrows or S and W keys. We will also use fire one or more likely fire two to trigger players special superspeed ability. Here I can see that fire two input event is triggered by left out on the keyboard, mouse one, which is the right mouse button or some keys that are specific for different controllers. We will go over this later. We don't really have to do anything here. I will leave it all as is. I just want to show you where you can go to see all these input events that we can use. I go to Assets scripts, IRClick create scripting mono behavior script. I will call it player controller. I select player Object and I attach this script as a custom component like this. Now that we have this script sitting on player Game Object, I can open it in my code editor by clicking on it here or here. I remove these comments. Back in Unity, player selected here, and I add another component called rigid body two D. Make sure you use the two D version. This will turn the player into a physics object affected by gravity and other forces. So if I play, player will fall off screen like this. I exit play mode. And I set gravity scale on the player to zero. This is space. We want to be floating. I want to use unit is built in physics, so I will make the player move by setting velocity forces on its rigid body two d component. We could also move the player by changing values of its transform component directly, but that way, we would bypass Units physics system, and we would have to write our own collision logic and many other things. So let's do it the right way. I need access to this rigid body two D component from this player controller script component to do that. I define a private variable. Type is rigid body two D. And I will call it, for example, RB. Inside start method, I set RB to get component, rigid body two D like this. When this object gets created, automatically find its rigid body component and save that reference in this RB variable for us so that we can work with it. Start method runs only once when the player game object is created. Update method will run over and over for every frame. Inside update, I set linear velocity on player's rigid body component to some value to make the player move in that direction. I will set it to vector two and I want to push it plus one horizontally to the right and zero vertically. I save this and I play just to see what this does. We are moving to the right, one unit per second. I exit play mode. Let's try minus one horizontally and plus two vertically. I save and play, and this is the result in motion. We know the values we pass here will make the player move in a specific direction horizontally and vertically. Update method runs as fast as it can, usually something around 60 frames per second, but it can run at different speeds on different devices. Fixed update method runs in sync with Units physics updates that happen by default 50 times per second. Everything to do with physics and rigid body should be inside fixed update. Inside update method, we will capture player controls. I define a temporary helper variable. I call, for example, direction X. I set it equal to input dot Gaxsaw and here I pass horizontal spelled exactly like this. Where is this coming from? Back in Unity, I can go to Edit Project Settings and Input manager. Here, Unity captures input from all devices, keyboard, mouse, game pads, and so on. If I expand horizontal, this name is important because this is the word horizontal we will use to access these values. Here in our script. Get axis raw means the value is not smoothed out. This value will only be minus one, zero or plus one. It will not be any decimal values in between. Minus one is moving left, zero means no horizontal movement, plus one is moving right. I do the same thing for vertical Y axis. Keyword is vertical, and by default, that's up and down arrow or W and skis. Up here, I define a variable, private type is vector two, and I call it, for example, player direction, serialized field so that we can see this private variable inside Unity editor. As update method runs for every frame, we capture horizontal and vertical inputs and we set player direction to new vector two with horizontal input as the X component and vertical input as the Y component. Now I can simply use player direction X to push the player's rigid body horizontally, left or right, and player direction Y to push the player vertically up or down. Save that and play. When I press arrow keys or WSAD on my keyboard, player moves around. You can see player direction here. These values are always minus one, zero or plus one. The problem we have now is that with this implementation, we are moving diagonally, one unit up, and one unit to the right, for example. In the same time, we travel further. Diagonal movement is faster with this implementation. We want to make sure that player travels the same distance in any direction. In unity, we can easily achieve that by putting dot normalized. This is how we normalize a vector and we go from this to this. I explained the math behind this in many other classes. Let's just trust a unit is built in methods this time and move on. Now if we play, player moves the same distance in any direction. You can see that diagonal movement values are automatically adjusted here. Okay, so we exit play mode and I can remove serialized field attribute, which will hide player directions in Unity Editor. We know it works, so we don't need to see those values anymore. We also want to be able to scale how fast the player moves. So serialized field, private type is float, floating point number, and I call it, for example, move speed. We scale the horizontal component of the vector by move speed here, and we do the same for vertical. Save that and in unity. I will move my script component up top, so it's easier to see. And I set move speed to one or maybe two. Now if I play, I can move around. I can change the values of move speed here and the player will move faster. If I go to Animator Window and I select my fly blend tree, I know that by changing Move X and Move Y, we switch between different animation states. I want to access this from my script. I say private type is animator and my custom name is, for example, animator with a lowercase A. To set values of Move X and move Y from my script, I want to access this animator component from my custom player controller script component. We are already accessing rigid body two D component. Let's do the same thing for animator. Get component animator like this. Now I can take that animator variable and I can call built in set float method. We called that float move X and move Y, and when they change values, we know that blend tree will switch player states between right, left, up or down. So set float called move X to the value of direction X, the value that goes between minus one, zero or plus one based on what keys we press and also set float move Y to direction Y from line 19 like this. If I save and play, we are moving the player and we are also switching animation states based on the current movement direction. Perfect. We also have this frame for sprint or super speed. Let's set that up as a separate state. I select player Game Object, Animation window. I click here, create New clip. I go to Assets Animations, and I call it player underscore boost. Save that. So we have animation window here to set up individual animations and their timelines. And we have Animator window where we set up how these individual animation states transition from one to another. With player game object selected here and player boost animation timeline here, I drop this frame in here. If I press play here, we can see the sprite gets swapped. Now I want to create a transition between player fly and player boost. I go here to parameters and I create a new one. It will be a Bolin, which can be true or false. I will call it boosting. I right click player Fly, make transition, and drag this transition arrow and connect it to player boost. I select the transition, inspect a tab, and I remove has exit time. I expand settings here, and transition duration will be 0 seconds. We want it to be instant. I go down here to conditions and plus. We will transition from fly to boost state when boosting is true like this. Now the other way around, I right click player boost, make transition, and I connect it to player fly. I select that transition arrow and I antique has exit time. Transition duration is zero and condition down here. Plus, we want to transition from boost back to fly state when boosting is false. Okay. And finally, now I need to be setting this boost in bullying between true and false from my script. I will do it here inside Update. If we press space bar, so if input, get key down keycode space, or if we press, for example, fire two, which is one of the preconfigured actions. I'm using Get button down here. We take animator and we call built in set bool method. Set Boolin we call boosting and we set it to true. Else, if we release Spacebar or fire two, I copy and paste this and I have to be very careful about brackets when I do this. If Gt key up space or get button up fire two, I set Bolin, boosting to false. Now if I play IPress space bar on my keyboard or I press one of the predefined fire two buttons, which by default is left out on the keyboard, right mouse button, or B button on my Xbox controller, pressing any of these will animate player boost state. Okay, that works perfect. When we are boosting, we also need the background to start flowing faster. I can handle that in many different ways. For example, I create a public float I call boost and I set it to F. Private float boost power will be, for example, five F. Down here, I create a function I call private void enter boost and another one I call exit boost. When we enter boost, we take animator and set boos boosting to true and when we exit boost, we set it to false. Here I call enter boost instead, and here I call exit boost. I have my boost and boost power variables. When we enter boost, we set boost from line ten to boost power from line 11. We set it to five. Player will move five times faster. When we exit boost, we set boost back to one. So now we have this public variable called boost that is either one or five. I might refactor this later. But for now, we will go to Parallax Background script file, and from here, I want to access boost from line ten sitting inside player controller script. I want to make some public functions and variables that are sitting on the player available all over the code base. So I will create a very simple singleton public static player controller instance. Whenever I want to use any public properties from here, I can access them through this instance. Awake method runs before start method. So here I can simply say instance from line five is this entire script we are inside right now. To follow good practices, I will make sure I have only one copy of this instance. If we set this object up later to persist between multiple game scenes, we want to make sure we don't have two instances of player controller. I say, if instance is not now, meaning that instance already exists, destroy this other game object. We don't need a duplicate. Else, set instance to this. So I'm creating a public static instance of player controller to make all public properties such as this boost from line 12 available from other scripts in our code base. And here I'm checking if this is the only player controller instance in the project. Now I can use this player controller instance to access this boost value, which we know can be one, or it can be five if the player is boosting. Here I say player controller instance dot boost. It's either one. So move speed of this background layer times one is that same base move speed. But if the player is boosting, this will be set to five, and this layer will move five times faster. I need to put brackets here. First, we calculate the speed, then we account for Delta time. This script sits on each layer object, so this change will affect all four background layers. Now if I play, we can see the background players react when we enter super speed. This boost state will also affect other game objects we will add soon, so I might move it to a different script file and I might refactor this a little bit. But for now, all of this is working. We have a spaceship flying through space with animations that react to player inputs. Awesome. 5. Energy Management: Right now, player boost is unlimited. Let's create a simple energy management system. Let's create an energy bar that depletes when we are in super speed. I right click UI slider, I rename it to Energy slider. UI elements in Unity can only exist if they are parented under Canvas element. So Unity automatically created a Canvas element. I rename it to UI Canvas. By default, Canvas in unity will be huge. If I select it here and press F to focus it, you can see how far the camera zooms out. The slider itself is here in the bottom left corner, and in game view, we can see it down here. So we know that even though the canvas is huge like this, in game view, it will overlay and fit into the game area. For this project, I will set Canvas render mode to screen space camera and I drag my main camera here into render camera field. This will shrink the canvas down and make it easier to work with. But now I can't see the slider anymore, so we know that UI Canvas is now behind the background. Let's add a sorting layer. It will be in front of everything. I call it UI. If I assign this new UI sorting layer to my UI Canvas element, we can see the slider again. Select Energy slider, I set width to 400 and height to 100. I click here to set an anchor. I hold down out to also set position, and let's do top left corner. X will be 50, Y will be -25 to move it a bit down. Okay, so if I expand this, I can see the slider is made up of three elements. I select handle slide area and I delete it completely. With slider selected, we have this value slider here. I go to background and I set the color to black. Fill area can be expanded even deeper. With fill area selected, I set all these to zero. Then I select fill, and I set everything here to five like this to give it a thin border. I click this source image and I press Delete. Color will be 130, 130, 255. I select the main energy slider object, anti antique interactable. The value of the slider can only be changed by code, not by simply clicking on it. If I change the value here, it will show us what the slider will look like when it fills with energy. This looks good. I write Click Energy slider. I go to UI text Text Mesh Pro. First time using it in this project, so I have to import TMP essentials. This is Units system for handling text. I want to put some text over the slider that will display its current value, how much energy we have. I rename it to Energy text. The default value will say energy, centre it horizontally and vertically. I resize this to match the slider size. I want to use a custom font. I will use this one, for example, link in the description below. I download the zip file, I unpack it. In my project folders, I go to assets TexmsProFonts, and I put that TTF file I just downloaded here. TTF is a common true type font file format. I right click it and I go to create TextMsproFont asset SDF. It will create a font file Unity can easily use. On my energy text, I find font asset field, and I will be able to see that new font file here. I select it, and this is how you can use a custom font in Unity. I go to Asset Scripts, right click Create scripting Mono behavior script. I will call it UI controller. I attach it as a custom component on UI Canvas Game Object. I can click it here or here to open it. I will also open player controller script. Here I create serialized field, private float, and I call it energy. This will hold the current energy value. Another field, this one for max energy, and I make another one for energy region. Inside start method, when the game starts and player game object is created, we set energy to Max energy. Okay, I think I might need a flag to determine if we are using energy or not. Up here, I create a private booling I call boosting. Initially, it will be set to false. When we enter boost, we set boosting to true. Exit boost, we set boosting to false. Update method runs over and over different speeds on different devices. So to make sure our energy levels are handled the same way on every device, I'll put this logic inside fixed update. If boosting is true, we do something else block here. So if we are boosting and if energy is more than let's say 0.2, we reduce energy by 0.2 per frame like this. If we are boosting and energy drops below 0.2, else, we exit boost automatically. We don't have any more energy to continue. This se block that will run when boosting is false, we want to recharge energy here. If the current energy is less than Max energy, increase energy by energy regen. Save that player game object selected here, and I see these three new fields. I set max energy to 50 and energy region to 0.1. If I enter play mode, I can see energy is set to max energy immediately, and it's now 50. If I press space bar, we activate boost and we are depleting energy. If I release, we start recharging. If I hold it down long enough to deplete all energy, we automatically exit boost. Okay, let's say we only allow the player to enter boost if the current energy is more than ten. Otherwise, we might get some jitters when we are around zero trying to enter boost. In UI Controller, I delete these comments. Here, we want to create a reference to Energy slider. Type is slider. For this work, we need Unity Engine UI name space up here on line two. I will name this variable, for example, Energy slider. Another variable. This time, type is TMP text spelled like this, and we need TMP name space up here. This will be the text element overlaying the slider. Save that, Canvas selected. I move the script component uptop to make it easier for myself. I drag energy slider into this field, and I drag energy text into this field. I delete these methods. Instead, I write my own custom one, I call Update Energy slider. It will expect two parameters, floating point number type with the current energy value and another float with the maximum energy value. Every time we call this method, it will take slider from line seven and it will set its value to current. It will also set its max value to MAX. And we will set energy text from line eight dot text, which will point to this game object and this text input component on it. I want to set this value to the current energy plus slash symbol plus Max energy like this. I have a feeling this line has to be declared before this line. First, we set max value and then the current value. Let's see. I want this public update energy slider method to be available all over the code base. So I will do the same thing I did for player controller. I will turn UI controller into a public static instance like this. I can copy this awake method. It will work exactly the same here, making sure we don't have a duplicate. Now I have this UI controller instance and I can access all public properties and methods sitting here, such as this update Energy slider from other scripts. I go to player Controller. Basically, whenever we update energy value anywhere in our code, we want that change to be reflected in the slider. When the game starts, we set energy to Max energy. So we want to call UI Controller instance Update Energy slider and pass it the current value and the max value. I copy this line and inside fixed update, after we did all these things with energy, we also update slider to display that new value. Save that and play, and we have an energy slider that works. If I press a space bar, we are depleting energy and we are showing many decimal values. So back in eye controller, let's round the value, we pass to slider to the nearest integer. Whole number without decimal points using this built in method. Save that, and now I play. And when I activate boost, we get this perfect energy slider display. If I deplete energy completely, the code we wrote will automatically exit boost. We also wrote another piece of code that will prevent me from entering boost mode again if my energy is less than ten. Well done, now you know how to work with Unity's game object based UI system. We can create UI elements and we can control them with code. This is an extremely useful technique you can use in so many different kinds of projects. You create a canvas element for your UI like this, you need to make sure it displays correctly on all different screen sizes. For example, a web version of this will display wrong if the browser window is not 1920 times 1080. We can easily make the UI scale by selecting UI Canvas and we set UI scale mode to scale with screen size. Reference resolution will be what we put here. 1920 Ts 1080. 6. Asteroid: So. Space is supposed to be empty, but this is a game, so we need asteroids, robots, and aliens. I created this asteroid spreadsheet for you. You can download it in the video description and you can drag and drop it inside Assets art folder like this. I make sure Sprite mode is set to multiple, and I open it in Sprite Editor. I slice it. Type will be grid by cell size. 248 times 248 pixels. Actually 250 times 248. I click slice, Okay, and I click Apply. I choose one of the asteroids and I drag it into the game scene. I rename it to asteroid. Here I add another sorting layer. I call it objects, and it will be in between background and player. Asteroid selected again and sorting layer set to objects. At component rigid body two D to turn it into a physics object. Gravity scale is zero. I add another component, circle collider two D, Addit collider geometry, and I make it a little bit smaller like this. I select the player, and if I wanted to be able to interact with other colliders, it needs to have its own collider as well. Add component, circle collider two D. Addit collider, and I make it considerably smaller, making our game a little bit more forgiving when avoiding swarms of asteroids. This seems fine. I play. And if I select Game view here, and I move the player towards the asteroid, we can actually push it away, perfect. You can see that player rotated after the collision, and the asteroid will now endlessly travel to the right out of game view. I exit play mode, player selected, and in constraints, I take freeze rotation zt to prevent player from rotating after collisions. I will not freeze it for asteroid. They can rotate when they collide with something. If I play, I can freely move the player outside of playable area. So let's do something about that. The quickest way would be to create an empty game object, I call level boundaries. I reset its transform to make sure it's centered. Here I add component and I search for box collider two D. I will position it along the left edge, so horizontally -9.5 units. Vertical size here will be ten units, which is the size of my visible area. Or maybe I will go 12 to get one extra block on each side. On this same level boundaries game object, I add another box collided two D. This one will be 9.5 units to the right. Vertical size also 12. I add one more box collider D. To move it down, I change its vertical position to -5.5, and horizontal size will be 12, 20 units. And finally, I add fourth box collider. This one as the top boundary, so I move it up by 5.5 units, and it will be 20 units wide. Now if I play while still having level boundaries selected here, so we can see them. Look what happens when I push the asteroid. It collides with the boundary and player collides with boundaries as well because both player and asteroid have a collider component attached to them. We want level boundaries to interact with player but ignore the asteroid. How do we disable collisions between two specific game objects? That's what we can use this layers drop down for. I click Add Layer, and I create a custom user layer I call player and another one called level Boundaries. And one more I will call obstacle. Keep in mind that these are not sorting layers. Sorting layers up here define what gets drawn behind and what's in front. They define draw order. These other layers allow us to associate objects with them and we will use it to disable collisions between specific layers. I select player game object, and using this drop down, I associate it with my new custom player layer. Asteroid with obstacle layer and level boundaries with level boundaries layer. Now I can go to edit and project settings. And here on physics to the tab, I can edit layer collision matrix. For example, here, I have collisions between objects associated with level boundaries layer and objects on obstacle layer. If I untake this checkbox, asteroid will no longer collide with level boundaries. I test it by playing the game. I push the asteroid and it flies through the boundary, but player will collide with it. Perfect. So this is how you can associate objects with layers, and you can be very specific about what collides with what in your game. Inside assets scripts, I create folder and I will call it obstacles. Create new mono behavior script. I call it asteroid. I attach this script to asteroid Game Object. I should clean this up, create empty game object. I call it managers. I will drag level boundaries under managers, also event system, main camera, and global light to the. I put managers up here and I collapse it to keep my scene a bit cleaner. Okay, I have asteroid game object with asteroid script attached. Asteroid has this sprite renderer component. I want to access this field from my script to give each asteroid a random image. If you remember, we have multiple different asteroid frames. I can delete all of this. I define a private variable. Type is sprite renderer. Name is sprite renderer. Inside start method, I take this variable, and it will be equal to get component sprite renderer like this. From this script, I'm accessing this sprite renderer component. Another private field, but I want it to be visible in Unity editor. So serialized field type will be Sprite, and it will be an array. I call it, for example, sprites. Save that and in unity, we have these five different asteroid frames. Here is the Sprites array we just created in our script. So I click plus five times, and I drag five frames in here. A now when asteroid game object gets created and the start method runs, we want to randomly assign it to one of these five images, sprite renderer dot Sprite. We are setting value of this field, and it's equal to this sprites array at some index zero, one, two, three, or four. I want to randomize it, so I say choose one of these images at random. Index in Sprite array will be random range between zero and however many elements are there in this array currently. So sprites dot ngth. If this index value is zero, we get this frame. If it's three, we get this frame. I go to assets and I create a new folder. I will call it prefabs. Prefabs are preconfigured prefabricated game objects that we can reuse over and over. I drag asteroid from the scene into this folder. Notice it will turn blue indicating that this object comes from a prefab now. I can delete it here because we have our prefab now as an asset. I can just drag it out like this into the game scene as many times as I want. All of these are already preconfigured with our custom script that will randomize their image when the game starts. So let's start and play. And yes, you can see each one gets a random image assigned from all of these. All the asteroids are already preconfigured with colliders and rigid bodies. So I can push them around, and it will all work. This is the power of prefabs. I want to give asteroids a little push using the built in physics system, so I will need access to this rigid body two D component from my script. Private rigid body two D. I call it RB. RB is equal to get component rigid body two D. Just one push at the start. Linear velocity will be minus one horizontally. Or maybe temporary variable I call push X. It will be a random value between minus one and zero, and push Y will be a random value between minus one and plus one like this. Okay, I use push x here and push Y here. This push will happen only once. We are inside start method, but it will be enough to create a little bit of movement and maybe even some collisions and some spinning asteroids after they collide. I play, and yes, that worked. Maybe I don't want them to move endlessly. Let's introduce some linear dumping to make them slow down and eventually stop again. Okay, yes, this is good. We have to keep in mind that this is an endlessly scrolling game. So as the background floats by, we want all game objects to float from right to left as well to create an illusion of player flying through space. Inside Update method, I create a float variable I call move X, and I set it to F. Update method runs over and over. As the method runs, keep decreasing transform position of the asteroid by minus move X minus two horizontally. If I save and play, this will be way too fast. We are inside update method that can run at different speeds on different devices. To make sure asteroids move at the same speed on any device, we need to account for time passing by. Time to Delta time is the amount of seconds that passed between this call and the previous call of update. Faster devices will serve more frames per second. Delta time value will be lower, so they will move by smaller steps. Slower devices will have more time between update calls. So objects will move by larger steps, and result is that objects move at the same speed regardless of frame rate. When making games, it's important that we time everything based on real time, not based on frame rate. This way, we can make sure that events in our game happen at the same speed on any device. Asteroids will just move endlessly to the left. We don't need them once they are not within the visible game area. So when asteroids move off screen all the way, I want to destroy them. So as the game runs and transform position updates, we check if transform position X is less than minus ten, and if so, we destroy the asteroid game object that this script is attached to. When I play, I can see the asteroids being destroyed when they reach this area. Just to make sure they are completely off screen when they get destroyed, I set this value to -11 units. I right click and I create empty game object. I call it game manager. I reset its transform. I go to Assets scripts, and I create a new mono behavior script. I call it game manager. I attach this game manager script to Game Manager game object as a component. I open it in my code editor, and I delete all of this. I want this game manager script to be accessible from other scripts in this project. So I will do the same thing we did here with UI controller. I will turn it into public static instance. I can copy the Awake method from here because it will be the same. Check if this is the only instance of game manager. If not, destroy it. I keep a public float variable I call world speed here. How fast is the world scrolling by? Save that and in unity, I set it to two. Now inside asteroid, I can replace this hard coded value of two with game manager dot instance WorldSpeed. World speed will affect many other floating objects and enemies in our game. So we want that value to come from the same source. Save that and look what happens when I set it to minus two and I play. While I play, I can change this value to five, making them move faster in the opposite direction or minus five to make them go the other way again. Okay, this works really well. I exit play mode and I set wall speed two plus two. If I play, asteroids get randomized sprites, they float to the left and they get destroyed once off screen. One more thing here, if I enter boost speed, the stars fly by faster, but asteroids don't react. I put world speed in brackets, and I multiply it Tam's player controller dot instance dot Boost. Maybe I will do this inside game manager instead later. But for now, let's see, save that and play. And when I boost, asteroids speed up as well and react to it now. Perfect. Now I need a system to spawn game objects such as these asteroids. Let me show you a simple but very powerful and versatile solution that can be reused to also spawn game objects like obstacles, enemies, and event triggers in predefined timed wave. 7. Object Spawner: All of these are an instance of a prefab. Let's delete them and create copies of our prefab with code instead. I go to assets scripts and I create a new mono behavior script. I call, for example, Object spawner. I create an empty game object, and I also call it Object spawner. I attach Object spawner script as a component. I delete all of this and I declare a public variable type will be Unity game object, and I will call it Bree fab. What game object we want to spawn? Another variable, float that I call spawn timer and another float I call spawn interval. So these variables define what do we want to spawn and how often. I see the fields in unity editor here. I go to Assets briefaps and I drag my asteroid briefap into this field. Spawn timer will count and reset each time it spawns a new one, and the interval at which I want to spawn the asteroid will be, for example, 1 second. I reset transform to 000. I create a private method. Return type is void, meaning it returns nothing, and I call it, for example, spawn object. In here, I want to take this game object prefab, which in this case, is an asteroid, and I want to create a new copy of it and place it in the game scene. We can do that using built in instantiate method. I pass it the object I want to create a copy of, in this case, prefab from line five. Then I need to tell it where in the game scene I want to put it. I want to place it at the same position as the game object. This script is attached to. So this position of 000 right now, and it also needs rotation. So I pass it the rotation of this object, which is also 000 right now. So instantiate method will create a copy of a game object and it will place it in the scene. We have to tell it what to spawn, where and what is its rotation. Whenever we call this custom spawn object function, it will create a new asteroid. Inside update, which runs over and over for each frame, we create some kind of countdown system to trigger this. I take span timer from line six and for every frame, I accumulate real time that is passing by in seconds. If spawn timer is more or equal to span interval from line seven, which we set to 1 second, we set spun timer back to zero so that it can count again towards the next object to spawn and we call spun object to create a duplicate of our asteroid brief up. Count real time. When we reach 1 second, reset spawn and count again. Save that and play. We have asteroid coming out every 1 second. We know that they get starting position and rotation from the game object. This script is attached to this object spawner. If I take move tool and I put it somewhere else, I play, and asteroids will come from this point, perfect. If I use our super speed move, there will be bigger gaps between asteroids because they always spawn every 1 second. But in our game, that doesn't really make sense because we are trying to create an illusion of traveling through space. We need to make sure that if we speed up, the rate at which we spawn asteroids also adjusts accordingly. On player controller, we have this boost, which can be either one or five. Inside Object spawner I use that multiplier here. Either it's one, anything times one is the same value, and if we are boosting, this will be five. Delta time will be increasing five times faster, reaching spawn interval breakpoint faster, and speeding up the entire spawning process. I save that and I play to test this. I fly at normal speed, and if I press a space bar and enter super speed, asteroids spawn five times faster. We can use this same object spawner to spawn enemies or anything else we might need in our level. That can include a trigger that when it spawns, when the player collides with it, it will mark this level as complete. We can basically spawn anything that can be a prefab, which makes this simple technique incredibly powerful. But let's take this step by step to make sure we understand everything and we are able to reuse these skills in other projects. Asteroids now spawn from a single point. From wherever in the game scene, we place the parent object spawner game object. Instead, I want to create an area here on the right side of the screen, and I want each asteroid to randomly spawn somewhere in that area. I will create two more game objects parented under object spawner like this, minimum position and maximum position. I reset position of the parent to 000. I move Min position game object somewhere here. Maybe 11 units to the right, four units up and max position will be 11 units to the right as well and minus five units down. Now I want to basically create an imaginary line between Min pose and Max pose game objects, and I want each asteroid to spawn from a random position along this line. So position of Min pose and Max pose will define the spawn area. I will need references to them so that I can access their position values. Serialized field, private type is transform because I want their X and Y position, and I call them Min pos and Max pose. Save that. In unity, I drag Min post game object to the field here and Max pose here. Now we have these references in our script to transform position of Min Post and Max pose game objects. I create a new customer method. It will be private. Return type will be vector two, and I call it, for example, random spawn point. I define a temporary helper variable. Type is vector two, and I call it spawn point. The horizontal component of spawn point will be horizontal position of Min pose game object. We could also use Max pose game object here because both of them have the same horizontal position of plus 11 units, and now we will need access to the vertical position of Min pose and vertical position of max pose, which is minus five, and we randomize the value within this range. So the vertical component will be a random range between the vertical position of Min pose game object and the vertical position of max pose game object. Now we make this function return spawn point, which is in vector two format. We have this random spawn point function that returns vector two, and here inside span object, this parameter, which determines where in the game world, we place the new object also expects vector two. I simply call this method here like this. Every time we call spawn object, we randomize position based on where we placed Min pose and Max pose in the game world, and we use that here. Save that and play. And this is how you can create a larger randomized spawn area. Asteroids now appear randomly along this line. This is probably the simplest implementation of object spawning system. We can expand on this and optimize it later. Let's see. For now, I'm very happy with what we've got. The most obvious improvement here would be to turn this into an object pool. Instead of constantly creating and destroying the asteroids, we create a reusable pool of asteroid game objects and we activate and deactivate them when needed, reusing the same objects over and over. So far, we are spawning only asteroids. Let's create another game object and plug that into our object spawner. You can download my Space whales spreadsheet in the description down below. I animated and rigged this animation myself using free software called Dragon Bones and I exported that in the form of a spreadsheet that can be easily used in unity. All the art assets I'm giving you in this episode are copyright free, so feel free to use them however you want. The image is pretty large because I wanted slow moving detailed animations and sharp clean art design. You can see the image is being shrunk down to 2048 pixel width because of this max size setting, but I want my image to be able to expand to its full original size. I check the width of the actual PNG image, and here in this dropdown, I choose a value that's more than that and I click Apply. I make sure Sprite mode is set to multiple and I open Sprite Editor. I click slide. Type will be grid by cell size. And the frames in this spreadsheet are 420 Toms, 285 pixels. I click slice, and I click Apply. Notice we have four different whales here, one on each line. If I expand my frames, I can see it's all sliced and ready. You can choose a different whale if you want. I will choose this first frame and with Scene tab open, I drag it into the scene. Unity will automatically create a game object for it with sprite renderer component attached. I set sorting layer two objects. I flip it horizontally to face the player and I rename it to whale one like this. I open asteroid script that we attached to asteroid prefab game object, and here we have this update method that handles how the object flows through space in our game that has a static camera. Inside scripts obstacles, I create a new mono behavior script I call whale. I attach it to Wal one as a component. I delete the start method code. I go to asteroid script file. I copy this entire update method, and I paste it here. This calls for inheritance, but let's keep it simple for now. If I save that and play, Wal will float by same as the asteroids do. I go to Assets prefabs and I drag and drop Wal one in here, turning it into a prefab. I can delete it from the scene now. I can select Object spawner and I drag Wal one into the prefab field here. If I play, we are spawning space whales. That was easy. I open Animation tab. If you don't have it open, you can go to Window Animation. I drag the prefab out into the scene again and with Wal one selected, making sure this says to begin animating Wal one, I click Create Navigate to Assets Animations folder here, and I will call this animation Wal one. Safe. I go to Assets art with Space whales spreadsheet expanded, I select the first frame. For you, this frame might be different if you decided to use a different whale. We have four different ones here. I scroll down to the last frame and while holding Shift, I click it, selecting all frames in between. I drag all these frames on animation timeline. If I press play, I get the flying or swimming animation. It's too fast, so I reduce samples to 30. If you don't see samples field, you can click these three dots and show sample rate. I think 25 is good. I want it to move slow because this is supposed to be a huge space creature. I made this animation on a copy of a prefab, but I want all the whales made from this prefab to have this animation, so I need to apply it to the prefab itself. I find the animator component and I can see some change was made here that is not on the prefab. It is only on this single copy. I go up here to overt and we can see that change to animator. I click Apply A, making sure the prefab itself and all its future copies will have this animation we just created. If I go to Assets prefabs, I can drag a few out and play. All space whales now animate. Perfect. I can delete this. If I play the game again, let's try to see when two whales overlap. As the animation runs and we are swapping sprite frames, Unity is deciding randomly what is drawn in front and what is behind. This creates this visual buck where the whales are blinking. This can't be fixed by sorting layers because all of these whales are on the same sorting layer. We will fix this by telling Unity specifically the rules it should use to decide what is drawn in front and what is drawn behind for objects on the same sorting layer. I go to assets settings and I find this renderer to the asset file. Here, we will set transparency sort mode to custom axis, and we will sort by the vertical Y axis. This simply means that game objects on the same layer will be sorted based on their vertical position. What is higher vertically will be drawn behind. What is lower will be drawn in front of it. This rule is useful for the top down games as well, where you want characters to walk around objects. But here we use it as a quick and easy way to prevent blinking spreadsheets. As you can see, now there's no more blinking because we defined a very clear rule, telling unity the order in which it should draw game objects that are on the same sorting layer. I have object game object here. Currently, we are spawning always the same object type depending on what prefab we put here inside the prefab field. I want to create a wave system where we can say, for example, spawn 25 asteroids and then spawn three whales and so on. We will be able to use this to define and time the flow of our game. I go inside Object spawner script and I create another private variable. It will be an integer number with no decimals and I call it, for example, wave number. One more variable and this one will be type of list. For list to work, we need system collections, generic name space. Just bear with me here and we will explain everything step by step. It will be a list of wave objects and I will call that list, for example, waves like this. You can see that wave is underlined because it doesn't exist. I'm not sure you know we can do this, but I'm here inside Object spawn class. I can actually define another class inside of this. I will call it wave. This will be a list of these waves. Rather than having just a single prefab and spun timer, we will have a separate set of these for each wave individually, each wave can be different. Now, we broke this code, so I will comment it out for a minute. This is good. Each wave will also need integer that defines the number of objects per wave. And one more called spawn Object count. This variable will keep track of how many of these objects we already spawned and how many we have yet to go. If I save that and I go back to Unity, we see wave number, but this wave class is not accessible from the editor, so we don't see our list of waves from line ten in the editor at all. I will make the class visible in Unity editor by adding system serializable attribute. I save that, and now in unity, I have this waves list. I click Plus and it will add the first element with an index of zero. If I open this, I see all the properties. I can click Plus again and add another wave. I go to prefabs, and let's say that the first wave will be asteroids. I drag asteroid prefab here. We want to spawn a new asteroid every 1 second until we reach five. When we spawn five of them, it will automatically move on and start spawning the next wave. The second wave will spawn well one prefab every 1.5 seconds, and it will spawn three of them in total. If I put my script side by side to this, we can see this list of waves here. Each time I add a new wave and it will take this class and create fields based on the blueprint we defined here. These are fields for the first wave. These are fields for the second wave. Down here in update method, depending on the currently active wave, we will either be accessing this spon timer or this spon timer. I comment this and to access spontr, I take waves from line ten, this list, and I access spun timer based on the current wave number as an index. If wave number is zero, we are accessing this one. If wave number is one, we are accessing waves index one dot SponTr which is this one. We will be accessing these elements depending on what is the currently active wave. Waves list at an index of wave number. So I will do the same thing for the other spa timer here. Same thing for spawn interval here, and for another spon timer here. I move this. I remove this closing command. I have to do another thing for this prefab we defined on line 14. Waves at the index of wave number dot Prefab is the object we want to spawn. If wave number is zero, it will be this asteroid. If wave number is one, we will be spawning this whale. If I save and I play, we are spawning asteroids. If I manually change wave number to one, we will start spawning the whales. Wave number defines the index in this list from which we are pulling the wave data. Let's automate this. Every time we spawn an object, we access spawned object count of the active wave and we increase it by one. We call this spawn object here. After that, I check if span object count of this active wave is more than total objects per wave. If it is, we increase wave number by one, which is all we need to do to move from this block zero to this block with an index of one and the game will start spawning that wave. In our case, the whales. I save that and I play to test it. We are spawning asteroids every 1 second, and we are counting them. As soon as spawned object count is more or equal to objects per wave, when it reached five, wave number will increase by one, and that automatically made our code start pulling data from this other block, wave with an index of one. When we reach three here, wave number increased to two, and we get an error because we have no more waves here. There's no element with an index of two inside this list. In my code, every time I increase wave number by one, I check if wave number is more than waves count. If this was an array, we would use length here, but this is a list, so I use count. If wave number is more than the number of elements we have in the waves list, reset wave number back to zero and we start spawning the asteroid again. We start from the wave one. So if I play to test it, we are spawning asteroids. We see spawn timer count to one and reset over and over. When we reach five spawned objects, wave number increases to one and we start spawning a whale every 1.5 seconds until we spawn three. And now we are spawning asteroid and wale at the same time for some reason. It's because when we go back to wave zero here, spawn object count is still more than five, so it immediately jumps to the other wave where spawn objects are also more than three. So we just get both waves at the same time over and over. If you look at what wave number is doing. When spawn object count is more or equal to objects per wave and we are ready to increase wave number and jump to the next wave, before we do that, we reset span object count to zero so that it's ready for another cycle whenever this wave comes up again. Save that and play. We spawn asteroids, three, four, five, we spawn whales, two, three, back to wave one, and we spawn asteroids and the cycle will endlessly repeat. I can add another wave. We will create more object types later, but for now, let's say two asteroids that spawn very fast. And another wave with a single whale that takes 5 seconds to spawn. We can use this system to craft and time object spawning, and this is extremely flexible and it will allow us to implement many different game ideas. Basically, we are laying out the timeline of our game. We are mapping out the level here. We are spawning only asteroids and space wells for now, but we can spawn any type of game object that can be made into a prefab here. I will explore this deeper later in the class. If you have any questions, let me know in the comments. I exit play mode for now and I set this to two waves. I. 8. Player Health and Collisions: Creating player health bar will be easy because I can simply duplicate the energy slider we already created. I copy and paste it, making sure it's parented under UI Canvas. I rename it to Health slider. I expand it, and I renamed this to Health text. This text field will say health as a placeholder value. Fill area and fill color will be red 25500. I select this main Health slider game object, and I click here. And under anchor presets, I hold down out to also set position, and I select the top right corner. Position X will be -50 and position Y will be -25. Now I need a reference to this new health slider from UI Controller script, same as we did with Energy slider before. I copy these two lines of code. I rename this to Health slider and this one to HealthText. Down here, I copy Update Energy slider function. I rename it to Update Health slider. It will take the current and the max health of the player. Here I replace energy with health in these five places. Set the current slide value to players current health, set slider max value to players Max health, and healthtext will display the current health slash the Max Health. We are calling Update Energy slider. We created earlier in two places here in the start method, and here in update. It works correctly in update, but it doesn't work inside start because right now we have to call this function twice until slider displays the values correctly. It's simple to fix this. I have to make sure I set the max value of the slider first and only then we set the current value. And I do the same thing for the health slider, max value first, then the current value. Same as we hold values related to energy here, I copy these. We will have a value for health and for max health. When Start method runs, we set players current health to Max health and we update health slider Pacinant health and max health as parameters. We also want to call it every time player takes damage or heals. Let's implement collision detection between player and asteroids. In unity, I go to Assets prefabs. I select asteroid prefab, and in this tag drop down, I add TAG. I click plus here, and my new custom tag will be called obstacle. Save that. Inside player controller script, I declare a new function, private void and built in on collision enter two D. This function gets this automatic parameter of collision two D type, and I name it, for example, collision. If player collides with something, this collision variable will store a reference to it. So if the game object player collided with has a tag of obstacle, this has to be spelled exactly like I spelled it here. If we collide with an obstacle, we will do something. In unity, prefabs folder, asteroids selected, and tags drop down. We have some default predefined tags, and we also have our custom obstacle tag we created. So I select it. We are on the prefab, so all asteroids will now be tagged as obstacles. Back in my code, if player collides with an object, tagged as an obstacle, we call take damage function and we pass it one damage. We haven't defined that function yet. I will do it down here. Private void, take damage. It will take one parameter of integer type, I call damage. When player takes damage, we take player health and we reduce it by the amount of damage received. And we will also call Update Health slider method, passing it the updated health and Max health. And as we just did, if player collides with an asteroid or some other obstacle, we call take damage and we pass it one damage. So inside UI Controller, we have references to the health slider and health text. We created Update Health slider function, which will update that slider and that text. We have variables for players current health and player's Max health. When player gets created, when the game starts, we set health to Max health and we update Health slider to display that change. And every time player collides with an obstacle, player will take damage, and we also update Health slider to display that. I save that and I select UI Canvas. The script needs these two references, so I pass it Health slider here. I expand this and I pass it health text from here. If we play, health slider displays zero, so I exit play mode, player selected, and we have to give Max health a value. Let's do five for now. We might introduce some power ups later that will increase players MAX health. I play and player gets five out of five lives. We are using on collision enter function, so every time we touch an asteroid, we will lose one live. Health slider is correctly displaying these changes. If we get down to zero health, player is still flying as normal because we didn't write any logic to handle that scenario. So in my code, inside take damage. When player takes damage, we will check if health is less or equal to zero. If it is, we first set boost to one F in case the collision happened in super speed, and we take player game object and we deactivate it. Set active falls, which is the same thing as unchecking this checkbox. Save that and play. I collide with asteroids losing lives, and when we lose all lives, player will disappear. The world is still scrolling by, but player is now great out here and deactivated. Let's do this step by step. First of all, I want the player to have some animation when it gets destroyed. I'm giving you a really nice explosion animation spreadsheet. I called it boom one. You can download it in the resources section below. I drag and drop it inside my art folder. I increase MAC size value here and I apply. Sprite mode is set to multiple. I open Sprite Editor. Slice will be grid by cell size, and frames are 300 times 300 Slice and apply. Unity has a robust built in particle system we can use here, and we will use it later for some smooth effects. But in this case, I want to show you how to animate effects from a sprite sheet. I expand my Boom one spread sheet and I drag one of the frames out into the scene. Unity creates a game object for it, and I put it on the same sorting layer as the player. I rename it to boom one. I open animation Window. If you don't have it open, you can open it by going to Window Animation Animation. With boom one, gameObject selected, making sure this says to begin animating boom one, I click Create. Inside Assets Animations, I will name this boom one. I click the first frame, I go down and I shift click the last frame, selecting all the frames in between. With Boom one animation here, I drag all the frames on the timeline. If I play, we can see the effect in action. If you don't see samples, you can click these three dots and tick Show sample rate. I slow the animation down by setting this to 25. I play it. Yes, this is good. The animation loops. In this case, we want the animation to play only once. I go to Animations folder and Inspector tab here. I select this boom one dot Nim file i antique Loop time. I go to prefabs folder and I drag boom one in here, turning it into a prefab. I will ignore this warning message because it makes no sense. Animations will still work fine, and I can easily test it by dragging multiple copies of my prefab like this. And if I enter play mode, all animations will play and work fine. As you can see, these boom one game objects are still here, even when the animation finished playing. I want them to self distract after they played all the frames. I delete all of these, and I go to Assets scripts and I create a folder I call effects. Inside, I create a new mono behavior script. I call it boom. We will share and reuse this file for other spreadsheets with explosions if I decide to implement more later. I delete all of this code. I will create a reference to the animator component. Inside start method, we call Get component animator like this. Now that we have a reference to the animator, we can check if all frames of the current animation finished playing, and then we can destroy the object. Actually, before we do that, let's just simply call destroy here. We want to destroy the game object. This script is attached to, but not immediately. So I pass it a delay of 3 seconds. I want to attach this script to Boom one prefab here inside my prefabs folder. It's a bit tricky, so I go back to boom one prefab and I press this little lock to make sure Inspector tab stays on this object. Now I go to scripts effects, and I drag Boom script on the prefab as a component. I will ignore this error. This animated reference is empty because we will be getting it automatically at runtime with G component we put inside start method. We define that logic here on line nine. I can also hide this from Unity Editor. It doesn't need to be visible there. We say destroy this game object after 3 seconds. Save that. And in Unity, I drag out a few of these into the scene. We see the objects here. I play, one, two, three, and they get destroyed after 3 seconds. That works, but we don't really know how long the animation takes, and it's not exactly 3 seconds. So here as the delay, instead, I will take the animator component and I call get current animator state info. We created only one animation with the explosion frames. So we know there is only one animator state this object can have at index zero, and we want its length. Simply said destroy the game object. This script is attached to after its current animation finished playing all its frames. Save that and I play. They animate, and immediately after the animation is over, all three game objects get destroyed. I will reset transform to 000. I want this blue explosion effect to play when player gets destroyed. So inside player controller script, I create another variable type will be Unity game object, and I call it, for example, destroy effect. When player takes damage and loses all health, we deactivate the player and we create a copy of this destroy effect. We know that to create a copy of a game object prefab, we use built in instantiate method, which takes the object. We want to create a copy of its position and its rotation. So I pass it the position of player when it was destroyed because we are now inside player controller script attached to player game object. Transform dot position here refers to player game object, and I pass it rotation of the player, which will be no rotation. Save that. I delete all these and I unlock this player selected here, and as destroy effect, which expects a game object, I pass it this boom one prefab. I set player Max health to two to make it easier to test. I play, and I will collide with some asteroids. When player loses all health, we have our boom animation playing. Actually, when player gets destroyed, let's set boost to zero, which will stop the movement completely. I play again to test this I collide with an asteroid and with another one, and the world will stop scrolling. And also game objects like asteroids and whales will stop spawning because the spawn timer is tied to player boost speed, which we just set to zero. So spawn timer is not increasing anymore. Now will be the time when we display a game over screen. So let's focus on all of the screens at once. Main menu screen, game over screen, and level complete screen. I set player Max health to five. 9. Pause Unpause: I right click UI Canvas and I go to UI and panel. Panel is a UI element, so it needs to be a child of canvas. Otherwise, it will not be visible. I will call it pose panel. Color will be 155-15-5255 with 100 opacity. I want it to be semi transparent. I give it some margins, 50, 150, 50 and 50. I write click pose panel and UI text text Mesh Pro. I want this text to be a child under the pose panel like this. I call it title. I center the text horizontally as well as vertically within the box. I expand it to make it really big. Font asset will be the pixel art font we installed earlier. Font size will be auto size 72-250. It will scale between these sizes based on available space. I want to create a special font style that will be used for headers in our game. Let's give it a gradient by ticking this checkbox. Color Mode is vertical gradient. The first color will be 155, 155, 255. And the second color, I leave it as white. I go down here to the material settings, and I set outline color to white. Thickness of 0.05, I will reuse this same title for other scenes. So let's just drop it into prefabs folder, so I have it saved as an asset. I have to remember that it will only be visible in the scene if it's a child of Canvas element like this one is under UI Canvas. I have this copy of my title prefab selected here, and I find its text input field. This one will say post. Move tool, and I drag this upwards pointing arrow, moving it up only vertically without affecting the horizontal position. I want another element inside my pose panel, so I right click it here and I go to UI button TextMshP. I set it to 400 times 100 pixels. Let's give it some graphics. I will link this casual game buttons asset pack in the description below. It's free. I download it and I unpack the zip file. It will give me a folder with all these button shapes. I choose this long blue one and I drag and drop it inside my art folder. With the button image selected inside Inspector tab, I set Sprite mode to single and I click Apply. I select my button element, and I drag and drop button image into source image field here. And now we have a nice button in our game. This button also has a text element inside, so I set font asset to our custom pixel art font. Font size will be 60, font color white. With the button still selected, I find its button component. Here, we can define what the button looks like in five different states. When it's normal, highlighted, pressed, selected, and disabled. I select highlighted color, and here I can use color picker. I can use this to pick any color that already exists in the scene. For pressed color, I will also use a color picker tool and I choose some bluish color and select it will also be some shade of blue. If I save and play, I can hover over the button and click it and I get a color highlight. Our game will have a few different buttons. So let's go to prefabs and drag the button game object here so we can reuse this button that's already set up later. I select my existing button. I rename it to resume button. I expand it and it has a text object inside here. I find its text input field, and this button will be to unpause the game, so it will say resume. I want to create another button. I can drag and drop our preconfigured button prefab into the scene. I need to place it as a child of Canvas. I will drop it on the pause panel to make sure it's under the panel as a child object. I move it vertically, 125 pixels. Okay, -125 pixels. I rename it to main menu button. I expand it here, and inside is the text object. The text on it will say main menu. I drag out another button prefab on the pose panel. Vertical position will be -250. I rename it to quid button. On the text object inside, it will say quid game. So if I play now, I can move mouse over the buttons and they will animate. Now I need to be able to show and hide the pause panel with code. I will put that logic inside UI controller script. Public game object variable, I call pause panel. It will be available all over the code base through this public static UI controller instance. I go inside game manager and I create a public function, I call pause. So I want to handle showing and hiding of this pause panel from game manager script. I will create a single function that will both pause and unpause the game. I check if pose panel is currently hidden. If UI controller dot instance dot pose panel dot Active Self is false. If it is currently hidden, I activate it to make it visible, set active true. Else, meaning when pose panel is visible, I hide it. Set active false. Back in Unity, UI Canvas selected here. On UI Controller script, we created a public field for pose panel. So I drag and drop this post panel game object here. Set active true and false in our code is the same thing as checking and unchecking this checkbox here. So finally, I need to call this pose function from somewhere. Inside game manager, I create an update method, which will run over and over for each frame. Inside, I check if Escape key on the keyboard was pressed. If input dot Get key down, keycdeEscape. Or let's also bind this pause function to P key, get key down keycode P, and I also bind it to a third button, which will be one of the predefined input events called fire three. Notice that for fire three event, instead of G key down, I'm using G button down. So when we press Escape or P or a range of inputs associated with fire three input event, we will call our custom pause function, which will pause or unpause the game. Save that, and if I go to edit project settings, input manager. See this fire three event here. I save and I play. If I press escape or Pike, pause screen is visible. I want to unpause when we click resume here. Right now, I can press escape again while the screen is active and it will deactivate it. Pressing Escape repeatedly will show and hide the pause screen. Also, you probably notice that the time doesn't stop when we pause the game, but that's very easy to fix. When we display pause panel here, we set time dot timescale to zero. When we hide pose panel, we set time dot time scale back to one like this. Save that and play. I press Escape key to pause. I press it again to unpause. This works. I also want this resume button to unpause the game when clicked. So down here inside its button component, I find its on click and I click plus to add an event. I drag and drop game manager object here because the pause function I want to call is attached to game manager script. Here, I select game manager, and I find the pause function. So when we click RezomPton, take game manager script and call its pause method, which will unpause the game because Resume button is only visible when pause screen is visible when the game is paused. I play, I press Escape to pause. Notice that buttons are still animating even when the game is paused. I click Resume to pause. I pause again, I press directional arrows and you can see the player is swapping sprites even when the game is posed. I want to prevent that. Inside player controller script, I will pass these values to Animator only if time dot time scale is more than zero. Save that and play. I can still enter boost when paused. Okay, so actually, I will put all of this code inside this block. I have to be careful about brackets when I do this. Run all of this code only when T dot T scale is more than zero. Now I play, and if I pause while the player is in superspeed, if I unpause, we will be stuck in superspeed because the keyup event that would trigger exit boost function happened while pause screen was active. I fix it by calling exit Boost every time we unpause. I will assume player released the super speed after they pause the game. They can enter boost immediately again after they unpause. This is a good solution that will fix the back and not affect gameplay. There are other ways I could have dealt with this. Let's see. Maybe I will revisit this later. Now, if I enter Superspeed and I pause, player is frozen with superspeed animation frame, and when I unpause, we automatically exit boost. I tick this check box to make pause panel visible. We will create main menu later, but now let's implement quid Game function. Public, so it can be called from other scripts, and I call it quid Game. In Unity, we can simply call application dot quid like this. This will not actually quit the game here when I tested in Unity editor, but if you create a playable build of your game, it will close the application down. I save my changes. I select quid button, find its on click Settings and plus. I drag Game Manager Game Object in here. And here I find the quid game function we just wrote. As we said, we can't actually test it here in unity. We will test the quid button later when we build a playable version of this game. 10. Main Menu Screen: C. And finally, we created a main menu button. We will create main menu in a completely different way than how we did the pause screen. We will build it as a separate scene. I go to Assets scenes. So far, we have only this level one scene here. I right click Create scene scene. I'll call it main menu. By making the main menu its own scene, we can keep it separate from the rest of the gameplay elements. It's more modular and also easier to deal with because we don't have to worry about any of the gameplay related logic here. We can get very creative. Let me show you some of the cool things we can do here. I select this background game object and I copy it. I double click the scene file to enter the new main menu scene, and I paste the background in here. I want to have this seamless parallax background animation even in our menus. If I play, I will get an error. I can view it in console, and if I click it, Unity will open my code editor and I can see that this value is not defined because in the main menu scene, we don't have access to player game object and it's player controller script. Again, there are many ways to deal with it. I make sure I'm not in play mode. I will go to Layer one Game Object. I find its parallax background script component, and I click here to remove component. I also remove it from Layer two, Layer three, and layer four. Now, if I play, nothing is moving. I go to Assets scripts and I create a separate folder I call menus. Inside, I create a new monobhavior script I call Manu parallax. I open it and delete all this code. I go to Parallax Background script file, I copy all of this code, and I based it here. Inside Menu Parallax script, I remove this reference to player controller like this. Save that, and for now, it will be the only change. I select layer one game object, and I attach menu parallax script as a component. I leave move speed at zero. I also attach it to layer two, and here, move speed will be minus one. I attach it to layer three. Move speed is minus two. I attach it to layer four, and speed will be minus three. Now we have a main menu scene with parallax space effect. I have this title prefab. I want to use it here to display the name of my game. But if I just drop it in the scene like this, it will not render UI elements in Unity need to be children of Canvas. I right click UI Canvas. I will call it menu Canvas and I put the title here with Canvas as its parent game object. Menu Canvas is large, so I set render mode to screen space camera. I drag main camera into render camera field. When I set sorting layer on the canvas to UI, title is finally visible. I set its position to 00. Move tool, and I move it up. I set the text to space. I drag another title out here, parent it under Menu Canvas. This line will say Quest. The first title, Max font size is 300. The second title font size will be 310. I expand this a little, 320, 315 font size, and with Move tool, I position it vertically. This will be the title of my game in main menu scene. I also take this button brief app and I drag it into the scene as a child of menu Canvas. Vertical position will be -100. Text on the button will say Mu game. I rename it to New Game button. I drag another button prefab. I make sure it's parented under Menu Canvas. Vertical position will be -230. I rename it to quid Game button. The text will say quid game. If I play, this will be my animated menu scene. We will add a few more things later. This event system object here, that Unity created for us is responsible for processing and handling events in a Unity scene. All I want to do here is to make sure that the game supports controls without a mouse, that the game and the menus can be fully controlled by using only a keyboard or only an Xbox controller, for example. If we are in the scene playing the game and all we have is a controller and no mouse, we need to make sure one of these buttons is already selected so that we can use Control stick or directional arrow keys to switch between buttons. It's very simple. I just drag New Game button into first selected field here. So when we enter the scene while playing, new game button is already selected, allowing us to move between buttons with no mouse. I also want to call quid game function from main menu scene, but this game manager script is too involved with objects that only exist inside Level one scene. To make things simpler, I will create a separate script to handle menu buttons. I go to scripts, menus, and I create mono behavior script. I call it menu manager. I remove all of this code. I go to game manager. I copy Quid game function, and I paste it here. It will work the same. I also create another public method I call New Game. I go to assets scenes. Basically, when I call New Game from main menu, we want to load this level one scene. Lucky for us, transitioning between scenes with code is very simple in Unity. I say scene manager like this, and for this to work, we need Unity Engine scene management name space up here, and I call load scene. I passed the string with the exact spelling of how I called the scene we want to load. In this case, level one. It needs to be spelled the same as the name of this level one scene file. So when we call New Game, we take scene Manager and we load scene called Level one. Save that. New Game button selected. I find it's on click plus, actually I need my Menu manager script in the scene. So I create an empty game object. I rename it to Menu Manager. I go to scripts Menus, and I attach Menu Manager script as a component on Menu Manager Game Object. On this script, we have new game and quid game functions. We will need them now. New Game button onclick. I already pressed plus before, so I have this field, and I drag and drop Menu Manager Game Object in here. And function I want to run is here under Menu Manager New Game. Quid Game button selected plus to add onclick event, Menu manager here, and here I find Quid Game function we wrote. Okay, so now if I play and I click New Game, it should load level one scene. Perfect. That worked. I exit Play Mode. I open Level one scene. I find pose panel and I deactivate it. It needs to be invisible at first. Now that we have main menu scene ready, on pause panel, we have this menu button. So when clicked, I want to load main menu scene. I will handle that logic in game manager script. Public void, go to Main Menu. I call scene manager. I make sure we have Unity Engine scene Management name space up here, and down here, I call Load scene and pass it the name of the scene I want to load. In this case, main Menu spelled exactly the same as the name I gave to the scene file. Safe and under Post panel main Menu button, onclick event, ICliPlus I drag and drop game manager, and here I select go to Main Menu function. Now if I play, Escape to pause the game, and here I click on Main Menu button. I will get an error. Scene couldn't be loaded because it hasn't been added to the built settings. Whenever we create a new scene, we have to go to build profiles and find scene list. The scene needs to be here before I can load it with scene manager. I drag and drop main menu scene in the scene list. I put it uptop as the first scene with an index of zero. Now I can play again. I press Escape to pause the game, and now when I click Main Menu button, main menu scene loads. But you will notice that the background is not animated. It's because we entered from the pause screen when time scale was set to zero. I exit play Mode, menu manager script. Whenever start method runs, whenever we load main menu scene, set time dot Time scale 21. Make sure it's not posed. I play. Escape key to pause, main menu, scene loads, and background is animating. Now I can click New Game and we load Level one scene from the beginning. So this is how you can load different scenes in unity and jump between them. 11. Game Over Screen: I will duplicate main menu scene and I will rename it to GameOver. I open it. Title I will say game. Title two will say O. Title one will be 320 BixelsFont size. I expand this box, 310, and I move it down. Now, when do we load this scene? I save my changes and I go to level one scene. I open game manager script. Down here, I create public void GameOver function. Inside, I say scene manager, load scene GameOver. Inside player controller script, if player loses all health, we do all these things, and then I take game manager instance, and I call public Game Over function we just defined. Save that in unity, I set player Max Health to three. GameOver is a new scene, so I go to file, build profiles and scene list, and I drag GameOver scene here. I enter play mode. I hit asteroids and we get game overseen. As you can see, it loads instantly. We can't even see the animation we created for when the player gets destroyed, it doesn't have enough time to play. Inside game manager script, instead of loading scene instantly like this, I will give it a delay. I will create another function I call Show game over screen. But return type will be something called I numerator. We need to be using system collections up here for this work. I numerator is a special type of method we use to implement co routines. When we call Show game over screen, I wanted to wait for 3 seconds. I do that by saying yield, return new, wait for seconds, three F. Only after 3 seconds passed, we load the game over scene. Like this, coroutine is a method that can pause its execution and resume at a later point, making it very useful for situations where you need to delay an action. So by saying start coroutine, show game over screen, I will call this eye enumerator, which will wait for 3 seconds and only then it will load game over scene. This is an extremely common thing to do in unity. You will see it over and over many times in many projects. If you've never seen it before, I'm sure it looks strange, but don't worry about it too much. It will make more sense if you use it more often. I save changes and I play. I hit asteroids until player gets destroyed. 3 seconds count down, so the blue explosion animation will have enough time to play, and only after 3 seconds, we get the game over screen. This is how you can delay something in unity. There are many more use cases for this technique. We will explore more of it soon. 12. Particle Smoke: So. No. You can download High Resolution player image in the resources section below. I drop it into my assets art folder and I set it's Sprite mode to single. This is just one frame. I open GameOver screen, and I drop the image in. Sorting layer will be player. I set scale to 0.50 0.5, or maybe a little bit more. 0.70 0.7, like this. I rename it to player Game Over I position it here. I select Rotate tool, and I tweak the values here to rotate it to an angle. This is a game over screen, so player spaceship is damaged. Let's add a smoke effect. Unity has a built in particle system that's quick and easy to use. I right click Effects Particle system. It will create a particle system object, and we can see it's already showing us what the particles look like when they animate. I rename it to particle smoke. I will tweak just a few simple things to turn this into a smoke effect. I reset transform to center it in the middle. If you want, this is a robust system. You can create some incredibly impressive things with this. I said start lifetime to two. Inside renderer settings, I set sorting layer ID to player, order in layer minus one behind the player. You don't have to follow this part exactly. Feel free to play with the values and create your own unique particle system if you want. I will change texture to default particle material or default particle system. They seem similar. Velocity over lifetime. I want them to flow to the left because the background will be animating behind it, maybe minus two in this field. I set color to black here. Start size will be five to make it look more like smoke. Size over lifetime. I click here and I have some predefined options at the bottom now. I want them to shrink slowly until they disappear. You can also add some noise, for example, to make it more chaotic. If you play with these values, you can achieve some nice motion patterns. I go to shape and I set scale 20.2. I set shape to sphere, or circle would also work here. With Move tool, I place it under the player to make it look like smoke is coming from the crashed ship. I want them to fly to the left to match the background as if player is floating to the right through space. Start speed two, start size three, four, I move it a bit here. Okay, feel free to change this in any way you want. Make it your own. Once you are happy with it, we go to Assets Brief Abs and I drag it in here. We can reuse it later when we need black smoke coming out of something. So this will be my game over screen, but I'm not done yet. We will improve this and add more things as we flesh the game out further. If I press new game, I can play. I hit asteroids, I crash my ship, and I get game over screen. Perfect. I save my changes, and I open main menu scene. I drag large player image into main menu scene. Scale maybe 0.60 0.6. I make these numbers nicer minus two vertical position plus five units horizontal position. I rename it to player menu. Sorting layer will be player Animation tab, which as you know, can also be opened through Window animation animation. Player menu game object selected here, making sure this line says to begin animating player menu, and I click Create. I navigate to Assets animations folder, and I will call this player menu Enter. With player Menu Enter selected here, I move to the end of the timeline somewhere here. I click this record button, and I want the final animation keyframe to be where the player is right now. This will be the end of the animation. So I right click position, and I click at Key. We can see that animation keyframe here. I move the timeline all the way to the beginning and the starting position for this animation will be minus eight -11 units horizontally. I check here if the keyframe was captured and I press Play. We have a simple animation of player entering the menu screen. I can move the last keyframe until I'm happy with the movement speed. I go to Animations. I find player Menu Enter, and I want the animation to play only once when menu scene loads. So I antique loop time checkbox here. We will reuse this player animation in other places, so I will drop it into my prefabs folder. I might organize the prefabs into subfolders later. It's fine for now. 13. Mission Complete Screen: God. I duplicate game overseen. I rename it to level one complete. We could create a template that we can use for every level complete screen where we just swap values based on the current data. But I want to make a very custom screen right now. That reflects the successful result of a specific mission we will have in the first level. We are on a rescue mission to find and repair a damaged space whale. If we succeed, I want the repaired whale to fly next to us on the mission complete screen. We could, for example, in Level two, turn that whale into a special ability that the player has. Doing a reusable mission complete screen is a bit more advanced, so let's keep this beginner friendly and simple for now. I save changes and I open Level one complete scene. I delete player game over image and I delete the particle smoke effect. Instead, I will drag player menu object from prefabs. That will just animate the player floating into the scene when this screen appears. Title one will say mission. Title two will say complete. I adjust the font sizes and positioning. I duplicate new game button. I move it up in the hierarchy. I rename it to next level button. Text on it will say next level. I select new game button and position Y will be -230. Quid game button will be -360. Now we can see the next level button and everything is aligned. For now, I will antique this interactable checkbox. We have a next level button here, but I will not do anything with it for now. If you like this class, I will make the next level into something cool like a boss battle, or maybe we are escaping from a monster or we are collecting a fleet of ships, or I just turn this into Space Invaders. Not sure. I'm having a lot of fun with this project. So if I get some good requests for the second and third level, I will record a follow up class for this. I want the next level to be completely different to level one. Different gameplay mechanics. We could get very creative here. We will get back to this screen and flesh it out further in a minute. Before we do that, I save my scene and I go to level one scene. We need to create some kind of a condition. What has to happen in level one scene for the player to successfully complete the mission and see our new mission complete screen. We are on a rescue mission. We are trying to find a damaged space whale that was lost in an asteroid belt. We will set it up as a trigger, and when we interact with it, it will complete the level and it will load mission complete screen. Inside prefabs folder, I duplicate my whale one prefab and I rename it to lost whale. I double click it to enter the prefab, and inside sprite renderer component, I flip it. I want it to float upside down. It's broken and it needs to be rescued. I also grab particle smoke effect we created earlier and I drop it here into the hierarchy attached as a child of lost whale. I reset its transform to 000, and because it's a child object, that will be the center of the whale. Lost whale is on objects sorting layer, order in layer zero. So particle smoke down here under renderer sorting layer will be objects and oder in layer minus one behind the whale. Okay, lost whale object selected here, and I add component, capsule collider two D. Direction will be horizontal. I click here to edit collider, and I change the size a little bit. I tick this is trigger checkbox. By setting this to trigger, it means the collider will not register collisions with rigid body, but instead it will send on trigger Enter on trigger exit, and on trigger stay events. We will listen for these events and we will run some simple custom code when they fire. Lost whale has this whale script from before. I will remove this component. I click this arrow to go back to Level one hierarchy, and I drag and drop Lost well prefab into the scene. This will be a special type of an object in our game. When we collide with it, it will trigger mission complete. 14. Win Condition: We need to write a little bit of custom code to handle this special object. I go to assets scripts, obstacles, and I click Create Mono Behavior Script. I'll call it Lost Whale. I open it. First thing is that I want to make it float from right to left, same as the other whales and asteroids. So I open whale script. I copy the entire update method, and I paste it inside lost whale script like this. I could create a system of inheritance for all these objects that float in space so that we can have this update method in one place rather than on every object separately. Let's keep our code simple for now. I might refactor this later in an advanced section. Every object that floats in space in our game moves from right to left accounting for world speed and for player boost value, and every object gets destroyed when it moves off screen to the left. I could also do a reusable pool of objects rather than destroying them. This is not as urgent as we have only a few objects per second. But if we decide to create a bullet hell kind of game, we will need those object pools for performance reasons. I will use built in method called on trigger Enter two D. This method will work because it trigger check box is checked on lost whale collider. Argument of collider two D type called simply collider. If another game object enters the collision area and if the game object attached to its collider has a tack of player, we will take scene manager, making sure we are using Unity Engine scene management up here. We call load scene method, and the scene we want to load is level one complete. Spelled exactly like we named the scene file here. If the player finds the whale and collides with it, whale will be fixed and rescued and Mission Complete screen will load. Save that player game object selected, and I give it a player tag. If you don't have the tag here, you can always click at Tag and create it. Okay. I go to prefabs and Lost Whale. I click this little log to keep the inspector on this game object while I go to scripts obstacles, and I attach lost whale as a component. I unlock the panel here, back to the main Level one hierarchy, and I play, and the whale should now float with smoke coming out of it. Yes, I collide with it and I get an error, of course, I forgot again. Edit build profiles, scene list, and I drag and drop level one complete here. Now we can load the scene. So I play and I collide with lost whale. We get mission complete screen. Awesome. I save changes to my scene, and I open Level one complete scene. I go to prefabs and I drop lost whale into the scene. With the copy of the prefab selected here, I remove capsule collider component just from this one copy, not from the prefab itself. I also remove lost whale script. Unity will highlight these changes as the difference from the prefab. I also remove particle smoke. I flip it back and up facing this way. I move it somewhere here, and I want it to be in front of the text. So sorting layer is UI. We found, rescued and repaired the damaged space whale, and now it's following us into the next level to help us in our space adventures. I save the scene, and the game will start in main menu scene, so I open it. Actually, I open Level one scene. We created an object with a special function. When we find it and collide with it, it will complete the level and load the next scene. In our case, level one complete scene. Earlier, we created this object spawner where we define what object spawn in the game and the timeline of the spawns. So what I want for now is to have a field of asteroids, and at the end, there will be one lost whale that we have to find as a level objective. I drag lost whale here. We need more asteroids. Ten for now. After the asteroids finished spawning, we will set spawn interval to 5 seconds and we will spawn one lost whale. Let's say player missed the whale and keeps going. We set this up to endlessly repeat. So after the whale spawned, if game is still running and mission hasn't been completed, I click plus to add another wave. It will just be a single asteroid with 5 seconds spawn interval. This will create some space between whale and asteroid belt from both sides and we let the process repeat. Player will go through the asteroid swarm again and we'll get another opportunity to complete the mission by finding the lost whale. Now I can delete the lost whale from here. Let's play the game. Escape main menu. New game. We need to avoid these ten asteroids. Final game will have more than that. And here we find our mission objective. I collide with the whale and I trigger the next scene, mission complete. New game. I can also go through the asteroids and avoid the whale. If the player misses it for some reason, the whole spawn cycle will repeat, giving the player another opportunity. This setup lets you create many different mission types and objectives. You can reuse the techniques we just learned for many other situations. I was trying to come up with something simple and easy to follow. Let me know in the comments, if you have any questions. We covered so many fundamental techniques, but there's more that I want to show you. We have a pretty cool game here, but we can make it ten times better. I tick this checkbox on post panel to make it visible. I will change the background color here actually to completely transparent. I think this will look better. I deactivated again, UI Canvas selected here. I already set up Canvas scaler to make sure that UI displayed correctly on different devices. I have to do this for all Canvas elements. I open Level one complete scene, Menu Canvas selected, Canvas scalar component, and I set UI scale mode to scale with screen size. Reference resolution will be 1920 times 1080, same as here. I save all changes, and I open main menu scene. Menu kind of selected, UI scale mode set to scale with screen size, 19 2010 80, save all changes. And I open gameOseen and one more time, I set UIScale mode here and reference resolution. While we are in Game Over scene, I created another image of player spaceship, but a bit more destroyed after a game over. You can download all project art assets in the resources section below. I drag the image into my art folder. I set Sprite mode to single and apply. Player GameOver selected here, and I replace the sprite with this new one like this. I play I open Animation tab, Window animation animation. Player game over selected, and I click Create. Inside Assets animations, my new animation will be called player Game Over. I click Save player game over selected here, and I set rotation to 000. Animation tab and I enable keyframe recording mode. I right click rotation and add key. I move further down the timeline, and here I want to rotate full circle, 360 degrees. I can see the keyframe was captured here, so I play and the player is spinning, but there is some easing in and out going on. I want a linear motion. I right click the first key, both tangents linear. I do the same on the last key, both tangents linear. Now, if I play, it's just continuous linear rotation. I want to slow it down. I can move this keyframe further or I set samples to a lower value. Just find some value that looks like player lost the engines and is just spinning in space. If I play, we also get the smoke. This rotation is why I chose to have the particle smoke behind the player, but not as its child object because I don't want the particle system itself to rotate. I'm happy with my game overseen for now, but feel free to get creative and add more elements if you want. As you can see, we can add images, animations, particle effects here, so many possibilities. 15. Music and Sound Effects: C. Music and sound effects can add so much to your project. Let's open Level one scene and implement some audio. It's very easy as well. I create a new game object, I call Audio Manager. I reset its transform. I find a free sound effects back. For example, this one is pretty nice. I link it in the video description. I download it and inside my assets folder, I create a new folder, I call Audio. I unpack the sound effects. I just download it. They are numbered, so I pick six specific ones, 03 step grass, 04 fire explosion, 13 ice explosion, 39 block, 092, pause, and 098 and pause. You can use any sound files you want, but I will use these now. To play an audio file like this in Unity, we can use audio source component. I can drag and drop all these into the scene. Unity will detect that it's sound files, and it will create a game object for each one, and it will automatically give it audio source component. With all of these selected, I antique play on awake. I don't want them to play automatically as soon as the scene loads. I go to Window audio Audiomixer. In unity, Audio Mixer allows us to group sound effects and for example, control volume separately for effects and music. So let's do that here. I click plus to create New Audio Mixer. I'll call it master. Then I go to groups down here plus to create new group, and I call it effects. Plus to add another group, this one will be for music. I select all of these objects, and with all of them selected at once, I go to their audio source component, and here in output field, I will choose an audio mixer group. All of these are sound effects, so effects group selected. In the mixer here, we can control the volume of effects separately here without affecting the volume of music. We will add music soon. I will grab all of these, and I parent them under audio Manager Game Object just to keep the scene hierarchy cleaner. Go to my scripts folder and I create new mono behavior script. I call it audio manager. I select audio Manager game object here and I attach audio manager script as a component. Let's open it. I want this audio manager and all its public properties and methods to be available from other scripts. I create a public static instance. We did this before for the player, for example. I copy this awake method as always, and I paste it here to make sure we only have one audio manager instance in our project. I will create a public reference for each sound here. Public audio source, I call Ice. I save changes, and on my audio manager script, I see the field here. It's looking for audio source component, so this one here. I select audio Manager, and I drag this entire game object in the field. It will find its audio source component automatically because I defined it here as a data type. Now, I create a public function, I call play sound. It will take the sound we want to play as a parameter, so type is audio source, and I call it sound. Then I take the sound, we pass to it, and first, I call stop to make sure if we play the same sound again too fast, before the previous one finished playing, it plays from the beginning. The stop function stops audio clip from playing, and the clip plays from the beginning. Next time we play it. Then we call play like this. Okay, so custom function I called play sound. I pass it sound I want to play, for example, this one from line seven. I will first make sure the sound plays from the beginning and then it will play it. This function is public, so I call it through the public static instance of audio manager. When player takes damage and loses all health, we destroy the player, and we will play the ICE explosion sound. You can, of course, choose a different sound from the pack we downloaded. Audiomnager dot instance dot PlaySD and I play this public audio source reference. Audio Manager dot instance dot ICE. I save and play. Let's hit asteroids and when player loses all lives, ice explosion sound plays. I create more audio source variables, fire Hit pause pause. I saved changes, and now I have all these fields here. You can choose your own sounds or you can see the file names and numbers from the sound effect asset pack I'm using here. Fire will be 04 fire explosion. Hit will be 39 block sound, 092 pause here, and 098 pause here. Inside player controller, I just copy this entire line that will play a sound. We will play hit like this. When player enters boost, we play fire sound. Save that and we also want to go to Game Manager script, and when we pause the game, we play pause sound. When we unpause the game, we play unpause. Let's play and test pausing and I'm pausing tdsed We are getting hit and player getting destroyed also has a sound. Adding sounds like this massively increases atmosphere and immersion of our game. We are also using audio here for player feedback and gameplay cues. Sound provides immediate feedback to our players, and it helps player to understand what's happening and consequences of their actions. I also want to play a sound when we interact with buttons. I go to my button brief app and I add a component called event trigger. I click Add New event type, and I select Pointer Enter. Then I go to resume button here and I find its event trigger component. And here, inside Pointer event, I click Plus. I will drag and drop sound that I want to play when we hover over a button. I choose 03 step grass sound from the effects back. You can choose any sound you want. So I drag it here and I simply take its audio source component and I call play. Then I click Add New event type again, and I want a move event. When we use keyboard or a controller to navigate between buttons, this event will trigger when we move from button to button. I want the same sound to play. Unity automatically selected the sound here and it's calling play on its audio source. Perfect. This is the setup I want on all my buttons. Main menu button, event trigger component, pointer event and plus, drag my sound in here and audio source play here. Add new event type and move event that already filled its fields based on the previous event. I do the same thing for quid button plus drag sound, audiosurce play. Add new event type. Move. Also, I find my event system object that Unity usually auto generates in every scene. If you don't have it in some scenes, you can simply just copy it from another scene. To make sure we can control the game without a mouse, I need to have a value here in first selected field. I want zoom button to be selected in this scene by default. And that way, we can use directional Aro keys or gamepad control stick to move between buttons. If the device we are playing this game on doesn't have mouse connected. So if I play, you will see zoom button becomes selected. We get a sound now when we move from button to button. Adding some basic UI sounds like this makes the game feel more polished, and at the same time, it gives player confirmation that the interaction is being recognized. I save everything and I go to game overseen. I make sure I have a value on event system inside first selected field here. And on Menu Canvas, New Game button, I want to add pointer Enter sound. First, I have to make sure the sound is present in the scene. So I drag it from my audio folder output, and I choose effects audio Mixer group. I antique play on Awake, New Game button. Pointer Enter, event trigger, and I click Plus. I drag my sound here. We access its audio source component and call play when Pointer Enter happens, add new type, move, and I make sure the sound is here and play is being called. Same thing for quid Game Button, plus, drag the sound here. Audio source play here. Add new event type move. Well designed sound track can make our game more memorable. So let's include some awesome video game music that will set the vibe and atmosphere. I recommend this free nostalgia music pack, Link in the video description. It's got some amazing retro game music. I download it and I choose two tracks for this project. Game Boy and Long car journey and VCR jungle. I drag them into Assets Audio. For menus, I will use this one. I drag it into the scene. Output and I select music audio mixer group. I keep play on Awake tick and I also tick Loop. I want this music to start playing automatically when we enter the scene, and I want it to loop endlessly. I right click here and create empty. I will call this object audio. I set it as a parent of my audio object. I can also reset its transform just for my OCD. I tested by playing the game. Nice. We get music. It's a bit too loud, so that's why we created audio mixer, where we can set the volume of music and effects independently. I reduce music volume like this. Now if I play, music volume is much lower and other sound effects are easier to hear. Okay, so that's game over scene setup. I save all changes. I copy this audio object. I open Level one complete scene. And I paste it here. This way, we already have background music set up here and we have the sound effect for buttons ready to be used. Event system, and I make sure New Game button is in first selected field. Menu Canvas, next level button is disabled. Let's leave it for now. New Game button plus here, I drag the sound in and audio source play. Add new event type, move, and also on quid Game Button. Plus here, I drag my sound in Audiosurce play. Add move event. When I play, Everything animates, responds and makes sounds. Our game is starting to look pretty nice and polished. I copy the audio object. I save changes to the scene, and I open main menu scene. I paste the audio with its sound and music child objects, event system, and I make sure New Game button is first selected here. Menu Canvas, New Game button, and one last time, I set up Pointer Enter. And move events here. And I also do it on quid game button. Now, all buttons in our game give audio feedback when interacted with. Quick play test again. Audio plays. I save the scene. I open Level one scene. We want pose panel to be disabled at first, so I antique this checkbox. We will have different background music in menus and while playing. During gameplay, here in Level one scene, VCR jungle Track will play. So I drag it into the scene under Audio Manager Game Object to keep my hierarchy clean. I make sure play on awake and loop checkboxes are ticked, output here, and I select music audio mixer group like this. I play we will actually start the game from main menu here. Do you think the atmosphere of the game improved now that we have sound effects and music? Music does a lot to set the mood. There is a lot more we can do with audio in unity, but this is a pretty good base to build on. 16. Flash on Hit: Cold. Visual feedback like flash animations on hit provides immediate confirmation of an action, enhancing the clarity of gameplay and making interactions more understandable. So let's add flash animation when player gets hit. There are many tutorials online, some of them using complex shaders, but let's keep this beginner friendly. There is actually a quick and easy way to make object flash white in unity. I go to assets, resources, and I create a new folder, I call materials. Inside, I right click Create material. I call this new material white for material white. And up here in Shader I go to GY and text Shader. That's it. Now on my game object inside sprite renderer component and material field here, applying this new white material we created to this field will make the object completely white. Now we just need a little bit of code that will switch this field between white material and this sprite let default material to create white flash. I open player controller script, and I need a reference to sprite renderer component. Same process as we did for rigid body two D and animator components before. Inside start method, we use Get component like this as usual. So now this variable points to this component, and I want to access this material field. We will need a reference to the default material. And to our new white material, we just created. I will make them private but visible in Unity inspector, serialized field private. I save that, and now I have these two new fields on the player. I want this white material, so I select player again, and I drag white into white material field. Default material will be this sprite lit default. So as soon as we get a reference to Sprite render, default material will be sprite render dot material, the value of this field. We will store that in default material variable so that we can switch back to it. Now, if I save and play, this value will be referenced inside default material field. Okay, great. When player takes any damage, we set material to white material like this. Save and play. I collide with an asteroid. And you can see that material here, and player is completely white. Perfect. I can remove this serial as field. We don't need to see the default material field in the inspector anymore because we know it works. Now I want to wait for a few seconds and switch player back to its default material to give it colors again. I will do that with a co routine I enumerator, and I need system collections name space up here. I call it reset material, yield return, new, wait for seconds. 0.2 F. Here I'm saying whenever we call reset material, we will wait for 0.2 seconds, and then we will set sprite renderer material back to default material. I call this by saying start coroutine, reset material. So when player takes damage, turn it white, call reset material, which will wait for 0.2 seconds, and it will turn it back to its original colors. Save that and play. I hit asteroids and player flashes white, visually confirming the collision. Now that we know how to do this, I can also do it for the asteroid. Let's make it flash when it collides with the player, and it will also flash white when we hit it with a weapon later. I open asteroid script and we will do the same thing, which is did for the player. We will need a variable for default material and white material. Inside start method, we save a reference to the default material. I give asteroid collision enter two D function. We already know how this works. If the object asteroid collided with has a tag of player, I will do the same thing we did in player controller. We set sprite renderer material to white material and we start a coroutine, a timer that will eventually reset material back to default automatically. I grab that reset material code block here and I just copy it. I might refactor this later. For now, this is good. I numerator here only works if we are using system collections namespace. Okay, so when asteroid collides with the player, we turn the asteroid white. We call reset material, which will wait 0.2 seconds, and it will turn it back to its original colors. I save changes. I make sure player has a tag of player in this field here. I go to prefabs, asteroid, and we have this white material field. I lock the inspector to stay on this. I go to resources materials, and I drag and drop M white here. I unlock the inspector and I play. When we collide, both player and asteroid flash white. Small things like this really increase the gameplay clarity. This is the simplest technique that I know to make objects flash white on collision. Do you have a different preferred way to do this? Let me know in the comments. 17. Phaser Weapon: I go to Assets prefabs, and I create a folder I call effects. I put boom one in there and also particle smoke effect. Another folder, I call UI. I put button prefab in there, title and displayer menu animation. I create one more folder and I call it weapons. You can download bullet one image in the resources section below. I drop it into my art folder. I set Sprite mode to single and apply. I will drag and drop bullet one image into the scene. Unity created a game object for it, and it recognized it's an image, so it also gave it a sprite renderer component. Sorting layer will be player, add component, capsule collider two D. Direction is horizontal. Now, we write a simple script to make it move from left to right across the screen. I go to scripts, I create a folder, I call weapons. Inside, I create a mono behavior script, I call phaser weapon. And one more script I call phaser Bullet. I'm building the weapons with the assumption that we might want to add multiple different weapon types to the player later. So let's build our basic weapon I call phaser. I right click the player, create empty, and this game object called weapons, will be a container that will hold all player weapons. Player will always carry all the weapons here, but some might be deactivated at first. Inside weapons object, I go one level deeper and I create the first one called phaser weapon. I attach phaser weapon script to phaser weapon game object. I open the script, and I want to do a Singleton here. Public static phaser weapon instance, same as we did for the other objects before. For example, for the player. I will copy and paste this wake method as usual, just to make sure we have only one instance of phaser weapon. This phaser weapon script will be managing the bullets and hold the stats. It will need a reference to phaser bullet. It will be a prefab and we will create a copy whenever we shoot. We will also turn this into an object pool in a minute. I'll show you a quick and easy object pool implementation for using bullets to increase the performance of our game. But first, let's do the basic simple create bullet destroy bullet pattern. We will hold phaser weapon stats here. If we decide to implement weapon leveling system later, we can easily access speed and damage from here. Save that, and with phaser weapon game object selected here, I set speed to two and damage to one. Now, I open phaser bullet script, which will be attached to every single projectile we shoot. Inside update method, as the game runs for every frame, I increase transform position by some value to make the bullet move. Position has X and Y components, so plus equals new vector three, and we give it some horizontal and some vertical value. If we don't give it the third value for Z, it will default to zero. So I want to have a wrapper for all weapons. Under it, we have phaser weapon that holds phaser stats, and it will be producing one of these bullets every time we shoot. I attach phaser bullet script to bullet one here. So this script will make it move to the right. But instead of hard coding one here, I want the speed of the bullet to be taken from this speed property on phaser weapon script. So as the horizontal component of the vector, I pass it phaser weapon dot instance dot speed. Whatever is the speed value, that's how fast the bullet will fly now. Also, we have to make sure the speed is the same on any device, so we account for real time time dot Delta T. Save that, and if I play, bullet is moving to the right, two units per second. As the bullet collides with asteroids, strangely, the player is taking damage, but that is actually expected because the bullet basically acts as an extension of the player. I put the bullet as a child of the player here as if it was a body part of the player. So if the bullet collides with something, it's the same as when player collides with it. We don't want that in this case, of course. For now, I drag bullet one here to the top level in hierarchy, making sure it's not parented under anything. I also want to make sure bullets get destroyed when they reach the edge of screen. I don't want them to fly too far outside the visible game area and destroy objects off screen. If transform position dot X, horizontal position of the bullet is more than nine units, nine squares in the grid from the center, which is where the He is. We destroy the game object attached to this script, the bullet itself. We also want to track collisions on collision enter two D. If the game object this bullet collides with is tagged as an obstacle, asteroids are tagged as obstacles now. We destroy the bullet. Save that, and I go to prefabs weapons, and I drag and drop bullet one here. Let's drag a few copies out into the scene and play the game just to test this. Bulets are flying and they get destroyed when they collide with an asteroid or when they move past Unit nine. One, two, 345 6789. Phasor weapon script will manage duplicating and releasing bullets. I will give it a public function I call shoot. I need to make sure we assign a value to the prefab from line seven. Save that and phaser weapon selected, I drag bullet one prefab into this prefab field. When we shoot, we call instantiate. We used it before and we know it expects the game object. We want to make a copy of, in this case, prefab, this bullet one. We also have to give it position and rotation. So let's just pass it position and rotation of phaser weapon game object, which is a child of player game object. So it will be wherever in the scene the player is at the moment. Okay, we can call this public shoot function using this public instance. Let's call it from update method on player controller. I can just copy this block and make sure I don't make any syntax errors here. If we press left shift key or fire one event, which by default is left mouse button, we take Fas weapon dot Instance, and we call shoot function from there like this. If I click Mouse, I'm shooting. If I press left shift, it poses my game. I have to go and rebind this. I use right shift for shooting instead. Now I play. I can use left mouse button, right shift, and also game controller to shoot phaser. The bullets get destroyed when they collide with asteroids. I set speed to four. I delete all of these. I want asteroids to flash white when we hit them. On my bullet one prefab, I add tag plus new tag I call bullet and back to my bullet one prefab, and I set tag to bullet. Inside asteroid script, if object we collide with is player or bullet, we run the code that will make it flash white. Save that and I play I shoot. And we get visual feedback every time we hit an asteroid. Awesome. 18. Object Pools: Cold. I go to Assets scripts, and I create a new script I call Object Pooler. We are creating and destroying game objects in our game. It's fine if it's just a few objects per second, but with bullets, it can get out of hand quickly. Continuously creating and destroying objects can lead to performance bottlenecks. Memory allocation and garbage collection can cause sttering and frame drops. One of the most common performance optimization techniques is object pooling. Object pool maintains a set of pre instantiated objects, which can be reused when needed. Let's optimize our game and create a pool of bullets. We take them from the pool and activate them when we need them and we return them to the pool and deactivate them instead of destroying them. That way we can reuse them later. Let me show you how to create a reusable object pooler. We will use it to pull these bullets, a reset transform here, but we will later use it for other things as well. Not just the bullets, maybe other weapon types, maybe enemy projectiles. Let's see. I delete this. First, we will need the game object, some kind of a prefab that we want to reuse. For us, it will be this bullet. Public integer, I call pool size. Initially, we will create five reusable bullets, but we will also make sure we automatically add more if we run out. We will hold them in list of game objects. I call, for example, pool. To use list here, we need system collections, generic name space up here. I create a private function, I call Create Pool. First, we reset the pool, make sure it's just a new empty list, waiting for game objects to fill it. Then I run a four loop five times. And each time it runs, we create a new object. This function doesn't exist yet, so I declare it here. Private function that will return a game object called Create New Object. Inside, I will have this helper variable type is game object. I call it, for example, OBJ and it will be equal to instantiate. We want to create a duplicate of the prefab from line six up here. We also know that instantiate method expects position and rotation. So we just pass it position and rotation of the object this script is attached to. We want to create the game object, but we want to make sure it's not active, set active falls. And now we want to add this inactive game object to the pool we defined on line eight. Pool dot at because it's a list and we add that object. This functions return type is game object, so we return it like this. I want to call create pool automatically here inside start method. Okay, create Pool function has a four loop that will run five times. It will create five inactive copies of a prefab we specify, and it will add them to the pool. They will be waiting there inactive for whenever we need them. So this is how you pre instantiate your object pool. We will also need a function that will search the pool, find the first inactive and available game object, and it will give it to us. Get Pooled Object will run for each loop. It will iterate over game objects in the pool. And if it finds object that is inactive and available, I Obj dot Active self is false, exclamation mark means false. We return that object, and this function will end. It will not search anymore. If we didn't instantiate enough objects, all of them are currently active in the game and we need more. We simply create one more. We call create new game object that returns game object, and we return that here like this. We set pool size to five, so we will have five bullets initially. Every time we call get pulled Object, we search the pool for the first inactive one and we take it. If there are no inactive ones, we add one more, and we use that one, increasing the size of the pool based on our need. I create an empty game object, I call Object pools. We will put all of the pools in here. The first one will be phaser bullet Object pool. I attach Object Poller script, and it has this field waiting for a prefab. What object will this pull consist of? I go to prefabs weapons, phaser bullet pull selected here, and I drag and drop bullet one into the prefab field here. Now with this setup, instead of creating new bullet every time, we call Get pulled Object instead. Inside Phasor weapon script, instead of referencing prefab of the bullet and instantiating it every time we shoot, I create a reference to the entire Object Poller script. I call it, for example, bullet pool. I save that and I have this new field here that expects Object Pooler type. So I pass it phaser bullet Pool game object that has Object Pooler script attached. Now I can use it to call Get pulled Object function we defined on line 29. So when we shoot, don't create a new copy of a bullet prefab. I comment this out and I also comment this out. Instead, we will create a temporary helper variable of type game object. I call it Bullet. It will be equal to Bullet pool from line eight dot Get Pulled Object, and this actually needs to be public so that I can access it from other scripts. So instead of creating another copy, we take an existing copy from the bullet pool. I'm saving it in a temporary variable here like this because when we get it, I want to reset its position because if we are reusing the bullet, it might have flown somewhere off screen. So before we use it, we make sure its position is the same as the position of the weapon, which is attached to the player. After that, I can set it active. Instead of creating a new one, we are using one from the object pool. Inside Phaser bullet script, instead of destroying it when it flies off screen, I simply mark it as inactive and ready to be used again whenever needed. Same here. If the bullet collides with an obstacle, don't destroy it. Deactivate it so that we can use it later. I save that and when I play, I have these five inactive bullet one copies. Maybe I don't want them to be here at the top level. I would prefer if they are parented under Phaser bullet pool game object, keeping the hierarchy clean. We can do that by going here where we create new object, and instead of passing them position and rotation of a specific game object, I replace this with a single parent transform parameter, which will instantiate the object at parents position and rotation, and it will also make the new object a child of parent transform automatically. Now if I save and play, I expand phaser bullet pool, and I have my objects neatly organized in there. As I shoot, it will automatically increase the size of the pool if the five I originally created is not enough. If we need more than five of them to be active at the same time, as I shoot, you can see they get activated and deactivated accordingly. Now I can create some super weapons that release swarms of bullets, and thanks to the object pool we just created, our game will animate smoother. If you want to turn this into a bullet hell game, object pool is essential to have and the difference in performance will be noticeable. But 19. Particle Trails: C. Before we finish this, let's take a small break and create a blue particle trail whenever player enters super speed, given the special move a better feel. I right click player Game Object and effects Particle system. It immediately starts animating. We already created smoke effect. But let me show you how we can also make much prettier things with this. I call it engine effect. Let's give our player spaceship a proper pop when we enter boost. Let me show you how to create Particle system and how to control when it plays with code. It's simple. On my new particle system, I set start lifetime to 0.5. Down here in renderer, I set sorting layer to player, order in layer minus one behind the player. Simulation space world. Emission rate over time, much higher, maybe 200. We are in a two D space, so I change shape to circle. I want them to fly to the left to match what's going on in the game world. Velocity over lifetime, linear X, maybe -20 or minus ten. Radius from which they come out will be much smaller so that I can hide it behind the player's sprite. 0.1 seems good. I move it to the left, so maybe -0.6 -0.5, back to renderer material will be default particle. Color over lifetime. I leave this as white and this one will be color picker here. I want to match the bluish color from player jets. Let's try again. I take color from somewhere here. Yes, I move this left to make them turn blue sooner, and the top ones are for Alpha opacity. I want the particle to be completely transparent by the time it reaches the end of lifetime. Size over lifetime. I click this and down here, I select one of the predefined curves. I want the particles to grow gradually, so maybe this curve. Start speed will be two. Start size will also be two or maybe three. If you ask me, this is a pretty nice particle trail. You can, of course, edit it in any way you want. This particle effect we just created will help us to make the super speed move feel more powerful. Now I want it to play only for 1 second whenever we trigger it, and I want to disable looping. Okay, maybe just 0.5 seconds will be better. Just release a puff of fast particles like this. It will just play like this and it will stop. Now I will just play it from inside player controller script. First, we will need a reference to the particle system. I will call this one, for example, engine effect. And when we enter boost, I take engine effect and I call play. It will play just that 10.5 second loop if we set it up like we did. Save that and I have this new field for engine effect. So I drag it from here. I make sure it's a child of the player game object to make sure particle trail moves with the player. If I play, this is what it looks like. I don't want the effect to play immediately only when we enter boost, so I find play on awake and I untick it. I said boost power to four F, making the super speed a little bit slower. I think this will work better. Adding eye catching visual effects with particle systems like this has many benefits. They provide instant feedback, making actions like using our special super speed ability more satisfying and impactful. Unit is built in particle system is pretty performance efficient and has endless customization options, so I recommend you use it whenever you want to add flare and excitement to your game. 20. Destructible Obstacles: We can make the asteroids destructible. I open audio manager, and I will need a few more sound effects. Boom, too, for when we destroy an asteroid, hit rock when we hit asteroid with a bullet and shoot when we fire a phaser. Save that. I have new fields here. I go to my audio folder and I bring more sounds from the sound effect back, we download it earlier. You can use different files. You can see which ones I'm using here if you want the same sounds as me. 46 poison, also 08 step rock and 12 step wood. I drag them into the hierarchy. With all three selected, I set output to effects AudiomxerGroup, and I disable play on Awake. I put them under audio Manager Object. I move the music file up Okay, so with audio manager selected, I actually want to change what sound plays when we enter boost. I'm using this fire for enter boost sound, so I'll drop this poison sound here instead. Fire explosion we used there will instead be used for boom to when we destroy an asteroid. Hit rock sound will be this one, and shoot will be this sound. Feel free to use different ones. If I open phaser weapon script, when we shoot, I take audio manager, instance, play sound, and I want to play shoot like this. I intentionally choose a quieter sound because it will play a lot and I don't want the players to get annoyed with too much noise. Playing the same sound so often over and over can be a bit monotone. I can modify it a little bit every time we play it. Inside Audio manager script, I copy my play sound function. I rename it to play modified sound. Everything will stay the same. But before we play the sound effect, we will randomize pitch. Random range between 0.7 and 1.3. So for sounds that will play often, we can now use play modified sound function instead. Now, if I play. You should be able to hear some variety in the sound effect. Phaser weapon and speed. I increase it to 12. This will feel better. I open asteroid script and I want to randomize the size. Each asteroid will be slightly different. Inside start function, I create variable float called random scale. It will be a random value between 0.6 and one. Now I access transform scale, this set of fields, and I set it to new vector two with random scale for both horizontal and vertical scale value. You can download Meca Vale audio file in the resources section below. I drop it into my audio folder. I open Level one complete scene. When we enter the scene and we won, I want the whale to make long robotic whale call just for flavor. I can simply drop the file into the scene. I parent it under Audio to keep it clean. Output is effects and play on Awake will stay ticked. If I play, we get that extra sound. New game. I hear the new sound when we enter boost, and we have a shoot sound. We need more sounds. I save changes to level one complete scene, and I open level one scene. I want the asteroid to make sound when it gets hit. I copy this line of code. I paste it here in this block when we check if asteroid collided with player or boulet. I want to play sound I called hit Rock. I make sure audio manager hit rock has a value here. We get a sound when we shoot and we also get a sound when we hit something. This does so much for the game feel. When making a game, it's important to identify the action the player will be doing the most and make sure it feels good to press that button. In this class, I'm focusing on super speed move and shooting our pacer gun for now. Make sure the actions pop. You can do that, for example, by including particle effects, sounds, animations, make other objects react to it, and so on. We did all of that already and we can do so much more. You can download Boom two spreadsheet in the resources section below. I drop it into Assets art folder, and I open Sprite Editor. Slice grid by cell size, 400 times 400 slice and apply. I take one of the frames and drag it into the scene. We've done this before for boom one effect. I renamed this one to boom two. Sorting layer will be objects, or in layer one on top of asteroids. Animation panel, window animation animation. Boom two selected here, making sure it says boom two here, and I click Create. I navigate to assets animations like we have done before, and I create a new animation called boom two. Save that. Making sure this says boom two, I select the first frame. Go all the way down and I shift click the last frame, selecting all the frames in between. I drag them onto the timeline, and if I press play, we can see what the animation looks like in action. Samples maybe just 20. Yeah, this is good. I go to Assets animations folder. I find Boom two animation clip file and I antique loop time to make sure it only plays once. Inside script effects, we have this boom script that will destroy Game Object it's attached to after Animator finished playing all the frames of its currently active animation state. We are using it for boom one, and I can use the same script file here for boom two. If I play the game, I check if Boom two object gets destroyed when animation finishes. Yes, this is working. I exit play mode and I go to prefabs effects. I drop Boom two in here. This message can be ignored because animations will work fine. I can delete this. Let's create a reference to destroy effect inside Asteroid script. Asteroid briefap and I can see that field here. I lock the inspector. I go to effects, and I drag Boomt Briefab into destroy effect field. I unlock the inspector again. We have this reference sorted. I will add another property integer called lives. Save that and asteroid Briefap. Asteroid will have five lives. Every time asteroid collides with player or a pullet, we reduce lives by one. If lives are less or equal to zero, we instantiate destroy effect prefab. We want it at the position and rotation of the asteroid. We will also use audio Manager. We will play modified sound. I called boom two. We set that sound up earlier, if you remember. Then I can destroy the asteroid like this. Save that and I make sure I have boom to sound assigned here on Audio Manager. I play I destroy some asteroids. I need to hit each 15 times to destroy it. The artwork is blurry, so I go to Assets art, boom to image, and I need to make sure this value is more than the width of the image itself so that the image can render at full size. I click Apply. I also want to open Boom script, and I want to make sure that the effect flows to the left as the game is moving. So I create an update function. And I can copy this code from asteroid update, for example, make it move to the left accounting for world speed, whether or not the player is in superspeed and adjust for real time, like we did for other game objects as well. Now if I save, I can reset this transform to 000. There's no reason just my OCD. I like the values clean. If I play, we get an impact sound every time bullet hits an asteroid. And if we hit it five times, we get a big juice explosion. 21. Harmless Space Critters: Sold. This next feature can be considered optional, but I'm just having fun at this point. I want to add some space creatures, little critters that will float around. I will take this opportunity to show you some really cool reusable two D game def techniques we haven't covered in this course yet. And I think adding some asteroid belt wildlife is a good way to do it, and it will also improve the feel of our game, and we could even use them to hide a secret boss in the game. Maybe let's talk about this later. You can download rater One spreadsheet in the resources section below. I also made adult and both versions of these because I have a lot of ideas what to do with this. I select the image file and I open Sprite Editor. Slice grid B cell size, 80 times 80, slice and apply. I drag one of them out into the scene. Sorting layer will be player I rename it to Krater one. Inside Scripts folder, I create a new mono behavior script I call Krater one. I select Greater one game object, I attach Krater one script to it as a component, and I open the script. I want to give each one a random sprite, same as we did with asteroids. I will need a reference to its sprite renderer component. And also an array of sprites, I call sprites. Inside start method, we find sprite renderer using G component as usual. Now I want to put some values into this array, so I save changes. In unity, I see the array I call sprites here. I click Plus, I add four elements. You can see they are expecting a sprite. So I drag these in Sprite zero, one, two, and three. Now I want to access Sprite render dot Sprite, this field, and I want to assign it one of these four sprite images. The image at index of zero or one or two or three. Let's just do a random range between zero and sprites dot length. However, many images we put in this array, it will pick a random one among all of them. If I save and play, we get a random image out of these four assigned. I test it again. And I get a different one. That works. We did the same thing with asteroids. This technique only works because I'm not animating the critter and the asteroid by swapping their sprite frames. For example, with the space whale, we are swapping sprite frames to animate it. So we would have to use a completely different approach to achieve randomized skins there. But for this simple critter, this is the go to technique. Let's make them move. We used the built in physics system to move asteroids and the player through rigid body to the component and its linear velocity. For the quitters, let's use the other technique because they will not be involved in traditional physics collisions. So I can simply move them using transform dot position. Position has X and Y and Z components, so we can update all of them at the same time by using vector three, move towards built in function. We can use it to move object from its current position. Towards a target position, it's very handy here. We pass it three parameters, the current position of the critter, target position, where do we want the critter to move? And this third argument, max distance delta is basically a step. Distance to move towards the target per coal. Formats are vector three, vector three, and float. We keep that in mind when we define them. I define private float move speed, private vector three target position. Inside Start method, I just give each critter a slightly different randomized move speed between 0.5 and three. I'm trying to create a bit of a chaos, so it looks like they are thinking living creatures. Let me show you a few tricks I like to use to achieve this. I will be periodically generating random position somewhere inside the visible game area, and they will be rotating and moving towards it. Custom function, private void, generate random position. Inside, I set target position we defined up on line nine. I set it to new vector two because we care only about X and Y. We can keep the set at default. Here, we pass it some horizontal and some vertical position. And inside start method, I will call generate random position immediately so that the critter has somewhere to move towards. We are inside update, which will run at different speeds on different devices. We never want to tie movement to a frame rate. We want to tie it to a real time that is passing by. So I account for time dot Delta T here. This argument will determine how fast is the critter moving towards the target. So if I play, my critter will move from its current position towards position two horizontal, one, two, three, vertical. These position values are in units measured from the center here. Critter moved to that position because we hard coded it here, two, three. We want to randomize target position instead. Random X, the horizontal component will be a random value between minus five and plus five on the horizontal X axis. Vertical component, random Y will also be between minus five and plus five, but on the vertical Y axis. Now I can pass random X as the horizontal component of target position vector and random Y as the vertical component here. So now, every time we call random position, it will be somewhere five units from the center of the screen. Random value between minus five and plus five horizontally and random position between minus five and plus five vertically. Keep in mind that the initial position of the critter will be somewhere off screen, and the game world is also endlessly moving. So the final movement will look good. You will see in a minute. Now if I play, critter will move towards some random position in this range of five units from the middle in any direction. Now, I just want to call this generate random position over and over at a specific interval to make the critter zoom around from place to place. Move timer and move interval is all we need to achieve that. I can also randomize the interval, making the movement look more unpredictable and natural. Move interval will be a random value between 0.5 and 3 seconds. This determines how often the crater changes target position. We will count backwards. Move timer will be set to move interval. Inside update method for every frame, we check if move timer is above zero. If it is, keep decreasing move timer by real time, time dot Delta T. Else, meaning when move timer is equal or less than zero, we generate random position. We set move interval to a different random value, and we set move timer back to move interval so that it can count again towards another loop. Okay, so move timer counts time. Move interval defines the breakpoint when something happens and when the cycle resets. Inside start method, which runs only once when the crater is created, we randomize move interval, and we set move timer to that value. Inside update that runs over and over, I move timer is above zero, we keep decreasing it by Delta time. If it drops below, we generate new random position. We randomize move interval again, and we set move timer to that new value so the cycle can repeat. I save that and I play. You can see the critter is moving from position to position. We are making a good progress on this. You can probably guess what we need to do next. We need to rotate it to make sure it's looking in the direction it's moving. In unity, it's also very easy, and you will probably need this technique for so many other things in your games. Another trick to your two D game development toolkit is the following. In unity, quaternions are used to smoothly rotate objects. Quaternion is a data type that represents rotation. It can be used for both two D and three D. So same as we move to move from the current position towards target position, we will rotate from current rotation towards target rotation. The rotation depends on relative position between target position of the critter and its current position like this. We need to know where it is and where it is trying to move to determine which rotation to give it. If the relative position is not vector 30, so zero, zero, zero, we take target rotation, and we use built in quaternion dot Look rotation function. Look rotation creates a rotation that points an object in the direction of a specified vector. Often it's used to make objects face a target or direction, which is what we are doing here. Look rotation needs two parameters forward and up. As the first parameter, I pass it vector three forward, which is a shorthand for vector 3001. The second parameter will define objects orientation. We want the orientation to be towards the target position, so I use relative position from line 37 here. This approach will work if the sprites are facing up like this. You have to tweak the sprites or this code if your characters are not facing upwards on the sprite. I recommend playing with the code for a while, passing it different values here, and it should become clear how it works. It's probably not very intuitive if you see this for the first time, but that's normal. Don't worry about that. It will make more sense if you use this more often. Now that we calculated the rotation, we want to actually apply it to these rotation fields on the critter game object itself. Transform rotation is quaternion rotate towards, same as we used move towards before. I don't want the critter to rotate instantly. I want it to rotate from its current rotation towards its target rotation, we calculated on line 39 by a certain step per frame. Full rotation would be 360 degrees. So if I multiply that value times three times time the Delta time, it will rotate by this number of degrees per second. 360 times three is 1080, so I want it to rotate full circle in a third of a second, but feel free to put a different value here if you want them to rotate faster or slower. So here, same as we used to move towards target position, we are using rotates to rotate towards target rotation. These are really useful things to know for many two D games, not just for the project we are working on today. Save that and let's see if it works by playing the game. We get a critter with a randomized skin. It's moving to a random location at a random interval. And always rotate in to face where it's going. Well done, let me know if you managed to get the same result. Do you have any questions about this technique? We can talk about it in the comments. One more thing, the critter exists in the game world and we are in an endlessly scrolling game, so we need to account for that when we are placing it in the scene. We did the same thing for asteroids and other floating objects. I calculate move X, horizontal movement, which will be game manager dot instance dot World Speed, TAMs player controller dot instance dot Boost. All of that in brackets multiplied by real time. Then we take transform position of the crater, these fields, which as you can see, expects vector three format for X, Y, and Z component, and we increase the current position by a new vector three. Horizontal component is this move X, we calculate it. Vertical component will remain what it is unchanged by this and z component, if we don't define it here, it will also default to zero here. It's the exact same thing we did for the asteroid before, making sure it floats from right to left. So now if I save and I play, the quitter is still doing its thing, but now it's also floating by as the players spaceship moves through space. I exit play mode, I add component to the quitter, circle collider two D. I click here to edit collider, and I use these four small handles to make it smaller. I add another component, rigid body two D. I set gravity scale to zero. I reset transform to zero, 00 and the critter is ready to be turned into a prefab. I drag it into assets prefabs. To test it, I drag it out multiple times. And I play. They all get a random sprite and they move around as if they are alive. Currently, they collide with each other and they even push the asteroids around. I don't really want that. They need a collider because I want them to interact with bullets, but I don't want them to interact with the other objects in the game world that also have colliders. We can implement that by selecting Critter prefab here and layer ad layer. I create a new layer called critter and another layer called bullet. Back to prefabs, Critter prefab selected and I assign it to Critter Layer. I go to weapons and bullet one prefab will get bullet layer. Now I go to edit project settings and on physics to the tab, inside layer collision matrix, we can decide what interacts with what. This column is for critter interactions, so I disable Critter with critter collisions. I also disable obstacle with Critter, level boundaries with critter and player versus critter collisions. They will also ignore each other. Here, we keep this one ticked to make sure critters and bullets do interact. I delete all of these. Instead, we will spawn them dynamically using our Object spawner system. I select Object spawner game object, and I duplicate it. I renamed the copy to crater spawner. On my new reaper game object, I set number of waves to zero, deleting all of these. And plus to add a new wave of critters. Prefab we want to spawn here is this crater one, spawn interval, and I want a new crater to spawn every 1 second. We will spawn three of them. After 3 seconds, I will have another wave. I want a swarm of craters to spawn. So span interval, something low, like 0.2 seconds, and I spawn ten of them. Then the cycle will repeat back from the first wave and over and over. It's using the same object spawner script, so it will work the same as Object spawner. So we have our critters, little harmless aliens. In the final gameplay, I will use less of them. This is just for testing. Critters now ignore collisions with player and asteroids, but they do get pushed around by bullets. This is completely optional, but it would be fun if we could destroy the critters in different ways. For example, our main phaser weapon is a blue energy blast. So what would happen to the critter if it got hit by that? 22. Plasma vs Critters: C. I put together a small animation. This is what I imagine would happen. You can download a sprite sheet I called grater one Zap in the resources section below. I drop it into my art folder. I open Sprite Editor, and I slice it. Type is grid by cell size. Frames are 50 times 50. Slice and apply. So I could do this in a few different ways as usual in Unity. Let's follow the same pattern we did for destroying asteroids. I drag the first frame out into the scene. Unity will create a game object. Sorting layer will be objects. Rename it to Greater one underscore zapped. I open Animation panel KreterO zapped, selected here, making sure it's mentioned here, and I click Create. Inside Assets animations, the new animation will be called KreorO Zap. Save that. I select the first frame and I shift click the last frame. With Great one zapped here, I drag and drop all of these on the timeline. I play too fast. Five samples, too slow. 15 samples is good. I go to Assets Animations. We have this new animation controller file and the animation file. I want the dot Anim file and inside inspector, I antique loop time. I want this animation to play only once. I go to scripts effects, and we have this boom script. We attached it to player explosion and asteroid explosion effects before boom and boom two. It takes animator component and it destroys the game object when all animation frames of the current animator state finished playing. It also moves the animated effect in the game world as the scene floats by. The way we created this scriptor zapped effect, it will work the same. I can actually just simply use the same script like this. If I play, it will float left and gets destroyed when animation finished. I go to Prefabs Effects and I drag and drop Creator One zapped Game Object in here. This message can be ignored because animations will work fine. I can delete this. Now I need to go to my Greater Prefab. I open rater one script. I'll create a reference to the zapped effect briefap. We just created private variable, visible in unity editor, type is game object, and I call it zapped effect. Currently, bullets just push the critters around a little bit as the automatic physics system in unity does its job. We want to detect collisions on rater script here and do something more specific on collision Enter two D, built in function, we will instantiate that zapped effect brief upp at the current position and the current rotation of the critter, it's actually very helpful that we can pass rotation like this to make sure the critter animation will be rotated correctly, facing the same way the critter was facing. We will also destroy the critter game object itself. We will not do this on any collision, only if the object critter collided with has a tag of bullet. Instantiate greater zapped animation, which we build as a separate game object and destroy the crater itself at the same time. And in unity, prefabs weapons bullet one, and I need to make sure tag Bullet is here. I also go to Greater one prefab, Zap effect field here. I lock the inspector. I drag Greater one zapped game object in here, and I unlock the inspector. Now, if I play, let's actually try to hit one. Yes, this works. We are frying the critters using our blue Pacer weapon. We could create a different animation for different weapons. Critters can get destroyed in different ways using this technique. Let's give that effect a proper squish. I go to the sound effect pack, we download it earlier, and I will use sound 77 flash. You can use any sound you want. It's up to you. I drag it into my assets audio folder. I then drag that file into the scene. Unity will automatically give it audio source component, so I set its output to effects audio mixer group. I disable play on awake, I put it under audio Manager to keep my hierarchy clean. I open Audio Manager script. New public audio source variable I called squished. Save that. Audio manager selected here, and I drag 77 flash sound from here to my squished field here. And now I can simply play it like we did before. If Critter gets hit by a bullet, I take Audio Manager Instance. And I call play Modified sound. The sound I want to play is audio Manager Instance dot squished. You might think it's mean to fry the harmless critters with our phaser like this, but are they really as harmless as they seem? We might implement some more functionality to them. Maybe they can get angry. If you like this class and you let me know in the comments, I will show you something cool we can do here in a follow up extended version. But I will only do it if people engage with this and let me know in the comments. Otherwise, my time is better spent on other things. I want to make sure bullet gets destroyed when it hits a critter. Currently, it just flies through multiple critters and destroys all of them. Inside assets prefabs, I select critter one prefab. Tag drop down here and add TAG. Plus, I will call this new tag critter and I save. Inside prefabs weapons, I have bullet one prefab with phaser bullet script attached. On collision Enter two D, if bullet collides with obstacle or if it collides with a critter, deactivate the bullet. I save that. I select my critter prefab again and I give it a tag of Krater. If I save and play, Each bullet can now destroy only one quitter. If I play the game, we are spawning a lot of quitters. If you want to have so many of them in your final game, it makes sense to create an object pool and reuse them like we did with bullets. In my final game, I will have much less of these critters, so I will not do an object pool here. Anyway, I'm just noticing we are not destroying them at all, so we have an endlessly growing trail of critters behind us. We will do the same thing we did for asteroid here. I copy this block of code. I open crater script, and down here, I paste it. After we move the critter horizontally, if it's off screen to the left, destroy the critter. Now, if I save and play, they get destroyed when they move past this point rate. 23. Heat vs Critters: So. No. We can destroy the critter in multiple different ways and each way can have a different animation. I created another spread sheet when the critter gets burned by the heat of our ship's engines. Or maybe we can also use this when critter gets caught up in asteroid explosions. I select the image and I open sprite Editor. This is what I imagine would look like if the critter gets exposed to heat. I slice it. Type is grid by cell size, 70 times 70, slice and apply. I drag any one of these frames into the scene. I want to do the same thing we did here for Krater Zap to brief up. I can see we put it on objects layer. I change order in layer to one on top of other objects. Now I select greater burn object. Sorting layer will be objects, order in layer one. I rename it to greater one underscore burn like this. I open animation panel Window Animation animation. Reter one burn selected here, making sure it says that here as well, and I click Create. Inside Assets animations, I create a new Anim file I call reterO burn. Save that. Inside art folder, I click the first frame, and I shift click the last frame, selecting all frames in between. With Greater one burn here, I drag all of the frames on the timeline. I play the animation too fast, 25 samples. Still too fast. 15 samples? Yes, this is good. Inside Assets Animations folder, I have this new animator controller file, and we also have this animation clip file. I uncheck loop time. I want the animation to play only once. Scripts effects folder KriterO burn object selected here, and I attach boom script as a component. We already know this script will auto destroy the object when all animation frames finished playing, and it will also move it along with the side scrolling game world. I play and the object gets destroyed. Got prefabs effects, and I drag KriterO burn in here, turning it into a prefab. I ignore this message, and I delete this game object. So now we have a different animation for when the Quitter gets electrified and when it gets burned. I open KriterO script, and we will do the same thing we did with zapped effect before. First, I create a reference to the prefab. Game Object, I call, for example, burn effect. Down here on collision Enter two D, if critter collides with a bullet, we create the zapped animation. We destroy the critter and we play squished sound. Else, if the critter collides with the player and touches the hot engines, we just do the same thing. But the animation that we play is burn effect instead. I save that. Assets prefabs, critter prefab selected, and I find the new burn effect field. I lock the inspector effects folder, and I drag Critter one burn into burn effect field. I unlock the inspector. Now we have two different ways to destroy the critter. Maybe I could add more, maybe even a different animation for each weapon type. We have a lot of freedom here at this point to do whatever we want. Do you have any other creative ways how to destroy the poor cutters? Let me know in the comments. I go to edit project settings, Physics two D tab. I will enable interactions between player and critter colliders by ticking this checkbox in layer collision matrix. For this to work, Kriter needs to be on the Critter layer here and player needs to be on player layer. I go to Assets Audio and I pick another sound from the sound effect back, we download it earlier. I'll use, for example, 51 flee. I drag it into the hierarchy. Output will be Effects AudiomxerGroup, and I uncheck play on Awake. I put it under audio Manager to keep this area clean and organized. I open audio Manager script, and I create a new audio source variable I call burn. Save that. I have my new field here and I drag the sound I want to play when we burn a Kritter. Now I can go here inside Kreuter one script, and I play audio Manager dot instance dot BRN LT. Save that and play. Making things interact like this really brings the game to another level. We could do a challenge, destroy as many critters as possible in a time limit, or maybe even a better idea. If we destroy a certain number of critters, big Boss comes to check what is happening. Okay, I actually like this idea, so I will quickly go and prepare some files for animation. I'm using free dragon bones software to rig and animate my characters, but you don't have to worry about that part because I'm giving them to you, export it as a standard spreadsheet. As I play, you will notice all these scriurs and asteroids. All the things created by Object spawners are on the top level in hierarchy. I would prefer if they were parented under Object spawners and collapsible to keep this area clean and easy to navigate around. Object spawner and Greater spawner both use the same script, so I can just open it and make that change here. I exit play mode first. We are creating the objects like asteroids and critters using instantiate function, which clones the object, the prefab, we pass to it as a parameter here. We also pass it position where we want it, and what rotation should the object have. I can pass it one more argument for parent. So here, if I pass it, the transform parent of the object this script is attached to. Objects created here will be children of that parent object. Save that and if I play, asteroids and critters are no longer cluttering top level hierarchy. Instead, they are under their respective spawner parent objects. Apsib like this, much better. Now, back to my secret boss idea. So players of our game might not even see this boss. It's optional, and it will only appear if we destroy a certain number of critters. How to implement that? At this point, we did so many things with code. We are slowly turning into game developers, so it should be easy. 24. Secret Boss: You can download Bs one Spriadseet in the resources section below. I drop it into my art folder. I open Sprite Editor, and in this case, I prepared two animations here. One for charge and one for idle state. Each of these states has the same number of frames but different frame width. So I will just let Unity auto slice each frame. You can see it did a great job. We can use this. If I zoom in, it's very blurry. It's because of this max size field. I need to make sure this value is more than the width of the image of the sprite sheet to allow the image to be rendered at full size. I click Apply. Now if I open Sprite Editor, we have large and sharp frames, perfect. I can see my sliced frames here, and as usual, I will just drag one of them out into the scene. Move it here. I will rotate the set by -90 to make it face the player. Sorting layer will be objects. Now you can see this is a big boy. We have to be more careful now. This is not just a harmless space critter. I rename it to Boss one. With Boss one selected here, I go to Animation tab and I click Create. Inside Assets Animation, the first animation will be called Boss one underscore Idol. Idle animation should start here from frame 39, so I click it and I go all the way down and I shift click the last frame, selecting all the frames in between. With Bos one idle here, I drag all of these frames on the timeline. I play it so you can see what I did for idle animation. I was trying to create a bit of a creepy space insect kind of thing. It's a huge creature, so it will have to move a lot slower than this. Maybe 25 samples. I click here and create new clip. The other animation will be Boss one underscore charge. I click the very first frame here, and I go all the way to frame 38. Shift click, selecting all the frames in between. This animation will play when the boss is moving fast. It will play when the boss is entering or exiting the scene. Idle will play when the boss is patrolling around the visible game area. Okay, so we have these two animation states. I open Animator tab. I select boss one to make sure I see its states. Window animator, if you don't have the tab open. Okay, let's move this around a bit. I right click Boss one charge state, and I set it as layer default state. Boss will start in charging state when it spawns. We will switch between charge and idle depending on the parameter. Type will be Bolin, which can be true or false, and I will call it charging. I right click Boss one charge, and make transition. I drag the transition arrow to boss one idle with the transition arrow selected, inspector tab, I anti has exit time and settings transition duration will be zero. I want an instant transition. I scroll further down, and in conditions, I click Plus. Boss will transition from charge to idle state if charging parameter we defined is false. Now I write clickidl state, make transition. I drag transition arrow to charge state. With that arrow selected, again, I unchecked has exit time and transition duration will be zero. Conditions plus, and we will transition from idle to charge state I charging parameter is true, both selected here. If I play, we are in idle state because in animator window, charging is false. I check it, setting it to true, and you will see both will transition into charging state. Charging true or false determines which one of these animation states is active. Okay, that works. Inside assets scripts, I create a new folder for NEMs. Inside, I create a new mono behavior script called boss one. I attach Bos one script as a component on Bos one Game Object. I open the script. We will need to start and update functions here. I have an idea how I want this particular boss to behave. I will just write it and figure it out as I go. Let's start by this. I go to Asteroid script and I copy this code block that will move it to the left, and it will destroy it when off screen. But the boss will not just flow by with world speed. It will hover around. It will stay around longer, keeping up with the player for some time, so I delete this part. We will adjust this code some more. But first, let's define some helper variables, private float speed X and speed Y. And private bullying, I call charging. Speed X will play a role in calculating move X, the horizontal component of position vector, and we will also have move Y because the boss will sometimes move up and down instead of left and right. For now, I will just keep it simple like this. I make sure I account for Delta time because I want the movement speed to be the same on all devices regardless of frame rate. I use move Y as the vertical component of the vector here. So with this setup, let's say at first, the boss will not move at all. Speed X is zero, and all of these values multiplied by zero will always be zero. As long as speed X is zero, we are not allowing for any horizontal movement. Speed Y will be, for example, a random value between minus two and plus two. Positive values here will make the boss move up. Negative speed Y will make the boss move down. If I save and play, boss will move randomly up or down, but not left or right. What if I want the boss to bounce up and down, change direction when it reaches the edge of the screen vertically. I can say if transform position Y is more than three, or if it's less than minus three, which means if the boss moved more than three units vertically from the center of the screen, simply invert speed Y to the opposite value, making the boss move in the opposite direction, multiplied times minus one. If speed Y is positive, minus times plus is minus, this line will make it negative. If speed y is negative, minus times minus is plus. This line will make it positive. It will always switch it to the opposite of what it currently is. I can test if it works by playing the game. And yes, the boss will just endlessly bounce up and down. Perfect. What else? I want the boss to switch between patrol state where it moves up and down, and charge state where it moves fast from right to left. For patrol state, we want speed X zero and random vertical speed. For charge state, I will do a static horizontal speed of five. Maybe I remove minus here, and instead, I do negative five here. And while charging, there will be no vertical movement. Okay, so patrol state, both is moving up and down. Charge state, both is moving to the left at a high speed. We want to start in charging state. I save and play and Boss is moving fast to the left. Great. We don't have to care about the actual sprite animations yet. We will deal with that in a minute. If I start in patrol state, save and play. Boss is moving up and down. This works. We will start in charge state. We will have two helper variables, switch interval and switch timer to help us randomly cycle between these two states. When we enter paterl state, we want to stay in it for 1 second. We set switch timer to the value of switch interval because we will be counting down towards zero. When we enter charge state, we will set interval to some other value. But for now, I also leave it at 1 second. Again, we reset switch timer back to the interval value so that it can count again down for the next switch. Update function that runs over and over for each frame. Whenever we switch state, we are setting switch timer to the value of switch interval. Let's say 1 second. As the update function runs, as long as switch timer is more than zero, we are decreasing it by real time that is passing by time dot Delta time. Else, when timer finally reaches zero, we switch to the other state. If charging from line seven is true, we are in charging state, so we will switch to patrol state. Else, meaning we are in patrol state, we enter charging state. Inside both of these, we are setting timer back to interval value, so this will become more than zero, and we are counting down towards the next switch again. So now we can just define whatever we want the boss to be doing in each of these states. Inside patrol state, charging will be false. Inside charge state, charging is true. Okay, so if timer is more than zero, keep decreasing the timer. When it reaches zero, switch to the other state. Reset timer and start counting down again. Now we are switching every 1 second. So I save. I move the boss more to the right. I play, Bs is charging, patrolling, charging, patrolling, charging, patrolling, charging, patrolling. So instead of switching every 1 second in regular intervals, we will stay in patrol state for a random time interval 5-10 seconds. Charging will last between two and 2.5 seconds. Also we created a separate animation for each state, and we are transitioning between them based on the charging parameter inside animator. Let's also make sure that different animation happens. I need access to this animator component from this boss one script component. We are inside right now. As usual, private animator, I call animator. Start function, animator is equal to get component animator. I have to do it before. We call this function because inside this function, we will use the animator variable to call built in set Boole method. The animator parameter that handles animation state transitions is called charging, and here I set it to false. Here when we enter charge state, I set it to true. Save that and if I play, we start in charging state. Patrolling will use the idle animation. And eventually the boss will charge off screen. Perfect. I select boss one, add component, circle collider two D. I click here to edit collider. I make it smaller around this size looks good. I also add rigid body two D. Gravity scale is zero. If I play, Boss will get stuck on level boundaries. I move it inside. I shoot. And unities built in physics system will do its thing. First of all, we want to prevent the boss from rotating on collision. Constraints, freeze rotation, z, prefabs, weapons, I have bullet one tagged as bullet and on bullet layer. Boss one selected layer, add layer, and I call it boss. I selected here, and I set layer two boss. Tag, add tag, plus this tag will be called boss. Boss selected here, tag is boss. Rigid body to the component on the boss, mass field here, and I will make the boss much heavier, so it cannot be pushed by bullets. Okay, at this point, I need to set up which colliders interact with each other. Edit project settings, Physics two D. Bs is on boss layer. We see the column here. I disable interactions between obstacles and boss for now. Also between level boundaries and boss, and Critter and boss will also ignore each other when it comes to collision. Boss versus boss also disabled in case we spawn multiple bosses at the same time. I go inside phaser bullet script. If bullet collides with an obstacle, critter, or a boss, deactivate the bullet. Boss select it, move tool, and I move it somewhere here. It will now ignore level boundaries, critters and asteroids. It will interact with bullets and the player. Bullets do get destroyed when they hit the boss, but the boss is still moving a little bit on impact. I increase mass to 50 to make it a proper heavy weight. Okay, it seems it has no effect. Bullet is still pushing the boss around in a very subtle way. It looks like I will have to give bullet prefab, rigid body two D as well. Gravity scale zero. Mass is just a 0.1, and freeze rotation around Z axis. Okay? Now, finally the bullets collide and get deactivated when they hit the boss, but the boss is not being pushed around by the bullets at all. This is starting to look pretty good. I could reuse the sounds we already have in game, but I want a different sound when we hit the boss, so we get an audio confirmation of what we are hitting. I will grab two more sound effects from the effects pack, 52 dive and hit. You can use any sounds you want here. One will be for when we hit boss' impenetrable armor, another sound for when the boss starts charging. I drag them into the hierarchy, and as usual, with both of them selected, I set output to effects, and I uncheck play on awake. I parent them under audio manager. I open audio Manager script, and I want to create two new fields for these sounds. Public audio source I call hit armor. Another audio source I call boss charge. Inside boss script, when boss enters charge state, we call Audio manager instance. Play modified sound, and the sound we want to play is audio manager instance, boss charge. I will give the boss a public function I call take damage. It takes one parameter, integer, I call damage. When boss takes damage, we will play hit armor sound. We will also reduce the lives of the boss by the incoming damage. Up here, I give both private integer, I call lives. Inside start method, we set lives to, for example, 100. Private void on collision enter two D. If the object bus collides with has a tag of bullet, we call T damage. Our basic bullets can't penetrate boss' armor, so we pass damage of zero. We have a system ready for later if we decide to add more powerful weapons, or maybe our phaser weapon can level up, and eventually it might be able to damage the boss. We have a simple system for that here. For now, the boss is invulnerable. Save that. On audio Manager, I have these two new fields, so I drop whatever sound I want to play when boss gets hit by a bullet and when boss enters charge. Because we are putting a different sound here, we know exactly when we are hitting the boss and when we are hitting asteroid or a critter, just from the sound effects that play on that collision. It's one of the things we can do to increase gameplay clarity. I also want asteroids to be completely destroyed when they collide with the boss, making the boss feel even more powerful, like an unstoppable force of nature. Inside asteroid script, we are checking for collisions already, but I will refactor this a little bit to avoid code repetition. Same as we just did for the boss. I create public void function, I call take damage. That takes integer, I call damage as a parameter. Inside, I simply copy and paste all this code. Which means I can delete it here. If asteroid collides with player or bullet, we call take damage, and the damage will be one for now. Else, if asteroid collides with a boss, asteroid will take ten damage, which will take its lives below zero immediately, and it will trigger this block of code. I'm missing a bracket here. That's better. Before, I disabled collisions between boss layer and obstacle layer, so I need to go to edit project settings, physics to the tab, and I enable obstacle versus boss interactions. And one more thing, we created this take damage function. It takes income and damage value. I sets material to white to make the asteroid flash. It plays a sound, and it reduces lives by the income and damage value. If lives are less or equal to zero, we destroy the asteroid and we play animations. Now if I save and play, Asteroids will get destroyed on collision with boss. In player controller script, if player collides with obstacle, player takes one damage. Else, if player collides with boss, player will take five damage. Currently, player has only three lives, so colliding with the boss is an instant game over. So when does the boss get summoned? Let's handle that logic from inside game manager script. This is a secret boss. Some players might not even see it because it will only come if we destroy a certain number of critters. We will have a public integer called critter count, keeping track of how many critters got burnt or zapped by the player. Inside start method, we set critter count to zero. We will also need a reference to the boss prefab. Private game object I call boss one. Save that. I drag Boss Game Object into Assets Prefabs folder. I can delete it from here, game manager selected, and I drag and drop Boss one prefab into Boss one field here. So I have this Boss one reference here and ready. Inside update, we check if greater counter is more than ten. If it is, we reset counter to zero so that it can count again and we spawn a boss. Instantiate. We used it many times before. We pass it the game object, we want to cloud, boss one prefab, in this case, we need to pass it position where we want to spawn it. So I want it to be just off screen to the right, 15 units on the horizontal X axis to the right from the center of the scene and exactly in the middle vertically. So zero here. We also need to rotate the boss because our spread sheets are not facing left. We can rotate it by using quaternion oiler like this. X, Y, and Z rotation. Let's leave it at 000 for now, just so you can see how it works. Just for testing, we will spawn a new boss every time we fry two critters, so we will probably get multiple bosses at the same time. We will make this value different for the final game, of course. Finally, I also have to go to Critter Script, and every time Critter collides with a bullet and gets destroyed, we take game manager instance dot Critter count, and we increase it by one. We also increase it when the critter gets destroyed after touching players hot engines. These critters have no armor, so they get destroyed easily. One, two, and the third critter is more than two, so boss gets spawned. And if I destroy more critters, you get more bosses. You can see the rotation is wrong. So depending on which direction is your boss spread sheet facing, we will use this quaternion oiler to rotate it accordingly. In my case, -90 degrees on the Z axis will make the boss face to the left. Every time we destroy more than ten critters, we spawn a boss. I save that and I play. I have to destroy a few more of these and we get a boss, and it's rotated -90 degrees to face the player to the left. I exit play mode, critter spawner, and the first wave will be one critter every second for 3 seconds. And then the next wave will spawn one every 0.2 seconds three times. Then the cycle will repeat. The boss will spawn when we destroy more than 15 critters. I play to test it to see if everything works. This boss is very custom. Other bosses in our game might work in a completely different way. I play for a while to see what exactly I want to do here to finalize this. First of all, I want to make sure the boss doesn't go in patrol state when it's behind the player like this, when it moves past the player horizontally. I want the boss to just charge off screen if it moves past the player. Another thing is the way it interacts with our super speed move. When the boss is patrolling up and down, it's not affected by player entering super speed at all. It just keeps the same horizontal position. And if the player is in super speed, when the boss is charging, the boss moves unusually fast. It doesn't feel right. I want to flip it. I want player super speed boost to have no effect on the boss while it's charging and have some, but reduced effect on the boss when the boss is patrolling up and down. I want the boss to feel like it's backtracking a little bit to stay on the screen longer to pose threat for the player. But if player uses super speed, the boss is not able to back up at the same speed, and our super speed move should have some reduced effect on boss' horizontal position. I'm not sure if I'm explaining it well, but let's just implement it and it will be very clear what I mean. 25. Cleaning and Refactoring: C. On Game Manager, I set world speed down to one. Let's do some refactoring to make our code a bit cleaner. We have this world speed value here that affects how fast the background scrolls and how object spawners count time. Instead of accessing it directly from the player when we enter boost, let's make sure this can only be set through a dedicated function. Public void set world speed. It takes one parameter. Type is float. I call it speed. Inside, we set world speed from line nine to speed that was passed as a parameter here. We can use this public static instance of game manager to access set world speed function. I open player controller script. I will delete boost and boost power variables completely. I will keep this bullying I called boosting. I will make it public. This broke our code, of course, so I go down here and when we enter boost, instead of setting boost to boost power, I will set world speed. Game manager dot instance dot set Wold Speed maybe speed seven for now. That way, in our other scripts, instead of using world speed and player boost value, both of them, we can use world speed only. Copy that, and when we exit boost, instead of this line, we set world speed to one like this. When player takes damage and player health is less or equal to zero, we call exit boost and I will set world speed to zero, which will make the background stop scrolling and object spawners will stop spawning. Save that I have some more errors in console because we make objects float by based on player boost value, we just delete it. So let's fix them one by one. It's easy. Inside Greater one script, I remove this bracket. I completely remove player controller instance boost because we deleted that variable. So the speed at which objects float in space will depend only on one value on world speed because player boosting is affecting the world speed value already. Save that. I also have the same error in Parallax background script. So I open it. I deleted player boost, so I deleted here for now. Save that. We have the same error in asteroid. This line will be only world speed times Delta time like this. Save that boss one scraped. I delete this. We will come back here and finalize boss movement in a minute. Save that Object spawner will account for world speed to spawn game objects faster if the game world is scrolling by faster. Safe. We have the same error in Wale script. I will actually completely delete this script. Scripts obstacles swale delete. Okay, we are almost done with this cleanup. Lost whale script. This line will be only world Speed TAMs Delta And I have one more Csolog inside boom script. Again, world speed TAMS Delta You probably notice that we have this code that moves the object to the left as the world is scrolling by in multiple different scripts. Code repetition like this is not the best practice. It would be much cleaner if we just put this code somewhere in one place and apply it to all objects that we want to float in space. Before we do that, I save my changes. I can see there are no more console errors. I play just to check if everything is working. I player entering boost affects world speed and if world speed affects position of asteroids, critters, and so on. It's all good here. So player controller inside fixed update, I change this value to 0.5, and I will make players spend energy a little bit faster, maybe 0.5 per fixed update. Now I play, if I enter super speed, we are deleting energy much faster and we actually have to manage it as a resource now. As we said before, we have this same code here in asteroid script. We have that exact same code here in critter script, also here in lost whale script. Similar code here in Boss one script, and similar code here in Boom one. That's a lot of unnecessary code duplication. We will clean this up. Before we do that, let's finalize the boss movement and behavior. 26. Boss Behaviors: C. I want boss to be aware of player's horizontal position so that it can react to it. I will put it in a variable. I call player position. It's equal to player controller, instance, transform position X. Boss is switching between patrol state and charge state. I only want the boss to patrol up and down if it's in front of the player to the right of the player. So here we only enter patrol state if boss is currently charging and if player is to the left of the boss. And here, where the boss bounces up and down, I can do else I When boss' horizontal position is less than player's horizontal position, when boss moves to the left of the player, in case of this game, that means boss is behind the player. I want the boss to just charge off screen instantly. I make boss enter charge state. Because of these changes, boss can now enter charge state while it's already charging, so I don't want the charging sound effect to play in that case. Only play the sound if the boss is not charging. Play it only when the boss enters charge from patrol state. Okay, so let's test it. I need to destroy a few more critters, and here's the boss. If I enter super speed, the boss is keeping its horizontal position. We kind of want that. We want the boss to backtrack a little bit to stay around longer, but boss shouldn't be able to speed up and keep up with the player boosting completely, maybe only partially. Player has this static bullying called boosting. When we enter boost, we set it to true. When we exit boost, we set it to false. So inside boss one script, we need to know if it's true or false. I will actually put that line down here. I want bosses' horizontal position to be completely unaffected by players boosting when boss is charging, and I want the boss' position to be only partially affected by players boosting when boss is patrolling up and down. So let's declare move X here, and its value will depend on a few things. If player is in super speed, if boosting is true, and if the boss is not charging, Bosses horizontal position will be affected by world speed Tim's Delta time, same as other floating objects, but only half of it, making it seem like the boss is still able to backtrack and keep up at least partially. Else, if player is not boosting or boss is charging, MVX will completely ignore world speed. It will be unaffected. I think this should do what I wanted to do, but let's play and test it. I destroy critters until it summons the boss. If player enters super speed, boss' horizontal position is affected, but only partially. If player gets to the boss and moves to the right so that the boss' horizontal position is less than players, it will immediately trigger the boss to charge off screen. Okay, I will try again. I move all the way to the boss. And yes, and the other one a bit further. Yes, it triggered charge. That works. One thing I notice is that we aren't getting any sound effect when boss enters charge. It's because this line needs to be above this line. If I put this all the way up, it will work as intended. I will make the boss charge faster, maybe minus ten F. This will make it a bit more difficult to avoid. It will stay in charge state between 0.6 and 1.3 seconds. I go to Assets script, and I put rater one script inside enemy's folder. I go to prefabs and Bos one prefab. Sort in layer is objects, or layer is two. Crater one prefab, sorting layer is objects, or inlayer is three. I go to Assets Audio folder and I drop two more custom sounds in. You can download them in the resources section below. One will be a bit of a scary horror sound when the boss spawns and another sound I call Swipe for when the boss enters charge. As usual, I drop them here into hierarchy, turning them into game objects with audio source component. With both of them selected, I set output to effects, and I uncheck play on awake. I parent them under audio Manager. I open audio Manager script, and I add one more audio source variable for boss spawn. Save that. Audio manager selected, and I have this new field here. I will drag and drop boss spawn in this field, and I will drag and drop swipe to replace the existing sound we are using for Bs charge. Swipe sound is more subtle and I think it fits better. Boss script enter charge state. And here I don't want to use play modified sound, just play sound. Up here inside start method, when the boss spawns, we will play boss spawn sound effect like this. Note, I'm using play sound, not play modified sound for this one as well. I play to test this and I should get a new horror sound when the boss spawns. Yes. We are using a new sound when the boss charges. Yes, that works. 27. Utility Functions: Inside assets scripts, I create a new folder. I will call it Utils. We will have our helper utility scripts in here. Inside the folder, I create a new mono behavior script. I will call it destroy when animation finished. I open it. If I go to effects folder, we have this boom one script which destroys the game object after Animator played all its frames, and it also moves the object along as it floats in space. I want to do this in a cleaner way. I take all this code, and I copy all of this code, and I paste it here. Destroy when animation finished is my utility script. I get reference to animator component, and it will destroy game object we attach it to after all the frames of the current animator state finished playing, after the current animation finished playing, basically. So now I have this simple script with a single job. I can attach it to any object I want, and it will do that simple task B to boom script and I delete this. If I go to prefabs effects, we have these four prefabs that all should destroy when they display all their animation frames. I select Boom one and down here at component, and I find the script we just wrote, Destroy when animation finished. Boom two prefab, add component, destroy when animation finished, creater one burn, add component, and I also added here. And finally, creater one zapped, and I add that component as well. We need to make sure that objects we add this script to have animator component on them. Okay, another utility script like this. Inside script utils, I will call it float in space. I open it. I go back to Boom script. Its secondary job was for the object to float in space, considering the current world speed, which itself is affected by player's super speed move. I simply cut this code block and I paste it in here. The job of this float in space utility script will be simple. Whatever object I attach it to, it will make it animate from right to left in regards to the current world speed. We took code from boom and we split it into two separate utility scripts. I save that and back in unity, prefabs effects if I play, because of the fact that I removed all the code from Boom script, these four animations will now be static. They will not flow along with the side scrolling game world. I exit play mode, boom one prefab, add component, and I add float in space script we just wrote. And I remove boom script. Boom two prefab, I remove boom script. And I add float in space script. Creature one burn prefab. I remove boom script. I add float in space script. Creature One zapped prefab. I remove boom script. I add component float in space script. Now each one of these four prefabs has a separate script with a very specific job. This script will make it auto destroy when it finished animating. This script will make it float in space. If I play, everything should be back to normal. Objects are auto destroying and floating. That worked. I go to prefabs folder, well one prefab and I delete it. We are not using it for anything. I open asteroid script. I want to use this floating space script on asteroid so we don't have to declare it here. I can delete this entire update function. Save that. Prefabs, asteroid, and add component, and I add float in space script. Now, if I play, asteroids are floating and react to player boost as they should. That's good. Lost well prefab, lost weal script. I will delete all of this code here. Save that and back in unity. Lost Weal prefab add component, float in space. Creator prefab creator script. This code here is what I want to delete. Now, if I play, critters are not floating as they shut, so I exit play mode. And on reterPrefab at component, float in space. Now if I play, Kriters movement is influenced by world speed again. So this is how we can take a piece of code that appears on multiple objects and turn it into a component. Creating modular, reusable and focused scripts that handle specific tasks makes our project easier to maintain. So let's do one more. I go to Scripts Utils and I create a new mono behavior script. I call, for example, flash white. I opened the script, asteroid and player flash white on collisions. I want to have a script that I can attach to anything, and the script will make it flash like that. Let's see how we did it inside asteroid script. First, we declare variables for default material and white material. White material is serialized field, so it's visible in Unit editor, and here we dropped the material asset in. I don't really want to have to drop the asset in like that, so we do it differently. I copy these two lines of code and I paste them up here inside my flash white utility script like this. I can delete this entire update method. I can see we won't need it. Also, this field doesn't have to be visible in Unity inspector, so I delete serialized field. I will need a reference to sprite renderer component. Inside start method, I get component and I set default material to the value of Sprite render material field. White material will have to be handled differently because as you can see here, previously, we just drop the material here into this field. This file itself sits inside resources materials folder. I want this script to be reusable. So whatever object I attach it to, I wanted to find that M white material file in that folder. One way to do that is to say resources load material. And the path inside resources folder. I put it inside materials subfolder, so I have to say materials slash M white. So instead of dragging and dropping that asset into a field visible in unit inspector, I'm loading it directly in a script. Now that we have this, I create a public function. I call, for example, flash. In there, I will use these two lines of code. And we also need reset material block that I defined down here. So I copy this as well. When I'm using I Enumerator, I need to make sure I have system collections name space up here. When we call flash, we set material to white and we start coroutine called reset material, which will wait 0.2 seconds, and it will set material back to the original default material. Here again, we extracted a very specific task into standalone reusable script. So I can go inside asteroid script and I delete this. I can also delete this. I delete this line of code and these two lines. Instead of all of that code, I can now simply declare a variable that will point to that flash white script, which we will attach as a component in a minute. So type is flash white. Variable is flash white with a lowercase F, for example. Inside start, I just point the variable towards it using get component, and at this point, I can call this public flash method. I will call it whenever asteroid takes damage. Flash white component dot flash like this. I save that and inside prefabs folder asteroid prefab and add component flash white. Now, if I save and play, Asteroids flash white when they get hit that worked. Let's put flash white script on player as well. Inside player controller script, first, I delete this. I also delete this and I don't even need sprite renderer reference here. I delete it up here as well. I delete these two lines of code, and this entire block, no more code repetition. I save that, and now when I play and player collides with an asteroid, player will not flash white. I exit play mode, player game object selected, add component, flash white. After we add this flash white component on an object, we just have to create a variable that points towards it. I want to access flash white script component, which sits here from player controller script component we are inside of right now. So once I declare this variable, I use it component as usual. And now I simply call this public flash method to make it do its thing. Now here, when the player takes damage, take its flash white component and call the public flash function. Save that and play. And now, when player collides with asteroid, player flashes white. I would follow the same process if I wanted the boss or the quitter to flash white when it collides with something. Inside assets, prefabs, I create a folder I call enemies. I put quitter one and boss one inside. I go to script effects, and we removed everything from the boom script so I can delete the entire effects folder here. Inside scripts Utils, we have our three new utility scripts. Whenever I want to make object or to destroy when it finished animating, or I want to make object flash white on collision or float in space and react to the current world speed, I can simply attach one or more of these scripts to it. Each of these scripts has only one clearly defined job, making our code easier to read and understand. We are also reducing code repetition throughout the code base by declaring that functionality only once and then reusing it. I go to assets scenes. I open Level one complete scene. For this animated whale, we are actually reusing the lost Wale prefab. We just flipped it and remove the smoke effect. We added floating space on the prefab, so now it's on here as well, but we don't want it here. So with just this copy of a prefab selected, I will remove floating space script, just from this copy, not from the prefab itself. We can see that these changes were done here and that's how this object differs from its prefab. I enter play mode just to make sure the whale doesn't float off screen. Okay, good. Save changes to the scene, and I go back to level one scene. 28. Code Consistency: C. If I expand player game object, it holds this weapon object where we can place all different kinds of weapons layer can use. So far, we built one. I called it phaser weapon. It produces phaser bullets. In assets prefabs, we have a prefab for that bullet here. So phaser weapon has phaser weapon script, which holds the current stats of the weapon. So far, we have only speed and damage, but we can add many more. Phasor bullet script sits on the bullet prefab, and we are accessing that phaser weapon speed value through the static instance we created. Accessing the speed value like this has an advantage because if we implement weapon leveling system and weapon speed increased, that increased speed value can make the bullets move faster immediately because of this connection here. We are not really doing the same thing with phaser weapon damage value. When it comes to collisions and taking damage across our code base, I wasn't really following a consistent pattern as I was developing the project. So now it's time to clean this up. Let's have a look at how I implemented it here. We have asteroid that can take damage from bullets and it can also damage the player. Notice that when asteroid collides with a bullet, it's not looking at what damage the bullet is dealing. It just takes a hard coded damage of one. This value on phaser weapon script doesn't play any role at all in that interaction. That's a problem because if we have a weapon leveling system and this damage value increases, as we are leveling up our phaser weapon, it would have no effect on how fast we destroy asteroids. This speed value, for example, is directly connected through this phasor weapon instance to the speed value. So if speed increases, bullets would move faster. We need to make sure that damage is connected in the same way. Here on Phasor bullet script, when bullet collides with object tagged as obstacle, which is the asteroid, for example, or with critter or boss, bullet gets deactivated and put back to the pool of available ready to use objects. I want to handle this a bit differently. Inside this on collision enter function, if bullet collides with something, we will pass the weapon damage to that object. I delete this and I say, I collision game object, compare tag, is obstacle. When bullet collides with an obstacle, this asteroid is tagged as obstacle here, I might have to change this tag later. For now, we will just remember that the only thing in our game we tagged as obstacle is this asteroid. So when bullet collides with asteroid, we want to access the asteroid script on the one it collided with and pass that script the damage value to handle. So helper variable type is asteroid, and I call it asteroid. We want asteroid script component on the obstacle asteroid, this bullet collided with. We get it by taking the collision dot game object, the object tagged as obstacle, bullet just collided with, and we want this specific asteroid script component. So get component asteroid like this. So on collision with asteroid, we find its asteroid script component. This one. The reason we need it is when I open it, it has this public take damage function. I want to be able to call that function so that I can pass it phaser weapon damage value. So if we are able to find that component, I take that asteroid script component and I call its public take damage function. It expects an integer, for example, too, but I don't want to hardcode this value. I want to pass it whatever value Phasor weapon is currently dealing. So this damage value from line 11, I can access it by saying phaser weapon, Instance dot damage. Same as we are accessing weapon speed here. Okay, so when bullet collides with something, we check, does it have a tack of obstacle? So far, we have only one obstacle, this asteroid. We get a reference to its asteroid script component and we take its public take damage method. We pass it the current phaser weapon damage value, and we let T damage function handle the rest. Doing it this way is better because if our phaser weapon levels up and its damage value increases, we will be immediately dealing more damage to asteroids. Right. So now that we created kind of a template, how we will handle this, let's make sure it's consistently applied for other objects as well. Another object that collides with a bullet is this critter. I open Critter One script on collision, enter to the function here, and we are destroying the critter in two different ways depending on if it collides with bullet or with a player. Critter is a bit of a special case because taking any, even the smallest damage will destroy it. So I will leave this code as is. I could refactor it, but this code here is serving its purpose well enough at this point. We might come back to it if we need critters with more lives, for example. Another game object involved in collisions, dealing and taking damage is our Bos one brief app. I open Bos one script to see what we did here. Here we will follow the same pattern we did for Phasor bullet script. On collision entry function is for dealing damage. Here, we will pass boss' damage along to objects it collides with. We will not use it for take in damage at all, so I delete this code block. Bos has a public take damage function, so we should use that if we want the boss to actually receive damage from somewhere. Boss will receive damage from Phasor bullet. So inside phaser bullet script, we will do the same thing we did for asteroid. Else, if the object bullet collided with has attack of boss, we want to access this boss one script component. Type is boss one, and I call it, for example, boss one. It's equal to the object bullet collided with that has a tag of boss dot get component, and boss one. We want this component here. If we found that component, we call its public take damage function and we pass it the current face weapon damage value. One more thing, we want to deactivate the bullet if it collides with obstacle and we also want to deactivate it if it collides with boss. After we pass the damage value here, we then let take damage function inside Boss one script to handle the rest of that interaction. I see that function here on line 77. As you can see, it will play hit armor sound and it will reduce bosses' lives, but there is no logic to destroy the boss. So far, we don't have a weapon that is able to do that, but maybe we will implement boss destroying mechanics later, either by giving player a super weapon or by allowing Phasor weapon to level up. For now, I will leave this code block like this. The most important thing here is that we connected this damage value here. Which has been passed along here from the damage value on the weapon. So if this damage value increases, boss will be taking more damage. Here inside asteroid script, you can see that we are using on collision enter two D for asteroid to receive damage, but we don't want that. Asteroid has a public take damage function through which it can receive incoming damage. On collision enter two D is for dealing damage. That way, differently sized asteroids can deal different amount of damage, for example. Also notice the problem here that when asteroid collides with Bs, it takes ten damage. But when I open player controller script, when player collides with boss, player takes only five damage. That's why we want to clean this up. We don't want some hard coded values that I came up with randomly when I was writing this code. We want to look at boss object, check how much damage it's dealing and apply that damage value consistently, no matter what it collides with. I go to asteroid Script. As we said, to follow our pattern on collision enter two D is for dealing damage, and this public take damage function is for receiving damage from other scripts. We know asteroid can deal damage to the player. If asteroid collides with a player, we want to get access to this player controller script and pass a damage value to its take damage method. We defined here on line hundred oh eight. I need to be accessing this function from other scripts to deal damage to the player, so it needs to be public. Also here, as we said before, this is for dealing damage, not for taking damage from other objects, so I delete this. It's not a hard rule. It's just a pattern that I decided to follow in this project to keep our code more uniform. Back to asteroid here, asteroid deals damage to other objects. If asteroid collides with player, I need access to this player controller script component. I will call it player. It's equal to the player game object we collided with dot get component, and we find that player controller component. Now that this helper variable we called player holds a reference to this component. If we actually found this component, we can use it to call its public take damage function, and we want to pass it some damage value. Player controller, take damage function, we receive that damage value here, and it will handle the rest of that interaction based on whatever code we put here. Instead of this hard coded value of one, we want to pass a value from variable. Up here, I can remove serialized field from lives to hide it from Unity inspector, and I create another private integer I call damage, defining how much damage will this asteroid deal to other objects. Inside start function, I set lives to five and damage to one for now. Or maybe for testing, I set it to two. So down here, when asteroid collides with player, we will pass to damage to the player or whatever value the damage variable we just defined is. I play to test it. If everything works, players should lose lives on collision with asteroid because we set asteroid damage value to two. Yes, single collision takes two lives. Second collision takes player lives from plus one to minus one. This works. Back to asteroid script, I will set this damage value to one, but we could, for example, connect it to the mass field on asteroids rigid body component and make them deal damage based on their size or something. For now, I leave it like this. So as we said, to keep our code consistent, we try to follow a pattern where we use on collision enter to the function to deal damage to other objects, and we will have a public take damage function to receive damage. Phasor bullet script is following the same pattern. Bullet doesn't need take damage function. It doesn't receive damage from anywhere. But here in this block, it's dealing damage to obstacles and both. I just do a quick play test to make sure it's all working. We did a lot of refactoring, so just a quick test if we can still destroy asteroids with bullets. Okay, all good here. If player hits asteroid like this, player is receiving damage, but you can see that asteroid is not flashing. Asteroid is not receiving damage from the player. I do that here inside player controller script. Inside on collision Enter two D, I will follow the pattern we established. It will be similar to what we did inside phaser bullet script. So I copy this entire block of code. I go back to player controller script and I paste that code in here. We have to be careful about brackets. I make sure I'm not missing any. I remove this line of code. So when player collides with an obstacle, only obstacle type we have is asteroid. We find its asteroid script component. If we can't find it, we call asteroids public T damage function and we pass it some damage value like one, for example. In this case, I can leave the hard coded value of one because it's just player body slamming the asteroid. It will be just some minimum damage like this. I save that and if I play, if player touches the asteroid, asteroid is receiving damage and it's flashing white again. Perfect. I go to my Boss prefab and I open Boss One script. Boss has lives and it will also have damage. This value will determine what damage will the boss deal when it touches or charges into something. Inside start method, we are setting lives to 100 and we will set damage to, for example, just for testing. Again, to follow our pattern, I move this up here. Bos has a public function called take damage where it can receive damage from sources outside this script. And here in collision entry to the function, boss will deal damage to objects it collides with. Boss will deal damage to asteroids, so I go here to player controller, and I copy this entire block of code. I paste it in here. Instead of hard coded one, we pass it this damage value from line 19. Currently, we set that value to two. So if boss collides with obstacle, find asteroid script component. I found, take its public take damage function and pass it the damage the boss is dealing. Boss will also damage the player. So else if the object boss collided with has attack of player, try to find its player controller script component. I found, take public take damage function that sits on that script and pass it the damage the boss is dealing from line 19, where we set it to two. I want to test if this works. I save and play. And when boss comes, I expect it to make asteroids flash and if the player touches the boss, player should lose two lives. Yes, and yes. And now that we test did that, back in Boss one script, I said the damage boss is dealing to a higher value, maybe 20, which means in case of a collision, it will destroy player and asteroids instantly. With this code, after our refactor, Bs is dealing consistent damage. After this refactor, we have a more consistent code base, and mainly the damage objects are dealing is coming from a property on that object, which allows us to level up our weapons or make our boss grow in size and deal more damage or make asteroids deal damage based on how big they are. For example, we can get really creative with this. 29. Debugging and Game Balance: So. No. As I play the game, I notice three small easy to fix bugs, few things we had before and we somehow lost during the refactor. Bullets are not being destroyed when they hit objects. They just slide alone. Objects are not being destroyed when they move off screen, and parallax background movement speed doesn't react to players superspeed move. I exit play mode and I will deal with the bullet first. Pas the bullet script. When bullet collides with an obstacle, I set active to force to deactivate it. Also set active to force when it collides with boss. I copy this code block I remove all of this code, I have to be careful about brackets when I do this. When bullet collides with a critter, deactivate the bullet. I don't want single bullet flying through and destroying multiple critters. That was an easy fix. Next, float in space script. After we move the object from right to left in regards to the current world speed, if the object move off screen to the left, let's say 11 units from the middle of the screen, which should cover even the largest game objects we have in this game, we destroy that game object. Done, final Bfix include word speed in this calculation that sets position of each parallax background layer. One more small thing I noticed inside greater one script. We have a game that has a static camera, but we are creating an illusion of floating through space from left to right. Camera is not moving. It's static, so we are moving all the game objects from right to left to create that visual. Graters generate random position somewhere in the visible game area to move towards every 0.1 to 2 seconds. Sometimes that random position is very close to the critters current position. So it arrives to the target position a bit earlier before this code runs and picks a new random target position to move towards, which is fine. But let's move interval to higher value to make the critters set target positions less often, so we can see what happens when they hover in place and what it looks like. Critter's target position is not floating by with the rest of the game world objects. Critter is hovering in space, but at the same time, it appears to be moving to the right because of the fact that this game has a static camera. For example, look at this one. It's thinking where to go next, so it should be floating to the left. It shouldn't be able to keep the same horizontal position like this. Also, as I play, I can see bullets get destroyed when they hit objects. Game objects are being destroyed when they move off screen, and parallax backgrounds react to players super speed move, so we fixed all of that. Critter is moving from its current position towards target position. I will make sure that target position floats from right to left, depending on the current world speed, same as all other game objects. Now, if I play, Look at this critter. It's thinking where to go and it is floating to the left as it should. Perfect. Back in my script, I make critters pick random position more often, something between 0.3 and 2 seconds. We learned a lot about making side scrolling games with a static camera. If you are interested, we can take this so much further. Let's implement more poses, special events, different enemy types, environmental hazards, two player co op. Let's turn this into space invaders or vampire survivors. I can do all of that in a follow up class if you are interested. Let me know by leaving a comment. Oh. For my final build, I adjusted object spawner waves. You can add waves by right clicking one of these and duplicate array element, or you can go all the way down to the last wave and click Plus. The first wave I have here with an index of zero will spawn 20 asteroids in total, one every second. The next wave will spawn asteroid every 0.6 seconds until it spawned 40. Next wave will spawn 100 of them even faster, one every 0.4 seconds, which should create a thick asteroid field that we have to shoot our way through unless we get a boss, and it will help us to break through some of the asteroids. The next wave is ten asteroids in total, one every 2 seconds creating more empty space and the final wave is the lost whale, our mission objective that we can collide with to end the level. We miss it, the level will continue and waves will repeat from the first one again. Critter spawner uses the same object spawner script, and it will produce three waves of critters over and over. The first wave is three critters every 1 second. Then they will start coming a bit slower, 20 critters in total. Each will come every 1.2 seconds, and the third wave will spawn one critter every 5 seconds, three in total. Then it will repeat from wave one. Earlier in Game Manager, we defined that every time we destroy 15 critters, it will spawn a boss. This type of boss is more of an environmental hazard. We can't kill this boss with our basic weapon, so we just have to make sure we understand its movement pattern and we manage to avoid it to continue our mission. Object spawner is using Object Spawner script, and the same script is used by Critter Spawner. So let's open it. Can make it more precise. Here, every time we reset spun timer back to zero, we are potentially losing a few milliseconds because spun timer might be jumping by certain steps. So by setting it here to hard zero, we are losing that little difference completely, even if it's just a fraction of a millisecond. If we run this on different devices, in theory, this difference can build up over time. We can change this code just a little bit to make sure we are not discarding that left over time. One way to do it is that we will make spun timer count backwards. Let's just do it, and then I explain it. I cut this. I put it here. And we do plus equals to keep the original value, add more to it. And this line will be less or equal to zero like this. So now spawn timer is counting backwards towards zero. If span timer is less or equal to zero, we set it back to the interval value, but we don't set the value. We just add to whatever that value is, accounting for those little differences that can happen. Let's say interval is 1 second and we spawn an object. So span timer will become something around 1 second here again, and it will be counting down from 1 second towards zero. When it is less or equal to zero, we add spawn interval value to whatever its current value is here, and the cycle repeats. Save that. Object spawner and Min position object. I set its position to 15 moving it a bit further off screen. I also set it to 15 on MaxPosGame object. That way, asteroids spawn a bit further along this line. And the reason I do it is that when I play, asteroids might push each other around a bit when they spawn. I want that pop in into existence and chaotic pushing to happen well off screen outside the visible area. I select player and I slow down energy region to half of its current value. We regenerate 0.05 energy per fixed update. If I play, and we get to the part where we spawn many asteroids, you can see how they kind of pop in and push each other around. I want that pushing and shoving to happen far outside the visible game area so that the user doesn't see any jerking or snapping asteroids. This is base Game complete. Let me know if you managed to get this far by saying I did it in commans. Now, let's create some playable builds for multiple platforms. 30. Export and Deploy your Game: C. Unity is excellent at exporting our games to various platforms like Windows and web because of its powerful cross device compatibility. It allows us to create a single project like we just did and then deploy it across a wide range of devices and operating systems with minimal adjustments, whether it's for desktop, mobile or web browsers, but also Playstation, for example. Let's create a native Windows App first, and then I will show you how to turn this into a playable web game and how we publish it online so that other people can play it. I will also give you a link to the project I create so you can try to play my build. I go to Edit Build Profiles. Here, we can see all the platforms we can create a playable build for. We will focus on Windows and web today. If you want to publish for devices like Android and IOS, you can do it but make sure you add touch controls to your game first. For any build, we have to make sure we add all of our scenes into Senist here. You can edit Scenlist on this tab. As you can see, my active Build profile is set to Windows. If I want to activate another one, I select it and I go to switch platform. These platforms are great out for me because I don't have that specific module installed in my Unity Hub. If you want some of these in your Unity Hub, when installing Unity, make sure you include Build support module during installation. Select the platform. You want to create a Built four by clicking Switch platform here, which will mark it as active. You can see I already have Windows built set as active, so I select it, and I click here on Build. On my local computer, I create a folder somewhere. I called my folder build 01. The folder name is not important, and I select folder. I forgot to save changes to my project, so I click Save here. Unit two will now take some time to create a playable Windows Build. It puts all of these files in that folder and you can just find dot X file, and that's how you play your game on Windows. Create a web Build. If you have the web option here grade out, you have to install WebGL Build Module. Depending on the Unity version you are using, there might be different options on how to do it. Usually, you can go to Unity Hub, go to Installs, locate your installed version of Unity and find option to add modules. Find a module called WebGL Build Support or something similar to that if you are watching it in the future and they made small changes to this process. I have my WebGL module installed, which means I can click this web option and switch platforms here. This might take some time, so I speed this up. Now, web is marked as active for. Same as I did before, I click Build. I create a different folder somewhere on my computer. I called mine Web Build 01. I go inside and I click Select Folder. Unity will compile everything and it will create a playable web Build. On my computer, this process took much longer than Windows build, so I fast forward 9 minutes. Unity created these files and folders inside my web Build 01 folder. This is a HTML file, but when you click it, you will probably get something like this. The web Build needs to be run through a web server. If you are a programmer, you probably know many ways how to handle this. For beginners, one of the things you can do here is to go to some site that allows people to publish their web games, maybe hdtiOO in my case, I will use Unity Play. I pack all of these folders and files into zip archive. I will call it Spacequest or something. Once you have your web build zipped, you can go to play.unity.com to publish your game. Notice that I'm logged in here. It's the same login details I use in my actual UNIT editor. Once I'm logged in, I can click on the button that says Upload your game. Now it's very simple. I drag and drop my WebGL build Zip file and it will process my game. And your game Build is successfully loaded. Awesome. I give my game some title and description. You can set your game to public or private here. I will also upload thumbnail and short game play video here later, but it's just optional, and I click Save. Now I have a playable version of my game and I can share it with people by using this link up here. I will leave this link in the description down below if you want to play test my build. I can also go here and my games to see all my games I published on Unity Play. Let's give it a quick test and you can click this for full screen. You can download source code on my Github. Don't forget that when you get Unity Project from Github, Unity will open an empty untitled scene, so it looks like the project is empty. Make sure you go to Assets Scenes folder and open one of the actual project scenes from there. So this is how you build a two D space game completely from scratch, all the way to playable Windows and web Build. 31. Get Github Source Code: Cold. So this will be the base project, and I created a Github repository for the game at this stage of development. This is the URL. I will also link it somewhere in the resources down below. It's a complete Unity project with all the scripts, art assets, and it might be useful if you get stuck to compare your code to mine. If you want to open this project in Unity, you can download a ZIP file here. The whole game is only 12.5 megabytes. I have my zip archive here. I unpack it somewhere on my computer where I keep my Unity project. I open Unity Hub, I click Add and Add Project from Disk. In a pop up window, I find the place where I unzipped the Github files, and when I add it, it will appear here. When you open it, Unity will take some time to install all the necessary packages, and one confusing thing is that it might open the project like this where all you see is just this untitled scene. If you see just the untitled scene like this, let me know in the comments. I'm not sure if this happens every time or only for some people. Anyway, all I have to do here is to go to Assets scenes and I open one of the game scenes, for example, level one. And that's it. You have the same Unity project as me. We made sure our projects are identical at this stage, and this will conclude the beginning version of this class. Let's move on to some a little bit more advanced techniques, and let's make this game a lot more fun. I have an idea that I will branch this Github repository out from this stage into a few completely different game genres. I'm thinking Spacequest mixed with plans versus zombies mechanics. Or space quest, but it's got rogue like and card game elements. But how about we just do a bullet hell? But we create multiple weapons, each with their own unique upgrade tracks, and we designed some more interesting enemy types that come in increasingly difficult waves. That would be mixing our space game with something like vampire survivors. Hordes of enemies, screen full of weapon projectiles and animated effects. To be able to do something like that, we need to optimize this code base a little bit more to make sure it runs well even on older devices. When making bullet hell game, the most obvious performance improvement technique is object pool. Let's optimize the game for better performance. 32. Performance Optimizations: C. In this game, as we fly through space, we are constantly creating new asteroids here and destroying them when they move across the screen. Object pooling in unity improves performance by reusing objects instead of constantly instantiating and destroying them. I select Object spawner. Here in waves list, we map out the objects that spawn as the time goes by. We already created Object pool for bullets. I reset transform here just to keep the numbers nicer. The logic is handled here inside Object Pooler script. Here we have a prefab for the object we want to pull. For example, here we used bullet one prefab. The initial pool size is five bullets that we will pre instantiate and make sure are ready when they are needed. We have a list where we will store those five game objects. As soon as start method runs, we will call Create Pool, which will run five times, and it will create new object five times. You can see we are instantiating whatever prefab is up here. This time, it's bullet. For the next one we are about to do, this will be asteroid. We are setting its parent to make sure they are collapsible to keep unity hierarchy clean. Also have a public function called get pulled object, which will search the pool for the first inactive and available one, and it will give it to us. If we run out of available objects because they are all in use and we still need more, this logic will just create one more to make sure we always have as many as we need. It's helpful to understand this code because we are about to turn everything in our game into object pool. No more destroying objects. We are going to learn how to make object spawners work with object poolers and we will be reusing our objects. It's actually easy if we take it step by step. So we have an object pool for phaser bullets. Let's also turn asteroids into reusable pooled objects. I write click, create empty, and I call it asteroid pool. I parented under object puls to keep hierarchy clean. Asteroid pool selected here, and I drag and drop Object Pooler script on it. I want it as a component like this. Here, we need to select the prefab that we want to pull and we select the initial pool size. How many do we think we might need? If we need more, it's fine, our code will create more if we run out. I leave it at five for now. Because of the logic inside Object Poller script that we just went over, if I play, asteroid pool will already automatically fill with five inactive asteroid objects. They are grade out, inactive, so they don't appear anywhere in game. We need to adjust our object spawner code a little bit so that it can work with these object pools. Object spawner selected waves list, and I set this to one. Let's set up only the first asteroid wave. I open Object Spawner script. Here we have our wave class, the blueprint that will be reused for each enemy wave, defining what prefab to spawn in that wave, how often and how many of them to spawn before we move on to the next wave. Instead of instantiating new prefabs and then destroying them when they move off screen, we will activate reusable objects from the pool, and instead of destroying them later, we will just deactivate them, making them available later again when needed. We will leave most of this as is, but instead of using this prefab, we will use the object pooler here. Public variable type is Object Pooler and I call it pull, for example. Object Pooler type means I'm looking for that custom object Poller script component we attached on asteroid pool game object earlier. So now if I save, I have this new pull field here plus to add one more wave block, this pull field is looking for object puller component, so I drag asteroid pool game object in here and it will find that object pooler component on it automatically. We will be also spawning asteroids in the second wave for now. I can delete this prefab completely. We will not be instantiating any new prefabs in this script. We will be just pulling existing ones from our object pools. Down here, inside spawn Object, custom method. I comment this out. Instead, we create a helper variable type is game object. I call it, for example, spawned object, and here I just want to pull an inactive available object from the asteroid pool. So I say pull which is a variable here from line 14 that points to object pooler component because we dragged it in here in the inspector on that script component, we have this public get pulled object function that will cycle over objects in the pool. We have five inactive asteroids in there at first. It cycles over all of them, but as soon as it finds the first one that is inactive, which means it's available, it will give it to us and it will stop looking. If it doesn't find one because the pool is too small or because all of them are currently active in the game, it will just create a new one for us. So when I want to spawn object, I will take my object pool and I get pulled object. This code doesn't work because we don't have just a single pool here. Each wave has its own pool so that each wave can pull different objects from a different object pool. So here, I have to specify which one of these pools I want to get pulled object from. I do that by saying Waves list at index wave number dot pool. If wave number is zero, we go inside Waveslist at index zero and call Get Pulled Object from here. If wave number is one, we go to this index and G Pulled object from this pool. Let me know the comments if this makes sense or if you need more information. I can make a special video on this topic and go slower and in more detail. We know that when this line runs, we will always get spawn object. Either we get one from the inactive ones or this function creates one if there are none available. So I take that spawn object and I need to position it. Where do I want that game object to spawn? Keep in mind that we might be reusing this game object, so it can be anywhere depending on what happened during its previous active cycle. So I reset its position back to random spawn point, logic we wrote here before. I also set its rotation. I'm basically doing the same thing we did here inside instantiate. We set position, rotation, and parent. We don't have to deal with setting up the parent here because we handled that earlier inside Object Pooler script. When we wrote the logic that pre instantiates objects and fills the pool, it sets the pool itself as the parent. I can delete this so we get pulled object and reset its position and rotation. Object pools store inactive objects. So at this point, we need to set active to true, and that's it. Instead of instantiating brand new object, we pre instantiate five asteroids in our pool, and we are pulling them and activating them when we need them. I save Object spawner selected here. First wave will spawn asteroid every 2 seconds until it spawns three. Then it moves onto the second wave where we spawn asteroid every 3 seconds, but here we only spawn one. Then I will go back to the first wave again and repeat the process. We also have grater spawner that uses the same object spanner script. For now, I will deactivate it because we don't have object pool for graters. Now if I play, I have five inactive asteroids, but you can see they light up as they get activated and they appear here. If we run out of inactive ones and we need more, Object spawner will create more as needed. If I destroy one, I will get an error. Unity game object has been destroyed, but you are still trying to access it. To fix this, I go to my asteroid brief ab and I open asteroid script. Down here, where asteroid takes damage and loses all lives, we don't want to destroy it. We want to set active to falls. Active true means it's doing something in the game. Active false means that the object is sitting in the pool inactive and available when it's needed. I save and I play. Basically, now, these asteroids are pooled objects. We never want to destroy them. We only want to deactivate them, which means they will get grade out here. When they reset, sometimes their sprite renderer is stuck on white material. We are handling that logic here inside Scripts utils flash white. The issue is that the last hit sets material to white and asteroid gets deactivated. So this core routine that will reset the material doesn't actually run. I can handle that in many different ways. For example, I create a public function I call reset, which will set material back to default material immediately. When asteroid loses all lives, we call flash white reset to make sure the material is reset before the asteroid is deactivated. I save and play. I shoot to deactivate some asteroids. They flash on it, but when they reset, you can see they are not white anymore. That's great. I get one more error, and it's because we destroyed an asteroid that flew off screen. Inside float in space script. We don't want to call destroy here. We want to just say set active falls like this. Now if I play, it all works fine. I see more asteroids being added to the pool, getting deactivated and activated again as needed. And when they move off screen, there are no more errors anymore. All good here. This is how we turned asteroids from a single use object into a reusable pooled object. In our game, there will be a lot happening projectiles, robots, swarms of aliens, and animated explosions. So far, we created these four animated effects as prefabs. In game, we create a copy of one of these. We play the animation once and we destroy that copy. We are using this one, boom two when we deactivate an asteroid. We are using it as an asteroid explosion effect. Let's turn boom two from a single use object into a reusable pulled object as well. I right click Create Empty boom to pool. To keep this simple, I will make sure the name of the pool is always the same as the name of the prefab. I parent it under object pools. I go to prefabs asteroid, and here we are using boom to prefab as destroy effect. When we destroy an asteroid, boom to prefab will be created, animated, and destroyed. Let's use our pulled reusable objects here instead. I open asteroid script instead of referencing the prefab, we will reference Object Pooler. Down here, when asteroid gets destroyed, instead of creating a new instance of destroy effect from a prefab, we will get one from an object pool. Variable type is game object because it's a prefab. I call it destroy effect, but I'm not creating it here. I'm taking destroy effect pool from line ten, and I'm calling its public get pulled object function. I take that game object and its transform position and also its transform rotation will be the same as the asteroid we are about to destroy or deactivate. Objects in the pool are inactive, so I set active to true to make the animation visible in game. I delete this line. We will have an object pool that stores boom two prefabs. When needed, we take one, position it over the asteroid, and we activate it. Then we can deactivate the asteroid itself. Save that. On my boom to pool, I add component object pooler Prefabs effects, boom, two, and I drag it into the field here, telling the script that we want to pre instantiate an object pool of five boom, two prefabs and store them for later whenever they might be needed. Now when I play, I have five asteroids in asteroid pool, and I have five boom, two objects in boom two pool. I exit play mode. Asteroid prefab. This is the tricky part. Asteroid needs a reference to destroy effect pool. I want to put this boom to pool there so it can pull one of those prefabs from there when needed. If I try to do that, you can see Unity is not letting me. There are some limitations when it comes to prefabs because, for example, this asteroid prefab is an asset. It exists in the project, and it can be used in multiple scenes. This boom to pool game object exists only in level one scene. So if I drag it in here and we use asteroid in a different scene, asteroid wouldn't be able to access this boom to pool from that other scene because that object only exists in this scene. As with everything, there are many ways to approach this. I'll go with the simplest possible solution. But if you are a more advanced unit user, feel free to do it your way. I need access from asteroid prefab to this boom to pool so that we can pull objects from there and play explosion animations when asteroids get destroyed. I have this destroy effect pool defined up here. Inside start method kind of in the same way as we are looking for sprite renderer and other components that all sit on the same asteroid object. We will look for Object Pooler component, but that one sits on a different game object. So first, I have to find that game object, game object, find, and here I need to call it exactly how I called it here in hierarchy. If you later rename the object here, you need to adjust your code. That's why some people prefer other methods of doing this. Once we have that game object from it, we call Get component and we find that object Pooler component that contains our pre instantiated prefabs, as well as the public Get pulled object method that we need. This is the simplest solution to this issue, in my opinion. There are many other ways to do this. If you are a more advanced developer, you can let me know in the comments how you would do this. From asteroid prefab, we are getting reference to this game object and its Object Pooler component. I can remove this now. I save and I play. I have my boom to pool expanded, and I see five inactive pre instantiated prefabs. If I destroy an asteroid, I can see one of the boom to prefabs gets activated. Animation plays, and then I get an error. Game object has been destroyed, but you are still trying to access it. The reason for that is here inside, Utils destroy when animation finished script. We don't want to destroy the game object when it displayed all its animation frames. We just want to deactivate it so that it returns to the object pool of available ready to use objects. I will start coroutine, I call deactivate. Think of this simply as something I want to happen, but after a delay. Outside start function, I declare I numerator. For this work, we need system dot collections name space up here. I call it deactivate because that's what I call it here. And inside, I say yield, return, New, wait for seconds. This syntax might look a bit unusual, but you will use it a lot when working in unity. But how many seconds we want to wait before we deactivate it? We have that time here after the length of the animation, after the animation finished playing. I can simply copy and paste it here like this. Then we deactivate the object. For example, the boom to prefab that has this script attached as a component, and I can delete this. Okay, so we get a reference to the animator first because we will need it. Then we call a special type of function, a co routine that allows us to pause execution and resume it later. Inside, we wait for however many seconds it takes our animation to finish playing all its animation frames, and only then we deactivate the object. Let's save and play. I see my five inactive boom to objects here and let's destroy some asteroids. I can see how they are being activated and deactivated. But if I continue for a while, this one is not being deactivated anymore. How can that be? If you know, pause the video and leave a comment below. So the reason it's not being deactivated is because we are using the same five game objects over and over. And if I open this script, we have to think about what runs when and how often. Start method is called only once. Typically when the object this script is attached to becomes active in the scene. We have to keep in mind that we are working with an object pool. We are using the same set of five game objects over and over. Start method doesn't run when an object is toggled between set active true and false after it's already been initialized, which means this co routine will not run to deactivate it when we reuse the same game object for the second time. Lucky for us, Unity has a different lifecycle method called Enable. And this one is called every time the game object or the script is activated. I could have left this animator inside start because we only need this start co routine line inside on Enable, but it's fine like this. I might refactor this a bit later. Important thing we learned is that start method runs only once when the object is created, but on Enable method runs every time object is set to active, which is very useful in our situation here with object pools. I can see how my boom two objects get activated and deactivated as we play the game. One more thing we have to keep in mind when working with object pools, sometimes our objects have stats that get modified during gameplay, like the asteroids have five lives at first, but as we hit them, lives get reduced, and then when we reuse that same asteroid game object, it still has no lives left. So now I can destroy them in one hit. Exit play mode and an asteroid script. I define lives and damage up here, and I set it to some values here inside start method. This would be fine for a single use object, but not for reusable pooled object. I define private integer called Max lives. I set MAX lives to five, and I set lives to Max lives like this. Lucky for us, we just learned about Enable method that runs every time object is set to active. So anything I want to reset to its original value, I can do that here. I set lives to Max lives. This can be cleaned up a bit more, but let's see if it works. On Object spawner, I increase spawn interval to 5 seconds for the first three asteroids. They will come a bit slower. I play. I hit it five times. It has five lives. So this one also has five lives. This one also lasts for five hits, and now we are using. So this one still has five lives. Five lives as well. Perfect. We have a working object pool for asteroids and Boomto what we just did is great for performance optimization. We are reducing memory allocation because we are not creating and destroying objects frequently. We are just activating and deactivating them, and we are also reducing something called garbage collection, which is an automatic process that frees up memory by removing objects that are no longer in use. We are not destroying our objects, so we will get no frame drops caused by garbage collection. Now that we understand the concept before I can add swarms of enemies or different crazy weapons that produce thousands of bullets, will make sure that everything in our game is an object pool because we want this game to run fast and smooth. 33. Everything is an Object Pool: Go. Same as we create boom two pool for this briefap, let's also turn boom one briefap into a reusable pulled object. I right click Create Empty boom one pool. I parent it under Object pools. At component Object Pooler. I drag boom one here, and let's just create one in the beginning because we are using this boom one effect only when player gets destroyed so far, but we can use it for many other things as well. Player select it, I have that boom one prefab here as destroy effect. It's here on this line. I don't need to see it in the inspector, so I delete this. It will be Object Pooler that I call destroy effect pool. Save that. I open Asteroid script to see how we did it there. Let's just follow the same pattern. So I copy this line to find the component inside start method. This will be helpful if we decide to turn the player into prefab later, but don't worry about it at this point. Are simply repeating how we handled destroy effect for the asteroid. I copy and paste this line of code here. Destroy effect pool we defined on line 22 is game object, find, and we want boom one pool dot G component, and we want that object Poller script component that sits on it. We need Object Pooler script because it has a public get pulled object method, which we will use here. I comment this out. Instead of creating a new object, we will get one from the pool. Game Object, I call destroy effect, for example, I can actually go to Asteroids script down here. I copy these four lines of code and I paste them in here. Get pulled object from Destroy effect pool. We are pointing this variable to Boom one pool with the blue explosion effect, set its position and rotation over the player object that just got destroyed and activate the object to play the animation. I can delete this line, save that. Boom one pool selected. It has one copy of Boom one prefab, deactivated and waiting when it's needed. I collide and when player gets destroyed, use this object from the pool, and when the animation finishes playing, we deactivate it and the object is ready to be reused again. I could go to asteroid and I could use that boom one pool here instead. Save that. On Object spawner, I make the first three asteroids spawn much faster, one every 0.5 seconds. Now if I play, the blue explosions play when asteroids get destroyed. Our system is pretty flexible at this stage. You will add more of these animated explosions later, so we will be able to choose from multiple ones as we add new destructible objects and enemies to the game. I go to prefabs EMs. Let's also turn critters into reusable polled objects. At this point, we did it four times, so it should be quick and easy. I create empty game object. I will call it KriterOPool. I parent it under Object pulls. I add component object puller, I drag KreterOPrefab into this prefab field, and let's initially create five. I select Objectspwner, and the first wave, let's drag this new KreterOPool here. I adjust these values. Okay, that's fine. So what will happen now if I play? Critters are spawning, but the problem is that when I hit one, it gets destroyed. We remember from when we did the other ones that we never want to destroy object from the pool. We just want to deactivate it so that it can be reused. Also notice that these critter zap and burn objects are being deactivated and they are staying here because they don't have a pool to return to yet. We will solve all of this now. First, I go to Critter One Script. And I never want to call Destroy. I want to replace destroy with set active face in both places here and here. Save that and play. Now we are spawning critters, and as I'm destroying them, they are being activated and deactivated inside my critter one pool. Perfect. That works. I will completely delete Critter spawner. Let's just handle critters from Object spawner along with all the other game objects. I play again. Let's destroy a few more critters. And if I scroll down here, you can see that the prefabs that play animation when critters get destroyed are stacking up here, deactivated, but we are creating more and more. So I exit play mode. Prefabs effects. Let's turn this creater one burn prefab into an object pool. Step one, create a new pool, critter burn pool. Step two, give it object puller script component, drag the prefab in and define the initial pull size. One will be enough at first. Let's do the same thing for crater one Zap prefab. I create crater one zapped pull. I give it object poller component. I drag the prefab in, and the initial pull size is one. I drag both of them under object puls to keep the hierarchy clean. Inside Creator one script, instead of instantiating a new copy of a prefab here and here, we want to get a reusable object from those two object pools we just created. Up here, I remove serialized field. Type will be Object Pooler and let's call them Zap effect pool and burn effect pool. Then let's follow exactly what we did with asteroid. Inside start method, we have this line, so I copy it. And I paste it inside start method on Greater one script. I call this zapped effect pool, and it's equal to game object, find crater one underscore zapped pool. The spelling is important here and it needs to be exactly the same as this as the name of the object we are looking for. This one will be Burn Effect Pool. Again, here I make sure I spell this exactly as the name of the object we are trying to find and I get its object pool or component. Scroll down here. I commend both of these lines out. Instead, we will do the usual four lines of code, same as we did here on the asteroid. Game Object, zapped effect is zapped effect pull get pulled Object. Once we got one of these reusable pulled objects, we set its position over the critter that got hit. And importantly, we will also rotate it so it faces the same direction as the critter that just got destroyed. Otherwise, it will not look good. And then we set active to true to actually play the animation. I copy these four lines and I paste them here. Instead of zapped effect, I will say burn effect in these five places. I delete this line and also this one. Now if I play, both of these pools have just one inactive, pre instantiated, reusable game object. Look how they light up as I destroy critters. We created only one, but our coach will make more if we need to play more than one of these animations at the same time. If only one at the time plays, the first game object will be reused over and over. Additional ones get created only if multiple need to play at the same time. After playing for a while and seeing how many we are creating, it actually gives me a better idea what this initial pool size value should be. We turned all four of these effects into object pools. This goes a long way towards performance optimization for this game. We can start creating a bit more chaos now and it will run smoothly. We'll also turn Boss one prefab into a reusable pooled object. I open Boss one script, and I declare private integer. I call it Maxfs. I set it to five at first just for testing. I set damage to 20 here. And I can delete this. Inside start method, I set lives to Max lives. Currently, boss takes damage, but it cannot be destroyed. So let's write that logic. We will implement more powerful weapons soon, so if we level them up, we might actually be able to destroy the boss. If boss' lives are less or equal to zero, we deactivate it, set active falls. Save that. I go inside game manager script. We have this prefab field. Instead, I want to create an object pool, create empty. I call it boss one pool. As usual, I add component Object Pooler. I drag Bos one prefab into this field here and the initial pool size can stay at one. Inside game manager script, I remove this part, private Object Pooler, and I name it Boss one pool. Inside start method, I set Boss one pool to game object, find Boss one pool. I make sure this spelling is the same as this. And when we find this game object, I want to access this component. So get component, Object Pooler. That's good. I comment this out. Instead of creating a new copy every time we summon a boss, we will take Boss one pool and we get pulled Object. Then I take that Boss one game object. I set its position to what we did here before, just off the screen to the right. I set its rotation to -90 on Zet axis because I want the boss to be facing left. Then we call set active True and we can delete this line. I changed this to more or equal, so when we destroy the fifth critter, boss will come. When we destroy the boss, it will be deactivated. For testing purposes, we give boss only five lives. Save that and play. I destroy five graters and boss spawns. I hit the bus five times to deactivate it. Here, if I expand Bs one pool, we can see that the object is active and it's off screen here. I wait for it to charge. I destroy it. Five critters and another boss spawns. Still, we're using that same first head object. The problem is that the boss doesn't start in charging state. It starts in patrolling state, apparently. Also, there is no destroy effect, so let's start with that. I copy this line from asteroid script, and I paste it up here. Inside start function on asteroid, I copy this line, and I paste it inside start method on the boss. If we use Boom one Pool here, we will get those blue explosion animations when we destroy the boss. I will also copy these four lines from asteroid and I paste them here. When boss loses all lives, get destroy effect from object pool, set its position and rotation over the boss and activate it. I play. And when I destroy the boss, we get the same blue animation from Boom wamp, the same animation that plays when we destroy asteroids. I exit play Mode. I will also copy this line from asteroid to play some sound, and I paste it here. Save and play. I destroy the boss, and we get animation and sound. The next boss at spawns will not charge into the visible game area. It's because this code only runs once when we create the object, but it doesn't run when we activate it again later. We know from before that we can use enable method. Every time boss gets reset and reactivated, I want to set lives back to Max lives, and I want to call Intercharge state. I also want to play boss spawn sound every time it's activated and reactivated. Save and play. I get the sound now because we created the boss as we pre instantiate the object pool. I also get an error. It's because Intercharge state method needs animator reference. But that first time on Enable runs first before start method has a chance to run and actually get that component. It's good to know the execution order in which these built in lifecycle methods run. I can do a few different things here. For example, I define weak here, which runs before on enable, and I get animator reference here. So when it comes to these three methods, weak always runs first, then enable and only then start. Now if I play, I don't get animator error. I still got boss spawn sound when there was no boss spawning. Every time Bs spawns, the sound plays and boss charges, so that's good. To make sure Boss spawn sound doesn't play when we create Boss one Object pool, but only when we actually summon the boss, I can go on Boss one prefab and I can deactivate it by unchecking this checkbox here. But that will also hide the prefab image, which I think is a bit ugly. So instead, I activate it again. And in my code, I call set active falls inside awake this will run before this, so no sound will play initially when we are creating the pool and adding inactive boss object into it. The sound will play only when we actually summon the boss. I play. I can see my inactive boss one object here, waiting. I destroy five critters. This object gets activated. Sound plays, and boss charges immediately. I destroy it. If we need another boss before we deactivated the first one, Object Pooler script will create another reusable object here. It all works great. I go to assets Art and I drag and drop Boom three spreadsheet. You can download all art assets in the description below. I need to increase Mac size. We want the image at full size, sharp and not blurry. Apply. I open Sprite Editor, slice. This spreadsheet has larger frames than boom one and boom two. So we will use it when we need a bigger effect. For example, when the boss gets destroyed. Type is grid by cell size, and frames here are 600 times 600. I drag one of these frames into the scene. I rename the object to boom three. Sort in layer is objects. Order in layer is three on top of most things within Objects layer. I go to Window Animation Animation. I will dock the animation panel somewhere. I like to keep mine here. Boom three object selected, making sure this says to begin animating boom three, and I click Create. I navigate to assets animations and I will call it boom three anime. Left click, the first frame, and I shift click the last frame, selecting all the frames in between, making sure that this says boom three. I drag and drop all the frames on animation timeline. I play the animation. That's too fast. I think 20 samples is better. Inside Assets animations. Inspector tab open here. This is the new animation controller. I'm looking for this other boom three file, the animation clip, and I will uncheck loop time. I want the animation to play only once. Boom three selected here, add component, float in space, which will make it float from right to left as the world scrolls by, and I add one more component. Destroy when animation finished, which will deactivate the object and return it back to the object pool when the animation finished playing when all the frames displayed. Okay, assets prefabs, and I drag Boom three game object in here, turning it into a prefab. Now we have three different destruction animations we can choose from. I delete this, right click Create Empty boom three pull. I parent it under Object pulls at component Object Pooler. I drag boom three here, and pool size maybe two at first. Inside boss one script, we already created all the logic. All I have to do is to go inside start method and point destroy effect pool variable towards boom three pool like this. And inside asteroid script, let's use boom two pool here. We have asteroids of different sizes. So if I want, I could also scale the destroy effect based on the asteroid that got destroyed. Transform local scale is equal to transform local scale of the asteroid like this. In unity, scale is defined in these fields on every game object. Actually, let's test this with boom three pool first. I save and I play. We have two inactive objects here at first. Nice. I'm getting different sizes based on the size of the asteroid. Bos also uses boom three effect. Small asteroid. Small effect? Large asteroid. Large effect. Okay, all of that works. I exit play Mode. Inside Boss one script, I set Mxives to 100. On asteroid, I set destroy effect back to boom two. Now, the boss has 100 lives, so it can't really be destroyed with the basic weapon, but don't worry. In the next lesson, we will learn how to implement weapon level ups and we'll make our face weapon much more powerful. I get an error. It's because inside Boss one script, we destroy the boss that charges off screen. Boss is a reusable object now. So instead of destroying it, we just set active to falls. We have this boss that is summoned when a certain number of critters is destroyed by the player. I could also just plug the boss object pool into the spawner to summon the boss directly the same way it's spun in asteroids and critters. Object spawner selected, plus to add one more spawner wave, and I drag it up top so that we start with that wave. I expand object pools, and I drag boss one pool in here. The first wave will spawn three bosses, one every 2 seconds. If I play, I notice an issue. They are not rotated correctly. Even though here on the prefab, we rotate it to face left, this rotation gets overridden by the logic inside object spawner. Because here we spawn the object and we give it rotation of the spawner and spawner is not rotated. It's always zero, zero, zero. I could remove this line. And now this -90 rotation on the prefab will actually persist, and the bosses are spawning face and left as they should. Now we have an option. We can make our game more diverse by sometimes spawning a bunch of these bosses directly, or we can just leave them only spawning every time a certain number of critters gets destroyed. It's up to you how you want to design your level. This is pretty dangerous for the player. They charge unexpectedly, and they hit for 20 damage. Player will be able to level up and might eventually have more than 20 lives, but at this point, bo hitting the player is a one shot. Let's check what happened to asteroids after we commented out that line inside Object spawner that resets rotation to 000 every time a new object spawns. I changed the first wave into asteroids, spawn one every 0.5 seconds, ten in total. I play. Let's destroy some asteroids, and as they get reused, they will keep the rotation from their previous life cycle. So we gradually get new asteroids spawn and rotate it in every possible direction. It might be fine for you, but the art I'm using for asteroids has this light and dark side. So I would prefer if they reset rotation every time they respawn. I open asteroid script, and I know that whatever I want to happen every time an object from Object pool responds, I can put it inside on enable method. So to reset rotation to 000 is easy. I do that by setting transform rotation to quaternion identity like this. No matter how many times I hit the boss, I will have a pretty hard time hitting it 100 times before it charges off screen, so I can't really destroy the boss with my basic weapon. We have bullet pool. We optimize this code phase, so I can spawn many more bullets at the same time and still keep my game running smoothly. So let's do that. Let's implement leveling system for player phaser weapon. This will allow the player to shoot more faster and bigger projectiles and actually be able to destroy the boss. And then we can get creative and implement even more dangerous enemy types. 34. Weapon Leveling System: I go to Assets scripts, weapons, I right click Create Empty, and I want to create one more script. I will call it weapon. This script is where we put all the code shared for all weapon types. We have only phaser weapon now, but we might add many more if we want. I will write this code with the expectation that we will implement 20 different weapon types for the player. Let's organize our code in a way that would make it easy to manage something like that. Also, this code is a public Github repository linked in a description down below. So maybe some of you will fork it and add more custom weapons when you finish this class. But let's take it step by step. I open weapon script, phaser weapon script, and phaser bullet script. Weapon script will have code that is shared for all weapon types. Each weapon type will have the main script that manages the main logic, like producing bullets or whatever it is the weapon does, and we will have another script that sits on the prefabs that the weapon produces. In this case, phaser bullet. This script is where we handle collisions of each individual projectile. So shared script, weapon specific script and script that sits on projectiles, or if it's a completely different type of weapon, whatever is the prefab that the weapon produces. We will follow this structure for every possible weapon type we will have in this game. On the projectile, I'm using phaser weapon instance speed, and phaser weapon instance damage. Those properties sit here inside phasor weapon script, speed and damage. I will actually cut them from here. And I paste them in here. I want this weapon script to contain all the code that every weapon type needs so that we don't have to repeat it in multiple scripts. Notice that weapon extends mono behavior, and phaser weapon extends weapon inheritance. By doing this, we can treat any property that sits here on the weapon as if it was sitting directly here in phaser weapon script. I will show you exactly how it works when we write the code. I save that, and if I play, you can see everything still works. We restructured our code, but we didn't change any functionality. It all works exactly the same as before. Placing any code in here is the same as if we declared it directly inside phaser weapon script because phaser weapon class extends weapon class. Weapon is custom based class, and we will create one subclass for each weapon type. So far, we only have phaser weapon subclass. Doing this allows us to have a lot of flexibility. We can define very specific unique weapon behaviors on each subclass, while at the same time, our code is reusable and easy to maintain because we are putting all the code that is shared for all weapon types on the base weapon class. What happens if I add a few more properties, public float size, public float amount, and public float range. I'm defining them on the base weapon class, not on phaser weapon subclass, but because this class extends weapon, these properties will work the same as if they were sitting here inside phaser weapon script. I can delete this and also this. I move this uptop and I put space in between. I see this script in the inspector. If I save, I will see all these properties on phaser weapon script. They are here. I hope it makes sense. I set size to two, amount also two, and range will be three. What will these properties do? Well, they can do different things for different weapon types. It really depends what that particular weapon does. We will define what exactly they mean for phase weapon. Let's start with the most interesting property. I called it amount. Currently, amount is two, so I want to shoot two bullets at a time. I do that by wrapping this in a single four loop. I is zero, as long as I is less than amount, I plus plus, and I put all this code inside the four loop. Notice how I'm using amount. I'm simply saying amount. I'm not saying weaponscript dot amount. Save that, and let's see if this will work. I have my phaser bullet pool here and if I play, I shoot two bullets at the same time, and in this pool, we can see that they activate and deactivate in pairs. While still in play mode, I can increase amount to three. Nice. How about ten? Now we have ten bullets. Can I destroy the boss now? Yes, we are strong. That was easy. I get an error that says co routine on asteroid could not be started because the object is inactive. Once we are hitting objects by so many bullets at the same time, we can get strange errors like this. I can prevent this one by going here inside asteroid script and we will only call the flash white coroutine if lives are more than zero. Else if lives are less or equal to zero, we do all the other things we normally do when asteroid gets destroyed. I can remove this part and it will still work the same. Save and play. Phasor weapon selected. Let's do ten bullets per shot. I destroy asteroids very fast and I get no errors grade. Our weapon will also have size property. In case of phaser weapon type, size will affect the scale of each bullte. So here I say bullet, transform local scale if I go to assets prefabs, weapons, and bullet one, I'm accessing these scale fields here. We want to set X and Y. We don't have to worry about Z in this case, so new vector two, and I pass it size as both vertical and horizontal component. I reference it simple as size, even though it sits on the base class here. Save that, and let's see if it works. Size is set to two, so I expect the bullets to be double in size. 0.5 is half the size, three times the size, five times the size. Amount is five. We are making so much progress. Notice how the bullets collide with level boundaries object, but not only that, the reason they are spread out like this above each other is because they collide with each other and spread out, they push each other away. They also push the player back a bit when we should. For my game, I want to disable all of these interactions. I go to edit project settings, Physics two D and layer collision matrix tab. We can see bullet versus bullet collide. I disable that interaction. I want critter versus Bullet, obstacle versus Bullet, but I will disable level boundaries versus bullet, and I will also disable collisions between bullet and player. Okay, save that. And if I play, Notice that even if I set amount to ten, it looks like one bullet, even though here we can see ten are activated at the same time per shot. Because we disabled bullet versus bullet interaction, they no longer push each other aside and they overlap. We have ten bullets on top of each other, perfectly overlapping. We are going to write our own better logic to spread the bullets around. We will make use of range weapon property. It will define how spread out the bullets will be. We will take the amount of bullets and we will spread them evenly within the range, whatever the amount or the range is. This will make our phaser very flexible, and we will have all these properties we can tweak and customize it. To spread bullets evenly within a specific range, we need to calculate what will be the spacing between the bullets. Spacing will be the range divided by the amount of bolets minus one. I'll explain y minus one in a minute. Let's just write the logic down, and then we will explain it in a little visual once we have all of it. Vertical Y position of each bullet will be the vertical center point, so the vertical position of the phaser weapon, which sits directly on the players spaceship object. So position of phasor weapon is always the same as position of player object as the player moves around. Plus index from the four loop times spacing. Keep in mind, we are inside a four loop. So as we create one bullet after another, depending on what the amount is, Y is increasing and placing bullet after bullet, and their spread depends on the spacing variable. To see visually what this value actually does, let's apply it to the bullets position. Bullet transform position is new vector two because we want to set just X and Y component. I keep the horizontal position as the current position of the phaser weapon. But for vertical position, we will use Y pose, which should spread the bullets within range we specified here. Save and play. We have two bullets spread within a range of three units. Units are visible in scene view as this grid. One cell in the grid is one unit. So range of three is three of these units. Three bullets now, they spread evenly within the same range. That part works, but I want the spaceship to be in the center vertically. Look what happens if I change the range value. Whatever amount we have here is spread within a range we define. For example, if I stop this now, we have four bullets evenly spread out in a range of one unit. Four bullets spread out within a range of four units. I can see that our spacing formula is working well. I center the range around the spaceship vertically by moving the vertical position of all the bullets down by half of the range. So this will happen. I save and play. Did that work? Two bullets. Three bullets. Four bullets. Five bullets. Five bullets in range of one unit. I think we can actually destroy the boss now. Amount of seven spread across the range of two units. I can play with these values to check, but I can already see our formula is correct. It will always spread whatever amount of bullets we have here, across whatever range we define here. There is one issue with this formula. Look what happens when I set amount to one. Maybe at first, we want to start with just one bullet, but that will actually give me an error. I can see the vertical component of the position vector is non, not a number. So when amount is one, this formula breaks because one minus one is zero, so we are dividing range by zero, and we can't do that. We need to say amount minus one here to spread them evenly within a range because we want to divide the range by the number of gaps, not by the number of bullets. We need the size of the gap, basically. There will always be one less gap than the total number of bullets. That's why amount minus one because two bullets have one gap. The bullets is two gaps, four bullets is three gaps, for example, spacing value is the size of these gaps, basically. Then we center the range around the player spaceship, and the first bullet is zero times spacing. Second bullet is one times spacing. The third bullet is two times spacing, for example. To be honest, you don't really have to understand these two lines. It's just a standard formula that's always used for this kind of a thing. You can easily Google it when you need it. Your skills as a game developer are completely unrelated to being able to write math formulas like this, especially if you are a beginner, so don't worry about this code too much. This is the only part of the class where I allow you to just copy my code and don't worry about actually understanding it. We know it works and it spreads the bullets within a specific range, and we just need to make sure this code doesn't break when amount is one. I will go with the simplest solution. If amount is more than one, I put this code here. When I do that, we can't access Y position here. It's outside its scope. So I define it one level up here, and inside, I just give it a value, and I also need to give it default value. Amount is one, vertical position will be zero just on top of player. If amount is more than one, we do our vertical spacing formula. And actually, I don't want the zero here because the player is moving around. I want the default vertical position when amount is one to be wherever the player is vertically at the moment like this. We always position it over the player, but if amount is more than one, we override that Y position value. If amount is one, this code block will be skipped. If you have any questions or improvements to this code, let me know and let's talk about it in the comments. I save that and let's test it. Amount is one that works. Amount two, amount four, range three, five bullets spread within three units. Ten bullets spread in a range of three units, 20 bullets, and we have an unstoppable wall. I can also increase the range and the bullets will still evenly spread in whatever range we define. I could store these values in a scriptable object, for example, but I will go with a simple object oriented approach here. This is a beginner friendly class. Every weapon will have one more property. Integer that defines weapon level, and for each weapon level, I want to define values for each one of these stats. I will do it in a way that's easy to understand and read. We will have a helper class, public class weapon stats. Notice I'm defining a class within a class. I copy these properties inside the class like this. And every weapon will also have a list. I need system collections generic to use a list, and it will be a list where each element is an instance of weapon stats class. I will call that list, for example, starts. In a minute, I will show you visually what we are doing. It will be easier to understand when you actually see it. I know from before that because phaser weapon extends weapon, I can treat all these properties as if they were declared on phaser weapon script directly. And if I save on phaser weapon game object, I can see this weapon level property, even though I didn't define it on phaser weapon script. It's defined on the base weapon class. But how come I see this, but I don't see my list of stats? It's because this weapon stats class, even though it's public to see it in Unity Editor, I need to serialize it system dot SerializB like this. Now if I save, I have the stats list here. This is the list, and each element in that list will be an instance of this class. What does that look like? I expanded. And plus to add element. You can see it will use weapon stats class as a blueprint to add stats for each weapon level. It will be replacing these, but if I remove them right now, I will break the code. So let's do it step by step. Stats list, the first element with index of zero will define the breakdown of stats for each weapon property when phase weapon is on weapon level zero. Five speed, one damage, size is one, amount is one, and range is one. Plus to add one more element. This will be weapon starts when we get to weapon level one, speed of ten, two damage, size of two, amount of two spread within a range of two units, plus to add one more block. When weapon level is two, speed will be 15, damage will be three, size of each bullet will be 2.5, amount is five and bullets will be spread across a range of three units. So we have this weapon stats class that defines a blueprint. We have a list of weapon starts. Each element in this list will represent one weapon level. So as weapon level increases, we move from block to block, and we apply all these starts to our weapon based on its current weapon level. When weapon level starts at zero, phaser weapon will be taking values from this block of stats. When we level up and get to weapon level one, phaser weapon will change based on values in this block. Weapon level two will be values from this block. So instead of accessing this single amount value that I'm about to delete, I want to access one of these amount values from my starts list and which one of them I will be accessing depends on the value of weapon level. I take stats list at the index of weapon level dot amount. This is the stats list. This is weapon level. So for example, when weapon level is zero, we take stats list at index zero, and we access this amount value. We will produce only one Bolt. When weapon level increases to one, we will access stats at index one, this block, and this amount value, which is two. So we will produce two Blites. I also have to do the same thing for amount here and also here. Depending on whatever the current weapon level is, we are accessing different amount values in stats list. The same thing will apply for all other stats. This block is for weapon level zero. This is weapon level one, and this is weapon level two. We can add as many weapon levels as we want, and we will add more soon. At this point, we replaced this amount with this value from line 20, so I can actually delete this and the code will still work. I save and I play to test it. Weapon level is zero. We are using this block. Amount of bullets is one. If I manually increase weapon level to one here, we are accessing this block, this amount value of two. If I set weapon level to two, we are accessing this amount value of five. Our code works. I want to replace all these remaining starts with these values that change based on weapon level. So let's do it. What else do I have in phase weapon script? I want this range value to dynamically change as well, based on the current weapon level. It's in two places. So I say starts at index of weapon level dot Range. Weapon level zero or one or two. We also have this size value that will make bullets larger as we level up. Starts weapon level dot size for X and Y component of local scale vector. Weapon level one is just the base size because size value is a multiplier here. Weapon level one is double size. Weapon level two will be size times 2.5. Let's save and play just to check if range and size respond correctly to changes in weapon level value. Weapon level one, two bullets, double size, range of two units. Weapon level two, five bullets, 2.5 times the base size, spread across the range of three units. Weapon level zero is just a single bullet at the base size. We have two more properties that we want to connect to these stats blocks, damage and speed. These properties are not used here. We are using them inside Phasor Bullock script. Here is the damage. Here is the speed. Accessing the values that sit on weapon script or phaser weapon script from here takes a little bit more code, as you can see. We need to get phaser weapon instance, so I actually have to access phasor weapon, and from it, I want this stats list. Phasor weapon instance starts at index of phasor weapon instance weapon level. It will work like this, but it's a bit long, and we will be writing phasor weapon instance a lot. So let's put it in a variable and give it a shorter name. Up here, I define a variable. Type is phaser weapon, and I call it, for example, weapon. Start method. And I set weapon to phaser weapon dot Instance. Now, instead of writing pas weapon dot Instance, I can simply write weapon, weapon dot stats at the index of weapon dot weaponlevel dot speed. And now I'm accessing these speed values from phaser Bullet script. I just have to use this prefix in front of every stat name that I want to access from here. I do that in both of these places to access the current damage value. So we are accessing damage here and here, and we are accessing speed. We connected all the stats, and now I can delete this. We have speed value here. It can be five or ten or 15. So as we level up, we should see bullets moving significantly faster. I save, and I play to test this. Weapon level zero, bullets are relatively slow. Weapon level one should double the speed 5-10. Yes, they move faster, and weapon level two should be speed of 15, so even faster. Awesome, our code works. I exit play mode. I set the speed value to eight. This will be 11 plus to add another block for weapon level three, speed will be 14, damage is one, two, three, four, size is one, 1.4, 1.8, 2.2. Amount is one, two, three, four, range will be one, one, one, one. We will tweak this a bit more later as we develop the project. Because of the fact we have speed, damage, size, amount, and range that all do something with how the weapon works, you can create a different and unique progression track for your weapon. It doesn't have to be the same as mine. We built a pretty robust and flexible system here. Right now, my weapon is at Max level producing four projectiles, but we will make changes to it when we finalize the game during the difficulty tuning section. While in play mode, I can set weapon level three to ten bullets spread across the range of five units. It will revert back to what it was when I exit play mode, but maybe our final upgraded weapon will look something closer to this, or maybe even more, even larger, even faster, depending on what enemies and what bosses we come up with. I did promise some reverse bullletl action, and as you can see, we are getting there, but we are missing one fundamental piece. Right now, we can only increase weapon level by manually changing the value in Unity Editor. We need an in game leveling system. I can do a classic system where enemies drop power apps or I could do an experience bar. I haven't decided where I will take this next, but I guess we will find out in the next lesson. So if you want to see what I do, I'll see you there. 35. Experience Bar: Right now, the front layer of parallax background floats at the same speed as asteroids. That's not good because asteroids should be closer to the camera. They should flow faster than the background. We have move speed for each layer here. I will set layer three to -0.4 and layer four to -0.6. This will look better. We have phaser weapon and it can level up to become more powerful. We defined stats for each individual weapon level here. But right now, the only way to move to a higher weapon level is to manually change the number here. Let's implement a simple experience system and connect it to weapon levels. I open player controller script. Player will need private integer for experience. Private integer for current level. And private integer for max level. Now I want to define a list. To use list, I need system collections, generic name space. This will be a simple list that contains a series of integers, numbers with no decimal points. I will call that list, for example, player levels. Each integer in this list will define a breakpoint, experience requirement for player to advance to the next level. I save this and in unity, I see experience, current player level, and max level. I will set max player level to, for example, 30. Here we have player levels list. Currently, it's empty, so I click plus three times. This list can contain only integers. I will put, for example, ten, 20, and 30. This means that player will need ten experience to go from level zero to level one. 20 experience to get from level one to level two, and so on. We will add more level breakpoints soon. But first, how do we display the current experience and experience required to reach the next level? One way to do that is a classic experience bar. I expand UI Canvas game object, and inside, we already created Energy slider and health slider. I will duplicate Health slider and I will follow the same structure to create an experience bar. If I press F on my keyboard, it will focus it like this. I rename it to experience slider. And I expand it fill area, and fill color here, and I will do full blue, zero, 0255. I rename this to experience text. Default value will say experience. I collapse it, select the main game object, and I click here on Anchor Presets. I hold down out to also set position, and I want to do this bottom center. I set width to 800 pixels. I select experience text Width will also be 800 pixels. Experience slider selected here, and I need to center it again. I click here, I hold down Alt key, and I select bottom center. Okay, now I have an experience bar positioned in the bottom middle of the screen. I set height to 50 pixels. I move it vertically, maybe 80 here. I click this label for full screen preview. Yes, this looks better. So we created experience Slider Game Object. Let's open UI controller script. I already have code that controls Energy slider and health slider. I will just follow the same pattern to control experience slider with code. First of all, we will need a private slider variable. I call it experience slider and we will also need private TMP text. I call experience text. Down here, I just duplicate this entire function and I will adjust it. It will be called Update Experience Slider. I rename it Experience slider in all these places. I have to be careful not to create an error when doing this. This function takes the current experience and MAX experience as parameters. First, we set max value of the slider, then we set the value of the slider to the current experience amount, and we set text to show the current experience MAX experience that we will need to get to the next level. These current experience and MAX experience values will be coming from here. Current experience will be this and MAX experience will be value from player levels list and which value it is will depend on player's current level. So inside start method on player Controller, initially, we set experience to zero. Then I call UI controller dot instance dot Update experience Slider. We know that function expects current and max, so I pass it experience as the current value. And here on player game object, we have player levels list with three elements. So if player is on current level zero, MAX experience will be ten. If level is one, experience needed to level up will be 20. When current level of the player is two, it will need 30 experience points to level up. So as max value, we pass it player levels list at the index of player's current level. So when current level is zero, MX experience needed for player to level up is player levels list at index zero, which means it's ten. As current level value increases, we are moving along this list. They will need a way to get experience. Let's create a public because it needs to be accessible from other scripts, void, get experience. It will expect integer, I call EXP. Insight, I increment players experience by the experience that was passed here, received experience. And we know that whenever experience value changes, we need to update experience slider, so UI controller, instance, update experience slider. I pass it experience as the current value and player levels at index of current level as the max value. I save that and in unity. On UI Canvas, we have two new fields. I drug experience slider here. And experience text in here. If I play, experience slider updates, and you can see I have zero out of ten experience. I exit play mode. Let's open asteroid script. Destroying asteroids will give player experience points. It will have a property. I call, for example, experience to give. Let's set it to one here. Down here, when asteroid takes damage and is destroyed, I want to call this public get experience method we wrote on player controller. Player controller dot Instant dot GET Experience. I pass it experience to GIF from line 14. I play. When I destroy an asteroid, G experience function will receive that one experience point per asteroid, and it will update slider to reflect that new value. Each asteroid gives me one experience point. Perfect. When I get to ten out of ten, you can see that it stops. So how do we handle that? At this point, I want player to level up. Public function, I call, for example, level up like this. Let's select player object so I can see this list of player levels. So when player levels up, I want to reset the current experience back to zero so that we can start filling experience bar again towards the next level up. But doing this means I could lose some experience that was left over. So a better way to do this is to say minus equals the experience needed to level up. Like this, Let's say I'm on level one and I need 20 experience to get to level two. Currently, I have 18 experience and I destroy an enemy that gives five experience points. 18 plus five is 23. Then I minus the 20 needed, and I am Level two with three experience points coming from the previous level. The leftover experience wasn't discarded, we have it here. After that's done, we want to increase the current level by one, but only if the current level is less than Max level. So only if current level is less than max level minus one, we increase current level of the player by one. By doing this, we will also start looking at the next value inside player levels list as the max experience value needed for level up. Every time we change experience value, we need to update experience slider to display that change. Okay, and when do we call this level up function. Every time we get any experience, we check if the current experience is more than experience needed to level up. Let's say I'm on level zero, I have ten experience points, and this function runs again. My experience total is 11, which is more than ten. So we call LevelUp, which will reset current experience value. It will increase current level by one, and it will update experience slider. I save that and I play. I get one experience point for each asteroid I destroy. If you look now, my current level is zero. Max experience is ten. I destroy one more asteroid and level up function runs. Current level increases to one, which means we are taking MAX value of 20 from play levels list at index one, and experience slide reset so we can collect experience again towards the next level up. If I keep going, eventually, I level up again and now the current level is two and Max experience is 30. If I keep going, gaining experience and I fill the bar all the way to 30, I get an error. If I pause the game, I can see the error says index was out of range. It's because we increased the current level to three, but this code is trying to pull a value from player levels at index three, and we didn't add that many elements. We only have index zero, one or two. Index three is out of range. I exit play mode. We say here that there will be 30 player levels, but we only added three. I could keep adding manually here until I have 30 elements for each of players 30 levels. But if we want this to be more dynamic and flexible, we can calculate them with code. Let's do it inside player controller up here in start method. Start method runs only once when the script is first enabled, and it runs before update method. Inside, I create a four loop. It will run once for each player level. We set max level to 30 for now. Each time it runs, we take this player levels list and we will add some value. Let's start simple. Just add a value of ten for each player level. If I save and play, this list will fill with elements. I can see I have 32 elements here. I exit play mode. I'm adding the first three elements manually here, ten, 20, 30. I want the total number of elements in this array to match max level value to make sure we have one value for each player level. So instead of starting the four loop from index zero, I will first check how many values we already added manually here and I run four loop that value from that index, all the way to max level. And instead of adding a hard coded value of ten, we will add the previous value. I can access them like this. Player levels at index two, for example. So to make this dynamic, I take player levels list at index of player levels dot count. So the last index. And as I'm adding one new value after another, I want each consecutive one to be 10% more than the previous one, so times 1.1 float. We can't add a float value to player levels list because it expects integers, so I convert it to an integer. Use built in math function called seal two int round the value up to the nearest integer number with no decimal points. Okay, so I start from this element, and I will be adding more until we have one for each player level. Each new element I add will be 10% higher value than the one before. If I save and I play, I get an error that says out of range. It's because here I want to look at the previous element, count minus one like this. Now I have my ten, 20, 30, and then every consecutive value goes up by 10%. Keep in mind that every time player reaches the next level, experience will reset back to zero, and these values represent how many experience points player needs to level up again. I want to space the values out a little bit more, especially in the beginning where the difference between level two, three, and four is very small. So I add a 10% increase plus let's say 15. Save and play, I might tweak this later when I'm balancing the game, but the idea is that this formula will generate experience breakpoints for each level so that we don't have to do it manually. 48 68, 90. This seems like a reasonable set of values. If I manually set current level 25, now I have to destroy an asteroid to trigger update experience bar function. You can see the max value on the bar is now showing 90 this element. The code works. So we have an experienced system that increases player level. Here on phaser weapon, we have some weapon levels. When a player levels up, I want the weapon to level up as well. Public function, I call, for example, level up. Depending on the value of weapon here, we will be using different block from this stats list. As we progress from block to block, phaser weapon gets more and more projectiles and other stats we have here improve as well. For example, size and speed. So whenever level up is called on phaser weapon, we check if weapon level is less than however many elements we add it to stats list minus one. We are checking, can we still increase it? Is there somewhere to move up to? If so, we increase the value of weapon level by one, and we move from one block to another. We don't have stats for that many weapon levels here, considering player can get up to level 30, we only have four weapon levels for now, but I will deal with that later. On player controller, when player levels up, we will also level up phaser weapon using the other public level up function we just wrote inside phaser weapon script like this. I can do other things when player levels up, for example, I can increase Max health of the player by one. I can heal the player to full health, and whenever health value changes, we know that we need to update health slider to actually show that new updated value like this. Okay, so player starts at level zero, three MAX health and single projectile. If I destroy ten asteroids, we level up, and player now has four MAX health, and the weapon fires two projectiles. Awesome. We have a pretty good progression system here already. As we level up, at some point, we are strong enough to destroy the boss. So let's open Boss One Script, and let's make sure Boss also rewards some experience points. Up here, I define experience to give. And I set it to let's say 20, considering boss has 100 lives. I go to Asteroid Script and I copy this line. Back to Boss one script. Down here, when boss takes damage and is destroyed, we take player controller instance and we call public get experience method, and we pass it experience to give. Okay, safe and play. My weapon leveled up. Let's try to see if I can destroy the boss. Yes. And I received a nice chunk of experience for it. Our system works really well. Let's do one more boss. I have two experience. Boom, I received 20 for that. Weapon level is three right now, and because we didn't add any more elements here, when player levels up, it will not increase any further. We stay on weapon level three. I can add many more blocks here to make the weapon more and more powerful, or I can add more weapon types and let the player choose which one to upgrade every time level up happens. So many options. Where should we take this next? On phaser weapon, I will reduce damage to one in all of these places because we are already getting more and more projectiles. I feel like the power increase should be a bit more gradual. These are not the final numbers. I will have another look at the numbers and balance later. I will also add one more weapon level. Element three will have range of 1.5. Element four will have amount of five, range 1.8. I add one more element. Element five will have speed 14, damage one, size 2.5, amount of seven, spread in a range of two units. We focused on weapons for a while now, and I feel that there isn't much of a challenge in the game. When I level up my weapons, it's pretty easy to get through everything. So let's have a look at enemies. We need more of them, much more. As I play, I notice that when Boss destroys asteroid, we get experience. Why we wrote the code, asteroid getting destroyed by anything will give player experience, so we have to fix that. Down here inside asteroid script, asteroid takes damage, gets destroyed, gives player experience. Asteroid is a bit of a special type of object. It's not a traditional enemy. It's an obstacle. With enemies, they don't get destroyed by anything else than by the player, so we can follow this code structure for all of them. But if we want a special interactions between objects, like we have between boss and asteroids, we have to make a small adjustment to this code. There are many ways I can do this. For example, I will make this take damage function, expect a second parameter, Bolin true or false. I call it give experience. And only if give experience is true, we award player experience points. By doing this, I will get an error in all three places where we call this take damage method on asteroid because now that method needs an additional argument. Inside player controller script here, when player hits asteroid, but not by a weapon, this is when spaceship crashes into an asteroid accidentally. I can decide, do I want to give experience if we destroy asteroid like that? I will say no. So give experience parameter will be false. Save that. Unity console will guide me to the next file that I need to edit. Phase bullet also calls take damage on asteroid, and in this case, we do want to give player experience. So as the second parameter here, I pass it through. Safe and close. Okay, good. The final third script is boss one. When boss destroys asteroid, we don't want to give player experience, so I pass it falls here. Now the errors are gone. Back in asteroid script. Notice here, I'm giving each asteroid a little horizontal and vertical push using rigid body so that there is a little bit of motion. I do that inside start method, which runs only once, but at this point, we turned asteroid into a pulled reusable object, which means that this code doesn't run when we repeatedly reuse the same asteroid object. I can do a tiny factor here to fix that. I cut this line of code that actually applies the forces to asteroids rigid body component to push it. Now, push x and push Y are not accessible here because we define them in a different scope. So let's cut this and paste them up here. Okay, like this, I save and back in unity, I get an error that says range is not allowed to be called from a mono behavior constructor. Back in my script, up here in constructor, I can give my variables values like this, but I can't do randomized values directly in here. So instead, I copy and paste this here. It needs to go before this line is called because we will need these values there. Up here, we will just define the variables to make them available anywhere inside asteroid class. And here I just take them and randomize their values like this. We define them here, and every time we activate the asteroid, we randomize them again and we give rigid body a little physics push. I save that and back in unity, I play. I get one more error. This time it's because here, we know that enable runs before start. So in the beginning, when I'm filling my object pool with asteroids, as I prepare them, this code runs and looks for rigid body RB before I actually found that component on line 31. We define a variable here. We assign it here, but just on that very first load, this runs before start method found that component. I'm going to say, only give rigid body a push if we have rigid body like this. I suspect this will not do the push at first, but only when we reuse the asteroid. But let's check that. To clean up, I can also delete these two lines and I can simply give them values up here since we are not changing them dynamically anyway. We only set lives to Max lives every time asteroid activates and reactivates. Save that and let's see. When I play, we don't get that physics push at first, only as they respawn because that's when Enable actually finds a rigid body component. Also, Boss is coming and we don't get any experience when Boss is destroying asteroids. We only get experience when we destroy asteroids with bullets. Perfect. I copy these three lines of code, and just for that first time we are using them, I put that code in here. I might actually not need to randomize push x and Bourgeois here. Let's see. I save that and I play. And yes, they're moving as soon as they spawn. We have that extra bit of dynamic motion to make the world feel a bit more alive. I exit play mode. I go to Assets art, and we have a lot of images here. Let's organize them in folders. I create a new folder I call enemies. I put Greater one in boss one as well. I create another folder, I call environment. I put all four background layers in here. In prefabs, we have greater Burn and Zap effect here, inside effects folder because all of these work in a very similar way. But for art, I will put these spreadsheets inside enemies folder because this art is very enemy related. It doesn't really matter. Asteroid can actually go inside enemies or even inside environment folder. I create one more folder, I call, for example, weapons. So far, we have just this bullet one. And another folder, I call UI. I put this button image in there. Also, these two larger player images we use in main menu and game over screen. Finally, one more folder, I call effects, and I put these three boom spreadsheets in there. Space well is not really an enemy, but let's put it inside enemies folder for now. Nice and clean. 36. Swarms of Enemies: Let's open enemies folder, and I prepared another spread sheet for you. You can download it in video description down below. I drag it in here, I select it and open sprite Editor. Slice grid by cell size, and frames are 120 times 120 pixels. Slice and apply. This is all the same enemy type, but I wanted some variety, so we will have some randomized skins. I drag one of the frames into the scene. Sorting layer at sorting layer, we are creating multiple enemy types, so let's give them their own layer. It will be on top of objects, but under the player like this. Okay, prefabs enemies. Boss is large. It will be on enemies layer all the way in the pack. So order in layer zero. Beatle Morph is a standard enemy size, so it will be on enemy layer, order in layer one on top of the boss in front of it. Critter is the smallest, so I want it to be in front of boss and regular enemies, so it's visible. Enemy layer, order in layer two. I renamed this enemy to Beetle Morph like this. We will have multiple enemy types. Each one will have a little gimmick, something unique about it, and we will learn how to implement it step by step. This will be a basic enemy type. We will practice some motion patterns on it. We have all three evolutions of this enemy now, but I can prepare more enemy types. If you like this project, let me know and I will create some additional lessons. I will rotate it by 90 degrees like this, just for now. We will make it face movement direction later anyway, which will override this. I add component, circle collider two D. I can click this button to edit collider geometry. I get these four handles and I can scale and move the collider that way. But more often than not, that will put it slightly off center. So I could also just set this offset to 00 to perfectly center the collider over the enemy, and then I can edit this radius value, which might be a better way to do this. I will go with 0.5. I need to give it a tag, but I can't really use critter or boss tag because those are special enemy types that have some unique interactions. I will need one more tag for general enemies. This way, we can add more critters, boss and enemy types and keep those interactions separate if needed, depending on what ideas we come up with. I select Beetle Morph game object, and I give it enemy tag. It will also need a layer because I need to set up physics and define which layers collide with which. Let's add layer for enemies like this. I select Beatle Morph, and layer will be NEMA. I go to prefabs enemies, and I drag Beatlemorf game object in here, turning it into a prefab. Now I can delete it from the scene. I right click Create Empty. I will call it Beetle Pool. We want an object pool for these new enemies so that we can reuse them as we are doing with many other game objects. We have our systems in place, so creating object pool takes seconds. I add component Object Pooler. I drag Beetlemorf prefab in this field, and the initial pool size will be five. I parent it under object pools here. Now I can already plug it into Object spawner. Waves list here, I take Beetle Pool and I drag and drop it into the pool field. These numbers are fine for now. I enter play mode to see what happens. They are spawning, but they are not moving. I need to add component. Floating space. I play again. This time they are coming. You can see bolets have no idea what to do. They just slide around them. You will need a script. Inside assets scripts, NEMs, I create new mono behavior script, I will call NM. Our enemies will need update and start methods. But first, let's declare some variables. Serialized field private because I want them to be visible in the inspector. We will need lives. Max lives, damage, and experience to give. All of them will be integer type. Few things to do now, which one to start with? Maybe let's use this damage and make the enemy deal damage to the player. Private void on collision Enter two D. We use this many times in this class. It will be the same here. If the object this enemy collided with has a tag of player we need to access the player controller script so that we can pass it that damage value to handle. I'm looking for player controller script component. I will call it player for short, and I find it by checking the game object we collided with that I know has a tag of player, and on it, I find player controller component. If we were actually able to find that player controller component that I'm calling player here for short, we know that it has a public take damage method, so I call it and I pass it whatever damage this enemy is dealing like this. Save that and in unity, I will actually not attach this enemy script to anything. Instead, I will create another script for Beetle Morph enemy type. I open it. I delete all the code inside. Enemy script will be code that's shared for all enemy types. Notice that it extends monobhavior, giving us the ability to attach it to game objects as a component. Betlemrph enemy type will extend enemy class. It will become a subclass, a derived class that will be inheriting everything from enemy class and by extension from monobhavior. I can prove that relationship by saving and if I go to Beatlemorf prefab, I lock the inspector to make sure it stays on this game object, and I go to scripts Nemes, and I will not attach the NEM script, but instead, I will attach Beetle Morf script as a component like this. This is the Beetle Morph script, which is completely empty right now, but because this bit of code, it extends enemy class. Beetle Morph is a subclass. Enemy is a base class, the parent class, and for that reason, I can see all these fields here on Beetlemorf script. We did the same thing for weapon script earlier in the class. Structuring our code this way allows us to put the code shared among all enemy types here inside the enemy script and code that's unique and only specific for Beetle MorfEemy type will sit here on Beetle Morf script. This will make our de much cleaner and easier to read and navigate in. We worked like this before when we created a base weapon class and phaser weapon as one of the subclasses. With enemies, we will go a bit deeper and I will show you more tips and tricks with subclasses and inheritance. Max lives will be five. It will deal one damage if it touches the player, and it will reward one experience when destroyed. I play. I crash into the enemy three times. Yes, this works. So this code is shared for all enemy types. And here we will put code specific only for this enemy type. For example, let's say I want to randomize the appearance of this enemy. We have four different visuals. To do that, I need to access sprite renderer component. I will do it on the shared enemy class because all enemies will have sprite renderer. Inside start method, we find it using Get component as always. On the subclass, I create an array of sprites. I call it sprites like this. We did this for critters and asteroids before. Save that and now on Beetle MorfPrefab I have this sprites array, so I click Plus to add four elements. I go to art enemies, and we have four frames here. So I drag the first sprite here, the second one here, third and the fourth. Now I want to randomly assign each enemy one of these four sprites. So let's do it inside start method. I take sprite renderer, which we defined here on the base enemy class. So I want to access that Sprite render component and it's sprite field. But for some reason, I'm getting a warning and it says Sprite render is inaccessible due to its protection level. The field is set to private, which means it can only be accessed within the class where it's declared, but not from the classes that inherit from it. I could do public, which would get rid of the warning, but we also have another keyword, protected, which is similar to private. But now this variable can also be accessed from derived classes, from classes that inherit from this class. Now it will work and I can set the value of this field to one of the elements from Sprites array. I just pass it index of zero or one or two or three. I can also randomize that index by, say a random range between zero and sprites length. Here on the base enemy class, I define sprite render as a protected property. Inside start method, we pointed towards this sprite renderer component, and here on the derived class on the subclass, we assign this field a random sprite from these four. If I save and play, I will get an error. It says that this sprite renderer reference is not set to an instance of an object. How is that possible? I clearly do that here where I point the variable towards the component. We are learning how to extend classes, and there is one thing I didn't explain yet. Look at this. I have a start method here on the base enemy class, and I'm also declaring start method on the derived class. The way inheritance works, we are accessing everything through this Beatle Morph script that inherits from enemy base class. When we call something from this script and it can't find it on here, it will follow the chain of inheritance, and it will go up to enemy class and look for it there. But because I have a start method here, it will find it. I will just run it, and it will ignore the other start method on enemy class. Sometimes you want to override a class like that, but in our case, I want to run both of them. I want the code from both start methods to run. To do that is simple. On the base parent class, I use public virtual here. It means it's accessible from anywhere and it can be overridden by a derived class. On the derived class here, I'll use public override like this. Inside, I say base dot SAR to first call all the code inside the start method here on the base class. This code that is shared for all enemy types, and then all the other code here will run. This code is unique only to this particular enemy type. If I save and I play, now all of it will work. We are randomly assigning each enemy one of the four sprites. You can see that the bullets don't really know what to do here. They just slide along. It might be an interesting behavior for one of our future weapons, but here we don't want that. So this is a derived class, subclass, also called a child class. It inherits from the parent base class. Here, we put things that all enemies need so that we don't have to write them over and over for each enemy type separately. One thing that all enemies need is a public take damage method so that the bullets can actually pass the weapon damage along to this enemy to handle. I will follow exactly the same code structure we did for this thing before, for example, for asteroids. I create a public method, I call take damage. It takes a parameter for damage. Inside, we reduce lives by damage. If lives are more than zero, we will do the flash in a minute. Else, meaning that lives are less or equal to zero, we will deactivate it, returning it back to the pool of available reusable objects. Okay, this is fine for now. Save that. And on prefabs, bullet one, I need to unlock my inspector here. I want to open Phaser bullet Script. Down here where the bullet checks what it collided with, I copy this block and I paste it in here. I have to be careful about syntax and brackets when I do this. We add one more block. If the object, Phasor bullet collided with has a tag of enemy, we want to find its enemy script component. If we found that component, we take it and we call public take damage method we just wrote. We pass it the current weapon damage that changes as the weapon levels up and we deactivate the bullet, returning it back to the object pool and basically marking it as available to be reused. So this is that method we are calling. It takes damage, reduces lives, and when the lives are less or equal to zero, we deactivate the enemy object. I save and play to see if it works. Something is wrong because I gave enemies five lives, but I can see they get deactivated after one hit. We define lives and MAX lives here, and we set those values up in Unity inspector. I already did that, but one more thing we have to do. Every time we activate and reactivate this object, we need to set lives to Max lives. Now they have five lives that works. I want them to flash white on impact. I go to prefabs enemies, Beatlemorf prefab, and I add component flash white. You can ignore this warning message if you get it. Up here, I define my components, private flash white type that I call, for example, flash white. We did this before for asteroids. Inside start method, I get that component and now I can call its public methods when I need them. So when we hit the enemy and the lives are not yet zero, we want the enemy to flash like this. When we upgrade our weapons and we have many bullets, sometimes it gets hit by multiple at the same time or really close together. So the reactivated enemies could still have the white material. To prevent that, I call flash white reset, and I will run this before I deactivate the enemy game object. If I save and play now, They flash on hit. It would be good if it also flashed white when player crashes into it to better indicate exactly which enemy caused the player to lose a hit point. I open player controller and to make the enemy flash, I will go down here on collision Enter two D. I copy this code block, and I say, if player spaceship collides with enemy, so this is player's body hitting the enemy, not player's weapon. We try to find enemy script component on it. If we find it, we call it T damage function and we pass it one damage. Enemies Ta damage function will handle the flashing because we just wrote that logic there. I save and play. Now, player crashing into an enemy will make the player flash and the enemy will flash as well, making it more clear what exactly we collided with and why we lost the hit point. We want enemies to also play some destroy effects. Private object pooler I call destroy effect pool. I will actually define it on enemy base class because all enemy types will have a destroy effect. But which pool we will point that variable two will be different for each enemy type. So I do that here inside Beatlemorf subclass. We don't have access to private property on the parent class, so we already know I can just change private to protect it like this. This will make this property available on this enemy class and on all classes that inherit from it, such as this Betelmrf class. Here, I will point it towards one of the object pools that holds a destroy effect. Let's start with Boom one pool, just to see if it works. We've done this before many times in this class. So I'm defining destroy effect pool variable on the shared enemy class, but I'm deciding which destroy effect we will use individually for each enemy type. Doing it this way, I can also write all that logic that handles destroy effect pool only once here in enemy class so that I don't have to repeat that code for each enemy type. I'm following the same pattern we used before. If enemy lives are less or equal to zero, we get a destroy effect from whichever destroy effect pool we pointed this variable towards. We position that effect over the enemy that is just being destroyed. And we will also rotate the effect the same as the enemy to make sure the more specialized destroy effect animations are facing in the correct direction. If we are using this as the destroy effect, rotation doesn't matter that much, but we will use something like this. So I want this animation to be facing in the direction the enemy that is being destroyed was facing. Finally, we activate destroy effect that will play the animation and we deactivate the actual enemy game object that just got destroyed. I save that and I play. We are using Boom one pool for now. And yes, the effect plays. This blue explosion animation is nice, but I'm saving it for mechanical enemies. This creature will need a custom destroy effect. Notice what is happening to the boss. It's getting stuck behind enemies. You need to set up interactions and define which layers will interact and which layers will ignore each other. I exit play mode. Notice that on Beatlemorf prefab, I set layer to anime. This is important for collider interactions. I go to edit project settings. Physics two D layer collision matrix. This intersection enables and disables collisions between objects on the same enemy layer. I disable that. I also disable collisions between enemy layer and boss layer. I want to keep enemy versus bullet collision detection. I disable enemy versus critter collisions, also enemy obstacle and enemy level boundaries. I will keep enemy versus player collisions checked. So basically, I want the objects I put on enemy layer to register collisions with objects on player layer and bullet layer only. We are using Boom one Pool when we destroy Beetle Morph. I want to give it a custom animation so I go to assets art effects. Actually, I'll put it inside enemies folder here. You can download all art assets in the resources section below. I called this file Beetle Pop because it will animate the enemy's shell being inflated and popping. I open Sprite Editor, slice grid by cell size, 110 20 times 120, slice and apply. I expand the sprites and I will drag one of them into the scene. I rename it to Beatle Pop. I put it on enemy layer and order in layer, maybe ten on top of all other enemies, so we can see this happening. I go to prefabs effects, and I'll also set Kriter Burn to nemayer, order in layer ten, and KriterZap to enemy layer, order in layer ten. I go back to my Beatle Pop Game Object and I open Animation tab. If you don't have it open, you can go to Window Animation Animation. I make sure Beatle Pop is selected, and in my animation window, it says to begin animating Beatle Pop and I click Create. I will navigate to Assets animations and I call it Betlepop dot Nim. I click Save. With Beatlepop selected, I make sure this drop down on my animation window says Beatle Pop. I expand the spreadsheet. I left click the first frame, and I shift click the last frame to select all the frames in between. I drag and drop them on animation timeline. Play too fast. 20 samples. Yes. I go to Assets Animation. I have my new animation controller here. I need this other animation clip file, I antique group time. I want this animation to play only once. I go to prefabs effects. It will work exactly the same as these creater animations. I select Beatle Pop, I reset transform just to keep these numbers nicer, and I add component. We will need this float in space and also destroy when animation finished. It will all work already. We set this up earlier in the class. Let's create an object pool so we can use them and reuse them. I create empty game object. I call it Beetle Pop pool. I drag this into prefabs effects folder, turning it into a prefab. I can delete it here. Beetle Pop pool, selected, I reset transform, at component, Object Pooler. Initially, we can create just two. I drag the new Beatle Pop prefab into this field, and that's all. I put it under Object pools and inside Beatle Morph script, I want to use it. I make sure I use the right spelling Beetle Pop pool like this. Now if I save and I play, We have two inactive objects here, and I can see they activate and deactivate to play the animation as needed. I'm using the same animation for all four variations of this anime. I think it works fine, but I could have also created a custom one for each variation if I wanted to. We also need some sounds to play. I could use something from Assets Audio folder we used before, but I will go with some custom audio files I prepared. You can download them in the resources section below as usual. I drop them into Assets Audio folder. I name them Beetle Destroy and Beetle hit. Same as we did before. I drop them into the hierarchy. With both of these selected, I uncheck play on Awake. Output will be effects audio mixer group. I put them here under Audio Manager. I open Audio Manager script, and I create an audio source property for Beetle hit and one for Beetle Destroy. We have these public play sound and play modified sound methods on here that we will use. Save that and back in Unity. Audio Manager selected. I have these two new fields here. I drag Beetle hit here and Beetle Destroy here. Inside enemy, we want to play the hit sound whenever enemy gets hit. Audio Manager, instance, play modified sound to have some randomized pitch because this sound might play over and over. But what sound will I play? I want to define that separately here so that we can have a unique sound for each enemy type, similar to how we have unique destroy effect for each enemy type. I will give it a generic name here, shared for all enemies. For example, hit sound. And what sound will this variable point to will differ based on enemy type. I copy this and I paste it here. When we destroy an enemy, I want to play destroy sound. Now I have to define these properties, so I go up here inside enemy script. I will use protected to keep this property limited to this class and classes that inherit from it. Type is audio source, and I call it hit sound. One more protected audiosurce I call destroy sound. So we will play this, but I will point them to actual sounds here inside Beetle Morph script. Hit sound will be audio Manager dot instance dot Beetle Hit. Destroy sound will be audio manager, instance Beetle Destroy. Doing it this way, I can have completely different unique sounds when I introduce the next enemy type later. Okay, so here on the subclass, I define the actual sounds I want to play. These variables are defined here on the parent enemy class under some generic names, and we play them from here. Save and play. And we get sounds on hit and on destroy. Perfect. I wanted kind of a sound of soft cracking shell. What else can we do? Right now, the enemies just passively float in space, same as the asteroids. They don't really move relative to the site scrolling game world. You will have different enemy types with different movement patterns. So on the shared enemy class, I will define protected float speed X for horizontal speed and protected float speed Y for the vertical speed. I will give them default values of zero here. Again, as we do, we can give each enemy type a different speed value here. Let's say for this one, I want the horizontal speed to be a random range between -0.8 and -1.5 to make each enemy move from right to left at a slightly different speed. On the parent enemy class, inside update method, I will take transform position. And I say plus equals, whatever its position is, add to it new vector three, where its horizontal component is speed X times Delta time to make sure it runs the same speed regardless of frame rate. And the vertical component is speed Y, Ts Delta time. If speed X or speed Y, for that particular enemy type is zero, this line will not do anything to its position, basically. For this enemy type, we will define only speed X in this way. Speed y will stay at zero. Now if I play, each enemy is moving to the left at a slightly different speed. And when asteroids come, you can see these are just passively suspended in space. The enemies are actually flying and moving horizontally in comparison. We have a static camera, but we managed to achieve a pretty nice and consistent side scrolling effect. Also, when we destroy an enemy, I needed to reward experience points. We decided that this enemy type will give one experience. Player controller, instance, and I call it public get experience method. And I pass it experience to give from this enemy that was just destroyed. I save and play. We are defeating enemies, sounds are playing. We are gaining experience. Enemies inflight and pop. They move at a randomized horizontal speed. Okay, this game is really coming together. It might be a bit too easy to defeat this enemy type if they just come directly towards us from right to left. Maybe we can make them move up and down or follow some movement pattern so that the player actually has to aim. Let's do that in the next lesson. He. 37. Enemies and Sine Waves: Sold. I reset transform on the pref app just to make the numbers nicer. In this file, we write code that is specific only to this enemy type. I want to write some code that needs to run for every frame, so update method, but we also have update on the parent enemy class here. I want this line to run first and then the other update method after. So public virtual void update on the base class and public override void update on the subclass. And we call base dot update. Now I can write some special logic that will apply only to this particular enemy type. I want a sine wave motion. Sine wave is a geometric wave form that oscillates. It moves up and down or left and right periodically. I want enemies to follow a sine wave motion pattern, which is extremely easy to implement. I create a helper variable I call sine. It's equal to a built in math dot sine function. It expects one parameter, an input angle in radiance. Basically, we can put in any value that gradually changes over time, and the speed at which it changes will determine the shape of the sine wave. Let me show you exactly what that looks like. In a game like this, the most common thing is to simply put the horizontal position of the enemy. As the enemy flies from right to left, this position value changes and sine function automatically maps that change in value along a sine wave path. So it expects an angle value in radiance, but it will just take position and it will all work. Now I want to apply that wave to enemy's actual position. It will be new vector three. The horizontal component will just stay whatever it is at the moment when this runs. But the vertical component will be taking those updated sine values, meaning that the motion we will get will be up and down, vertical oscillation. If you have a simple game, this is all you have to do. Look what happens if I save and play. That looks pretty good already, doesn't it? Beatlemorf prefab should be rotated 90 degrees here. Object spawner. I sent this to 00 here as well. And here, 0.2 seconds and thousand objects per wave. I play I pose the game, and on player controller, just for now, I increase energy regeneration to five. I play, and we are getting a really nice sine wave. Notice how it by default centers around the zero vertical position, and it oscillates, goes up and down between plus one and minus one unit in the scene grid. Also notice that they speed up when the player uses the superspeed move, which is something we don't really want. If we had a simple game with a static scroll speed, we could be done here, but because our player can speed up and because we use static camera and we move objects from right to left to create an illusion of a player that is flying through space, we have a few more things to do here. As much as I like how they follow this clean, regular sine wave, the fact that they speed up when the player speeds up doesn't really look right. So let's change this to make it look better. As update method runs, enemies transform position X is changing, and sine function is mapping those changing values on a sine wave path. We are then using that oscillating value as vertical position for each enemy, and the speed at which they move between these two values depends on how fast the value we pass to it is changing. So basically how fast the enemy moves from right to left. When the player uses a super speed move, this position X value starts changing faster and it causes the enemies to speed up in a way that we don't want. Let's try something else. We learned that math sine function expects an angle value in radiance and it maps that position on a sine wave. We also know that we can pass it any floating point number and it will interpret that as an angle value for its own purposes. So what if instead of using enemy's horizontal position here, we will use real time that is passing by. I declare a float variable. I call it, for example, timer. As update method runs, I will increase or decrease timer by Delta time. I need this value to update to get that fluctuating wavy movement between plus one and minus one. Then I pass that changing time value here as an angle to math sine function. I can also do minus equals here. It will still work. We are using these objects, so I don't want an endlessly increasing or decreasing time value. I want to reset it back to zero every time we activate or reactivate the object. I will need on enable method for that, but I also want the code inside on Enable on the base enemy class to run. So as usual, I will say public virtual void on enable here. And on the subclass, I will say public overt void on enable. Inside, I first call on enable from the base class, and then I can put some custom code that I want to run only for this particular enemy type. All I need here is to reset timer back to zero. Okay, so ever changing value pass as angle to math sine function. This function will map those updating values on a sine wave oscillating by default between minus one and plus one. We then use those values as enemies vertical position. If I save and play now, I increase energy region on the player just so I can stay in super speed a bit longer and observe how it affects the sine wave shape. Tir is changing much slower than position that we used before, so as a result, we have a sine wave with a lower frequency. We can change the shape of the resulting sine wave by changing its frequency and amplitude. Frequency value describes how quickly the wave cycles, how many cycles it does per second. Amplitude refers to the height from the center point of the wave. It defines what is the maximum displacement from its resting point. Later, I will randomize them for each enemy, so let's already put them inside on enable. Just to see how it works, I set frequency to two and amplitude to three. In the formula, we multiply the angle by frequency. And amplitude will affect the entire resulting value, so it's outside the brackets like this. Don't worry about this too much. It's a very standard formula. You can just tweak the values, see how it affects the resulting wave shape, and after a while, it will make sense. If I play, not getting a clean wave, so I will comment this line out for a while. I want each enemy to have the same identical horizontal speed for a while so that we can see the wave clearly. Now, if I play, this is what happens when we set frequency to two and amplitude to three. Amplitude is pretty straightforward. The wave always goes three units in both directions away from the resting point, which for us is at vertical coordinate zero. The wave will look like this. This is when player is not using super speed. If we enter super speed, it will change the wave shape like this. They are selected and I increase energy region. Now, if I boost for longer, you can see the other wave shape better, the beauty of mathematics. I made this a little bit more challenging for us because I gave the player this super speed move and also because this is a game with a static camera. So when we use superspeed, the custom float in space script is moving enemies to the left faster, depending on the current world speed, which causes the change in the wave shape. Strangely enough, this will already look consistent if we separate the enemies as individuals when they are not grouped in a snake like formation like this. While in play mode, I can also give player a high energy value just so I can sustain the boosted speed for longer and fully see the other sine wave shape. I think this motion is pretty interesting, and we will explore deeper if we decide to do more traditional space game where enemies come in oscillating waves. But first, let's just send them out as individuals because that's easier. I exit play mode, and player energy and region automatically resets back to default values because changes we make here in play mode don't save. I will set frequency to a random value between 0.3 and one. Amplitude, the displacement from the center point of the wave will be a random value between 0.8 and 1.5 units. I also uncomment this randomized speed. Right now, the wave forces all enemies to oscilate around vertical coordinate zero. I want them to oscilate up and down around their original randomized vertical position, so I will save it in a helper variable. I call, for example, center Y, the vertical center point, the vertical resting point of the sine wave. Every time enemy spawns and response reactivates from the object pool, it will get some random vertical position assigned to it, so I will save it in this centra Y variable. Then instead of oscillating around the coordinate zero, I will make it go up and down in a sine wave motion around that randomized vertical position. Object spawner. The first wave will be 20 beetle morphs in total, one every 0.8 seconds. 38. Enemy Motion Patterns: I also want to offset the initial pace where on the sine wave the enemies are placed at first when they spawn. I can set the starting timer to anything that is different for each enemy. For example, their vertical position will do that job here. As they move up and down along the oscillating path, it would be nice if the enemies also rotated to face in the direction they are moving. I will write that functionality as a reusable utility script so that we can attach it as a component to other enemy types in the future if we want to. I go to scripts Utils and I create a new mono behavior script. I call it face movement direction. If you remember, we already did this with critters. They always face the direction they are moving. Let's use the same technique here. All we have to do basically is to take the current position of the object, its previous position from the previous animation frame, compare them and rotate the object accordingly. I will need a private variable that will hold a reference to the previous position. Another one I call move direction, which will be the difference between the current and the previous position. And quaternion for target rotation. Unity uses quaternions to represent rotation. It's basically the same thing as vector three construct, but quaternion has four values X, Y, Z, and W. W is a special value representing the amount of rotation. We don't really need to understand that for this project, so don't worry about it now. Also, let's define float for rotation speed. Initially, I set it to 30. Start method. We set previous position to the object's current position just at first. Every time update runs, we set move direction, which is a vector three to the difference between objects current position and objects previous position. And after we calculated that, we do some rotations, and then we set previous position to objects current position so that it can be used as the previous position in the next upcoming call of update. As update runs over and over, previous position is always object current position from the previous update. Once we calculate move direction by comparing the current and previous positions, we can set target rotation by using built in quaternion look rotation method. We are in a two D space, and this method, as far as I know, is built for three D games, but it will work for us here. All we have to understand is that we define which way is up and where do we want to rotate. I have a little typo here. That's better. There is another way to do this with atan two, which I prefer because I made a lot of web games in JavaScript before. But let's try this approach with quaternions. All we have to understand here is that we calculate what is the target rotation that we want to achieve to make the object face where it's moving, based on its current and previous position. This method is handling that for us. Once we know what is the target rotation we need, we will use built in rotate towards method. It takes objects current rotation, target rotation, and how fast we want to animate towards that target, the speed of that rotation. This will give us smooth animation because instead of snapping directly to the target rotation, we just calculate smaller step towards that target rotation. And for this update, we do just that one step. I want this to run at the same speed on all devices, so I will scale rotation speed by Delta time. Okay, so check where the object moved. The difference between the current position and the position from the previous update. From that, calculate target rotation we need to make the object face in that direction. Then animate that rotation gradually towards that target rotation. Don't snap directly to that new rotation, and then set the object's current position as its previous position so that we can use it in the next upcoming update. Save that and let's see if it works. I go to prefabs enemies, and on BeatlemorPrefab, I add component face movement direction. I play the C, and yes, enemies no longer face directly to the left. They rotate in the direction of movement. I want to really test it. So what if we have larger waves? And by that, I mean, I will change the amplitude range, and I will also increase frequency to higher values just for testing now. I play. I can see they don't rotate all the way to face where they are moving if they move much faster like this, which means my rotation speed is too slow. Well, this makes them more dangerous and hard to avoid. Wow, they just slapped me around. Maybe we can use this motion for some more difficult enemies later in the game. I increase rotation speed to 50. Still too slow. Maybe 100 then? I want to say we are getting there, but this still feels pretty slow. It really depends on what is the final effect you are going for, I guess. I doubled the rotation speed to 200. This kind of feels like playing a space Frogger. Well, that's an idea for a game. Maybe a special Frogger level later, we can do that. Now player superspeed move is actually helpful because it allows us to quickly push through some of these dangerous paths and move out of the way. Notice that when they don't move in a single formation, it actually makes visual sense that the sine wave path gets longer when we speed up, so we are good on that. There is one small issue that comes from the fact that we have a game with a stationary camera. And we create an illusion of movement through space by moving everything from right to left. When we speed up, the relative difference between the current and previous location of the enemy makes them rotate towards a different angle because when we speed up, we are stretching that sine wave as we saw before. We want that stretching when it comes to positioning of enemies' bodies, but we want to negate it when it comes to the rotation they are facing. It probably doesn't make much sense now when I say it like this, so let's just do it. And when you can see it, hopefully it will be more clear. In Beatlemorf script, I set frequency of the sine wave to a random range between 0.3 and one, and amplitude will be between 0.8 and 1.5 units from the center point. Now, the final issue I mentioned will become more obvious. Look where the enemies are facing as they move up and down, and look how they change, where they face in reaction to player speeding up. I don't want them to react to that in this way. I want the rotation of the enemies to ignore whether or not player is in super speed. But player entering super speed stretches that sine wave as we demonstrated before, and that causes the rotation to change when the world speed changes. I have to have a little think about this, and basically what we need to do is this to achieve the rotation, what we are already doing, we determine how much we rotate the enemies by measuring the distance between their current and their previous positions, and we make them face rotate towards that direction. If I speed up, world speed increases, and the distance between previous and current position of the enemy also increases because the sine wave stretches and it's causing this rotation on enemies that we don't want. I will fix it by checking what is the current world speed, and I negate its effect on enemies previous position. So here I want to adjust previous position minus equals to negate the effect, and it has to be vector three because position values are in vector three format. And when it comes to world speed, we are dealing with the horizontal component only. It will be game manager dot instance dot World speed, Tams ta dot Delta But to calculate that world speed, TAMs T Delta T here might be a little bit inefficient because we would be doing that calculation too many times on each enemy. What if I do it differently? I open game manager script. Here we have that public world speed variable, and it can be changed by this public set world speed method. Player is calling that when it enters and exits boost. So let's calculate that adjusted world speed here inside game manager directly. Up here, I create a public float, adjusted world speed, and in update, I make that calculation world speed Tams ta dot Delta T. We pre calculate it once per update here inside game manager, and we will access this adjusted world speed value directly in all places we need it. So we start here in phase movement direction where I'm negating the previous position by whatever that adjusted world speed is. I'm not sure if I explain this bit in a way that's completely clear, but by doing this, I'm negating the effect of players super speed boost on enemies rotation. I want enemy's rotation where it's facing to completely ignore how fast the world is scrolling. Before I test it, I also go to float in space script, and instead of calculating world speed, Tams Delta time for every update on each object that has this script separately. I will pull that pre calculated value from game manager directly. Adjusted world speed like this. Save that and we also do that same calculation on Object sponer here because to create our illusion of moving through space, we are speeding up the rate at which Object spawner activates objects based on the current world speed. Again, instead of multiplying Delta time T's world speed, I will use that pre calculated value here by using adjusted world speed directly. Now, let's save and play to see if this little trick with offsetting enemy's previous position worked. Notice now that enemy rotation doesn't react at all to player entering and exiting super speed because we are moving previous position of the enemy in relation to the current world speed. And now, finally, enemies following sine wave motion pattern look natural and consistent with the illusion of player moving through space. I give myself some extra work by giving player this superspeed ability that affects how fast the world scrolls by. If we had just a constant at speed that never changes, this lesson would be much shorter. But we learned a few new tricks, which is always useful. We have a basic enemy type, and we know that if we want to make it more dangerous later, we can increase the frequency and amplitude of the sine wave motion, turning this into a hardcore space frog. Maybe we will do that, but before, let's implement another completely different enemy type with different interactions, different sounds, and different visuals. It will be much quicker because we already have our base enemy class that handles all the basic functionality for enemies, and we can focus only on the fun part on implementing unique enemies that add different aspects to the gameplay loop. Let's go. For a while now, we had no way to win this game and actually see mission complete screen. So let's reinstate that functionality. It's really quick and easy. At this point. We have all the systems in place. We have this lost whale prefab, a broken space whale that the player has to find and rescue. We set it up as a trigger that will complete the level. At this point, everything we spawn dynamically in the game is an object pool. So let's turn the space whale into a pooled object as well. We have all the systems in place, so it only takes a few clicks. I create empty game object I call lost Wale pool. I reset its transform to keep these numbers nice and clean. Add component Object Pooler, and I drag lost Well prefab into this field. One will be enough. I parent it under object pools as usual, and now we are ready to plug it into Object spawner. I made some changes to my object spawner waves to kind of design a simple level. First wave is Beetle Pool, two of them, one every 0.8 seconds. Then I will have five critters. You don't have to follow exactly what I'm doing here. Feel free to create your own level structure by spawning different objects in different waves. In my case, I will follow up with 70 asteroids, one coming every 0.5 seconds until we spawn all of them. Keep in mind that it will probably not take 35 seconds to get through this wave because the spawning speed is increased whenever player uses super speed move. So if player uses that move, this wave will happen much quicker. Then I have critter pool, ten of them in total, one every 0.1 seconds, then 40 beetles, spawn interval 0.8 seconds, 70 asteroids, one every 0.5 seconds. Seven critters coming in 0.1 second intervals. 30 asteroids, seven critters again. Then I will have the lost whale spawn interval one. Objects per wave will also be one and after 30 asteroids. The whale will be basically in the middle of an asteroid belt. So the whale is basically a mission complete objective. Player needs to collide with it to trigger mission complete screen. We designed this game in a way that if player misses the whale and keeps going, this waves list will start from the beginning again from the first wave, repeating the cycle. This is fine for me now. This is not the final level layout because now it's time to add another unique enemy type and also a different type of boss right after that, and we will slot them to spawn somewhere in here as well. 39. Charging Enemy Type: I created another spreadsheet with a new enemy type. As always, you can download all the project resources in the description down below. I drag and drop it into Assets art Enemies folder. I open Sprite Editor and slice grade by sell size, 120 times 120. Slice and apply. If you look at the spreadsheet I prepared, this enemy type is a little bit different than the first one. This one has double the amount of frames. We still have four variants, one, two, three, four, but each one has another frame that will be used for charging animation. We already have our enemy parent class, so all the basic functionality will come from there, and we can focus on unique features of this anime. Want this enemy type to float around and kind of wait for an opportunity to strike the player. And when it gets hit by players weapons, when this enemy's health reaches a certain breakpoint, it will charge forwards at high speed. It will introduce a new dynamic to the gameplay. Let's implement it, and then we will do a boss version of this enemy as well. I expand the spreadsheet and I drag and drop the first frame. Sorting layer will be enemy, and ON layer is one above the boss and under the critters, basically. Tag is enemy, and I put it on enemy layer. I reset transform and I rotate it to face the player. I move it a bit to the right here. Okay, I rename it to Locust Morph. I lock the inspector and I go to scripts enemies, and I attach this enemy script as a component. Max Life is ten, damage is two, and experience to give is two. Add component, float in space. Now if I save and play, we have the enemy moving to the left. I add component capsule collider two D. I rotated the enemy by 90 degrees, so these values and direction can be a little bit unintuitive because of that. What I want is vertical direction for the collider. Horizontal size is 0.7. Vertical size is 1.2. This is pretty good. Now, if I play, bullets are colliding and sliding around. I add component, flash white. I move capsule collider component up like this, just to keep all these utility components together at the bottom. Inside scripts EMs, I create a new mono behavior script. I will call it locus morph. I delete all this code. Save that. Instead of attaching the parent enemy script, I actually want to remove that component, and instead, I attach Locust Morph script. If I make that script, extend enemy class, we will get the fields here again. Max lives ten, damage two, experience to give two. Now, this enemy is inheriting all the basic functionality from the parent enemy class, and on locus morph subclass, we will define only the things specific for this enemy type. It will work the same like we did it for Beetle Morph. I copy this entire code block and I paste it in here. I will replace all these values one by one with things unique for this enemy type. I delete this line. Horizontal speed will be positive, a random range between 0.5 and 0.8, which will make the enemy float slightly backwards. The enemy is also influenced by float in space script that makes it move to the left in relation to the current world speed. But this line will make it hover around a bit longer, waiting for a perfect opportunity to strike the player. I will actually increase this speed just to make it obvious what I mean. If I save and play, you can see the enemy is moving backwards. It's looking at the player and backing up. It also flashes on it. Great. So I decrease this range of values, but I still keep them in positive direction, but much more subtle. I also want the enemy slowly bounce up and down between the top and the bottom of the screen, similar to what Bos does when it's in patrol state. I give it random vertical speed between negative -0.5, which will make it move down and positive 0.5 to make it move up. To do this, we will need an update method here with some custom code specific only to this enemy type. So public override void update. Inside, first, I call pace dot update. This function that sits on the parent enemy class that contains code shared for all enemy types, and then we will bounce the enemy between the top and bottom of the screen. But to get the right values, we have to check the vertical range where the enemy can spawn. Because if we set the bounce breakpoints to range inside of that, the enemy can get stuck there if the spawn range is larger and it spawns outside of those bound breakpoints. We spawn enemies here on object spawner. It has the minimum and maximum position objects. I unlock the inspector. Min position object is here. Max position object is here. I will actually move it to minus four like this. Okay, so we know that where we placed, these objects in the game world will define the range. Enemy spawned by Object spawner will appear randomly somewhere on this imaginary line connecting these two objects from plus four to minus four vertically. Okay, now that I know the spawning range, let's try to use five. I have to make sure enemy doesn't spawn past this point. I say, I transform position Y of the enemy is more than five or if it's less than minus five, invert speed Y by multiplying it times minus one. We already did this for both in patrol state before. Let's say enemy is moving up, speed Y is positive. When it moves past plus five, positive speed multiplied by minus one will turn the speed negative and enemy will start moving down. I grease speed Y just for testing. So we can clearly see if it works. It moves down, it bounces, it moves up. It bounces once it reaches the fifth unit from the center, vertical position five. Yeah, it works. Just to remind you, this is vertical position zero. This grid represents units plus five units is here, minus five units is here. We go from the middle where zero is. Now that I know it works, I return speed wi to a random range between, let's say, -0.9 and plus 0.9. Now I want to replace these sounds with some unique sounds that I created specifically for this enemy type. This is a special enemy type. It will have hit sound, destroy sound, and it will also have a charge sound. You can download them in the resources section below. I drag and drop them into Assets audio. Then I drop them into hierarchy. With all three selected, I antique play on Awake, I set output to effects as usual. I put them under audio controller to keep hierarchy clean. On Audio Manager Script, I create three new properties. Audio Source, Locust hit, Locust Destroy. And Locust charge. Save that. And now I drag Locust hit into its field here, Locust charge here, and locust destroy here. Okay, nice. On Locust Morph script, I can now set hit sound to locust hit and destroy sound to locust destroy. I play to test it. And, new sounds. This is a squishy space slug, as you can hear. It still uses destroy effect animation from Beetle Morph, so let's give it its own unique animation sequence. I created something a bit more dynamic for this one. You can download Locus Pop Sprid Sheet in the resources section below. I open Sprite Editor, slice grid Bell size, 120 times 120 slice and apply. I expand the spreadsheet, and I drag and drop one of the frames into the scene. Sort in layer will be anime. Auto inlayer is ten. I rename it to Locust pop. It will work the same as this Beatle Pop prefab we created earlier. So we will need Animation panel. If you don't have it open, it's under Window Animation Animation. Locust Pop selected. This has to say to begin animating Locust Pop. I click Create Inside Assets Animations folder. I create a new file, locuspop dot Nim. Save that. With Locus Pop Object selected here, this drop down says Locust Pop. I go to Assets art. I expand this spreadsheet. I left click the first frame, and I shift click the last frame, selecting all the frames in between. I drag and drop all of them onto the animation timeline. I play. Now you can see what I meant when I said I created a bit more dynamic effect. 20 samples. It's much more cartoony this time. I'm just having fun and experimenting with how I do these animations. Okay, I go to Assets Animations. I find Locus boop animation clip and I antique Loop Time. With L ocusPop game object selected, I add component, destroy when animation finished. Add component, float in space. We always do this for this kind of an object that plays animation. I go to Assets, prefabs, effects, and I drag and drop Locus pop in here, turning it into a prefab. We can ignore the message in console. I delete the object from here. I create an empty game object I call Locust Pop pool. I reset transform, at component Object Pooler, I drag Locus Pop prefab here. The initial pool size will be two. I create one more game object, I name it Locust pool. Reset transform, at component Object Pooler. I go to prefabs NEMs. I drag Locus Morph game object in here, turning it into a prefab. Now I can delete it from the hierarchy. Locus pool selected, I drag Locust morph prefab into the prefab field here. I keep the initial pool size as five. I put both of them under object pools. Object spawner waves list. I right click the header of the first element and duplicate array element. I move this one up here. Object spawner selected again. I drag and drop locus pull into this field. We will do ten objects per wave. Spawn interval 0.8 seconds. I want to use this locus pop pull as destroy effect on this enemy type. So here I say locus pop pull with exactly this spelling to make sure it works. Object spawner. I right click the header of element three, duplicate array element. I take element three by this corner and I drag it up. So now I have locus morphs spawning and then a wave of 70 asteroids. I do this so that when we play, we can see the difference between asteroids that are just passively suspended in space and flowed to the left. And in comparison, we can see that Locus morph enemy type is backtracking a little bit so that it can stay around longer, waiting for a perfect opportunity to charge at player. They flash on hit, they play hit and destroy sounds, and they animate the new destroy effect. I'll get here. Okay. Let's go inside Locus Morph script again. I want to randomize enemy visuals. We have four random sprite sheets. Each variant has an idle and charge frame. We also had four variants of Beetle Morph enemy, but that was just a simple sprite sheet with four frames. We just added them to Sprites array and we assigned a random one to this sprite field on sprite renderer component. With Locust Morph, we want to create a data structure where each element represents one of these four variants, and each one of those variants will hold its own idle and charge frame so that we can switch between. I create a private list. We need system collections generic name space. This list will hold frames, which we will define in a minute. And I call the list frames like this. So this frames is undefined. I go down here. Still inside Locus Morph class, I define a private class, I call frames. Now we have a class frames nested inside Locus Morph class. This class will be very simple. The blueprint is that every object created using this class will have public array of sprites, I call sprites. That's it. It's a very simple class. We will give this array two elements, one sprite for idle and one sprite for charge. I need to use system serializable here so that I can work with this class inside Unity inspector. We are using that class up here. Don't worry about this. Let me just show you in the inspector why we did this. It will be easier to understand when you see it. On Locus Morph Prefab, I have this new frames list. So I click Plus to add a new element. I expand it, and inside, it has sprites array. I click plus twice to give that array two elements. I go up one level, and this plus will add another element to frames list. I open its Sprites array, and this one already has two sprite elements inherited from the previous one. Plus to add another element to frames list. Again, we have Sprites array with two elements inside already. And finally, plus to add one more to frames list, and inside again, it has sprites array with two elements. Okay. Now if I compare the script and what we did in the inspector side by side, we added four elements into this list. One, two, three, four. This list expects that each element in it is an instance of our custom frames class. Frames class has only one property, array of sprites. We see this here, here, here and here. We gave each sprites array two elements because we have two frames for each enemy, idle and charge. I log the inspector, I go to art enemies, and with Locust morph spread sheet expanded. If I look at the spread sheet, this is the first variant, idle charge, second variant, idle charge, and so on. This first element represents the variant one of the enemy, so I drag and drop this first frame as idle and this second frame as charge. Then the second enemy variant, Idle frame here, charge frame here. The third enemy variant, idle frame Charge frame. And the fourth enemy variant, idle frame here, charge frame goes here. So the way we designed this simple data structure, we have a list we call frames. It has four elements, one element for each enemy variant. Each one of these variants has one property, sprites array, where the first element in that array element with the index of zero is the idle frame. And the second element, the element with index of one is the charge frame. Now I will create a custom private method I call Enter idle. And another one I call Enter charge. Let's start by just swapping these frames to index zero when the enemy enters idle and to index one when the enemy enters charge. So Sprite render dot Sprite, the image we are displaying for the enemy is this frames list at index zero. We will only deal with the first enemy variant at first. And we want the idle frame. So Sprites array index zero. When we enter charge, we want frames at index zero. It's Sprites array at index one, the charge sprite. Now we can call Enter idle or Entercharge from anywhere in this class, and it will swap the sprite frames automatically. For example, I will make enemy Entercharge when it takes a certain amount of damage from the player. We will need to overwrite take damage method from the base class. First, we call the method from the base class, and then we pass this damage value along to it so that the method can do what it needs to do. And that method on the parent class will be public virtual like this. So once we call that method from the base class, we will add some extra code specific only to this enemy type. I say, if lives are less than Max lives times 0.5, I need to make these properties protected, which means available on this enemy class and on all classes that inherit from it. And here I say, as the enemy is losing lives, when it lost a half of its maximum lives, enter charge. Save that I enter play mode. Locus Morph has ten lives. When I reduce its lives to five or less, it will enter charge and its sprite will change to the charging image. Yes, that works. I also want to call a sound effect from here. Audio manager, instance play sound. The sound I want to play is audio manager instance, Locus charge. We already prepared that sound and that property earlier, so it will work. I go up here, I cut these two lines of code. I paste them in here and also in here. When enemy enters charge, it will speed up to the left. So vertical movement will be zero. Horizontal movement will be a random range between minus four and minus six, moving very fast to the left, charging at the player. The values for idle state can stay like this. Save that and play. I hit enemies when their lives get down to 50% of Mac's lives or less, they charge to the left. Perfect. This introduces some new mechanics for the player to look for and deal with. We have to focus this enemy to make sure we destroy it before it reaches us or we have to make sure we avoid it when it's charging. We are only showing the first enemy variant for all of them. This one for idle and this frame for when it starts charging. Let's display all four of them. I create a private integer called enemy variant. I will need on Enable method here, so public override void on Enable, and we call pace on Enable at first to run the code from the parent enemy class. In unity on Locust Morph prefab, I unlock the inspector. I go down here to frames list so that we can see how it's structured here. Every time we activate or reactivate the enemy, I want to randomly assign enemy variant, a number 0-3. So enemy variant will hold the index inside frames array. If enemy variant variable is zero, it will take sprites from frames at index zero. These two. Index one, Index two will be these sprites and index three is these sprites. So we use that enemy variant here. And here as the index in frames list, let's say, for example, enemy variant is two. So for idle, we go to frames list at index two dot Sprites array at index zero, and for charge Sprite, we go to frames at index two dot Sprites array at index one. Enemy variant value will determine which one of these four elements in frames list we are pulling the sprites from. If I save and play now, it will still show only the base frames. It's because I need to call Enter Idle somewhere to actually assign that value to sprite renderer component. I will call Enter idle here after we randomized that enemy variant value while we are activating or reactivating Locusmrp object. If I do that, I will get an error that says object reference is not set to an instance of an object. It's because I'm calling Enter idle too early before we actually get component for sprite renderer. When I enter idle, I need sprite renderer component, but that very first time we are creating this object and putting them into the object pool, this enable runs first, and Enter Idle needs a sprite renderer component. Before start method that runs after has a chance to actually get that component. We get that component inside start method by calling the base class start. And here on line 26, we actually get sprite renderer component. We need to get it before on Enable runs. So if I check unit documentation, I can see that awake method runs before on enable. I will put this line here. Awake method will now get that component before enabled triggers enter idle function where we will need that sprite renderer. I save and play, and we get randomized skins and we manage to associate them together in pairs for idle and charge states. I have a feeling that we are triggering Enter charge method over and over. I create a property I call charging. It's a booling. It can be true or false. Right now, when enemy takes damage and its lives are below 0.5, every time it gets hit, it runs this code again. So this sound plays after every hit, resetting the audio from the beginning. I only want entercharge method to run when charging is false, when the enemy is not charging currently. I say, I charging is false, exclamation mark is false, only then run all this code. And inside, I set charging to true. So once we entered this method, we can't call it again over and over. Let's say charging is false currently and enter charge gets called. This check will pass because charging is false and all this code will run, setting charging to true until something in our code sets charging back to false again, this code will not run again and this sound will not play again. I will set charge into false whenever we call Enter Idle again. Right now, we only call Enter Idle at the beginning when we activate and reactivate the enemy. Now if I play and I hit enemy over and over, charge sound plays only once. Perfect. I want to create a new boss now because this enemy type will also have a special boss version. Let's do it. Will. 40. More Boss Types: C. I open boss one script. We have Beatle Morph enemy type that extends the base enemy class. We have Locust morph that also extends the same base enemy class and we have this Boss one that extends mono behavior. We are not taking advantage of inheritance here and we are redeclaring some basic functionality that is shared for all enemies and for this boss. Things like speed X and speed Y destroy effect pool lives, Max lives damage and experience to give. All enemies have that. We don't really have to declare all of that here. We can just extend enemy class and inherit that from here. Let's do it. Boss one extends enemy. Now I get warnings for everything that is already declared on the parent class. I delete destroy effect pool property. I delete speed x and speedY from Boss one script here. Here we have lives and Max lives and if I go to the parent enemy class, I said damage and experience to give to protect it. We get all four of these highlighted as duplicates, so I can delete them. We will leave here things only specific to how this specific boss functions and behaves. Let's refactor this code a bit and then we will implement a completely different boss type with some unique interactions. On the parent enemy class, I set awake method to public virtue. Here on boss one, I set it to public override. I also do public overt void on Enable, public overt void start, public overt void update, and public override void take damage. Now, as we always do, first, I want to run the code from the parent method, the one that sits on the base enemy class. Base awake, base dot on Enable base start, base update. And base dig damage. Actually, looking at the code inside take damage, it's almost the same on the enemy base class except for the flash white functionality. Let's go on Boss one script and completely delete take damage method. Now, this take damage method from the base class will be automatically inherited for boss one. I just have to make sure we have flash white script component on Boss one prefab. I save changes to all my files and on Boss one prefab, I go down and I add component flash white. On Object spawner, I right click element zero in waves list, and I duplicate array element. I drag reterOPool inside and let's say 20 objects per wave. I save and play and I destroy critters until it spawns a boss. Boss will just zoom by like this. Clearly not everything works yet. I'm getting errors about destroy sound and hit sound, which we are trying to play here, but we didn't actually point them to any audio source yet. I will do the same thing we did on Beatlemorf subclass. I go inside start method on Boss One script, and I define what audio source we want to play when Bs gets hit. Hit Sound is audio manager dot instance dot HIT Armor, the same sound we used for this until now. And destroy sound will be audio manager Instance boom two. When Boss enters charge state, we set speed X two minus five. I save that. On Boss prefab, we made this script inherit from the base enemy class, so I need to re declare these values. Max lives is ten just for testing. Damage is 20. Experience to give is 20. I save and I play. Yes, that works. I'll get here. We have boss one inheriting from the base enemy class, and that way, we don't have to re declare the shared functionality for every single boss type. Inside boss one script, we declare only the things that are specific to how this particular boss functions. When boss is in patrol state going up and down, I want the vertical speed Y to be a random value between minus one and plus one. Up here, inside on Enable, we have this line, but we already have that line of code on the base class. Yes, so I can delete it here. Let's have a look down here on collision enter two D and on base enemy class, we already check for enemy versus player collisions. So I do public virtual void here, and on boss one, I do public overwrite void on collision Enter D. Inside, I first want to call the shared code from the base class, passing this collision reference along, and I can delete this bit. We are handling that one on the base enemy class. We only need this part because boss is the only enemy type that actually causes damage to asteroids. A enemies damage player. Boss damages the player and also damages asteroids. I save and plays charges, B patrols. It gives player experience. All is good here. 41. Boss that Cruises Along: I created a new boss type large version of Locust Morph. As always, you can download all project resources in the description down below. I drag and drop the spreadsheet inside art Enemies folder. It's fully animated and similar to the Beetle Morph boss. It will have two distinct animations, one for idol and one for charge. With Bs two PNG Art Asset selected, I go to Max size, and I do the bottommost value, the largest one possible so that the spreadsheet can render at full size. I save changes and I open Sprite Editor. As usual, I go to slice, grid by cell size. These sprites are big, 360 times 360 pixels. Slice and apply. These are big sharp frames. I hope they look good in a game. Let's see. We've done this part so many times in this class. I expand the sprite sheet, I drag and drop one of the frames into the scene, which will prompt unity to create a new game object with sprite renderer component. Sort in layer is anime or the in layer is zero. I rename it to boss two. I want to rotate this boss but not to face the player. I want the boss to face away like this. It will cruise along with us moving from left to right in the opposite direction to all other enemies. Animation tab, Window animation animation. Boss two selected here, and I click Create Inside Assets Animations. I create a new file, I call boss two underscore Idle. Save that. I expand the spreadsheet. I left click the first frame, and I shift click frame 38, the last frame of idle animation. It will select all the frames in between 0-38, and I drag and drop all of them on animation timeline, making sure this says both too idle. This plays too fast. I try 20. Maybe 30. Yes, that's good. I click this drop down and create new clip. I will call this one Bs two underscore charge, and I save. I make sure I see Bs two charge here. I left click frame 39 and I shift click the very last frame. I drag and drop all those frames on animation timeline. I don't see the frames here because I don't have Bs two game object selected. Now I can see them. 60 is too fast. Let's do 30 again. Okay, so I have boss two selected here. I scroll down and add component float in space. I go to assets scripts enemies. I create a new mono behavior script I call boss two. I open it. I remove all this code inside, and I make sure it inherits from the base enemy class. Save that boss to beam object selected, and I add boss two script as a component. Boss two script is completely empty right now, but because it extends the base enemy class, it already covers most of the basic functionality that's shared for all different enemy types and bosses. Just for testing, Max lives will be ten. Damage dealt by this boss will be 20, and experience to give will be 40. On boos one prefab, I increase Max lives to 100. Boss two selected, and I have boos two script here. Inside Bs one script, I copy this entire code block with start method, and I paste it inside boos two script. Here we have an opportunity to give this boss a unique destroy effect, hit sound, and destroy sound. For now, I will leave them like this. We will also need public override void update, where we first call the update method from base enemy class, and then we will write some unique logic to make this boss move in a specific way. I will make the boss bounce up and down between the top and bottom of the screen at first. So if transform position Y is more than four, if boss is more than four units above the vertical center of the screen or if it's less than minus four, in both cases, flip speed Y to the opposite value, making the boss move in the opposite direction. We did this for boss one in patrol state and for locust morph as well. It will have a private method I call enter idle state and another one called Intercharge state. Private booling, I call charging. By default, it will be set to true. When boss enters idle state, we check if charging is true. Only if boss is currently charging, we will switch to idle and we set horizontal speed to slightly positive, making the boss move backwards, but only very slowly. And vertical speed will be a random value between -1.2 moving down and plus 1.2 moving up. We will also set charging to false because boss is now in idle state. It is not charging. I copy this code block in here, and I change a few things. Inside Enter charge state, we only run this code if boss is currently not charging. Boss can only enter charge state if charging is false. Inside, we set charging to true. When boss is charging, it is moving fast but not from right to left. It is moving from left to right, in this case, in the same direction player is moving. So when charging, vertical speed will be zero. Horizontal speed will be a random range between plus 3.5 and plus four positive values, so boss will move to the right. Okay, we set these boundaries to plus four and minus four. Let's save this. And if I check Object spawner mean position, it's plus four here. Max Boss game object is minus four. The area where the boss can potentially spawn is in this range, so it will work fine. I need to make sure that spawn range is the same or smaller than bounce range to prevent the boss from spawning outside the bounds range because it would get stuck there. These values are fine because they are the same as maximum vertical and horizontal spawn point. I will make this boss automatically try to keep up with the player in moving along with the player as we play the game. If the boss reaches the right edge of the screen, if its horizontal position is more than 7.5, it will enter idle state. It will stop charging, and it will wait around for the player to catch up. Else, if boss's position is less than minus five, if it's almost touching the left edge of the screen, it will enter charge state and starts moving to the right. If I save, and let's check. Plus 7.5 units horizontally is here, minus five units is here. Seems good to me. Let's set the initial position to 40 for now. It doesn't really matter. Boss is in idle state, just hovering in space. It's affected by the game world scrolling by world speed, same as all other objects and creatures in our game. Okay, so only if charging is true, we can enter idle. Only if charging is false, we can enter charge. Initially, charging is set to true here as a default value. I will need on enable method here, something that will run every time we activate and reactivate boss two game object because it will be a pooled reusable object, same as everything else. Public override void on Enable. First, we call base on Enable to run all the code shared for all enemy types, and then we make this boss enter idle state. Every time we activate or reactivate this boss, it will start in idle state. If I save and play, Bs is in idle, it moves very slowly up and down and bounces from the top and bottom edge of the screen if it reaches there. When its vertical position gets to minus five, it will enter charge state. It will start moving forward at a higher speed. It moves forward until it reaches plus 7.5 units horizontally, and it will switch back to idle again. That works. I go to Window animation and animator. It will open animator Window, which is basically a simple state machine. Here we define conditions when object transitions between different states. Earlier, we created animation for boss to idle and boss to charge and you need to turn these into animator states. I want to switch between these two states dynamically to play these animations when we need them. I go to parameters here, I click Plus, and I want to add a booling I will call that bullying charging. So this value can be true or false. I click Idle animator state and make transition. I drag the transition arrow over the charge state like this. I click the arrow itself, and inside the inspector tab, I antique has exit time. I also expand settings and I set transition duration to 0 seconds. I want instant transitions. I go down here and I find conditions block. I click Plus, and the condition to transition from idle to charge state will be when charging parameter is true. I right click the charge state, make transition, and I drag this transition arrow from charge to idle. I select the arrow itself. I anti has exit time. Transition duration is zero. Condition to transition from charge to idle state is when charging parameter is false. So these are animator states. They play the two different animations we set up from Bos two spreadsheet earlier. Now I can simply target this animator parameter we called charging, and by setting it to true or false, Animator will be switching between idle and charge animations. Base Anim class doesn't have a reference to animator component because basic anime types don't use animator, so I will do it inside awake method on Bs two subclass. We are doing that here in Bos one script. I will copy this animator property first and I put it here. And I will copy this entire Awake method from Bos one script, and I paste it here. I delete this. We don't need this line because boss two doesn't play a sound when it spawns. Okay, so we define animator and we pointed to the animator component inside Awake, which runs before on Enable. Because here inside on Enable, we will already need that animator because in Inter idle state, we will be setting that animator parameter we just prepared. Whenever Boss two enters idle state, we take its animator reference and we call built in set Bool method, set booing. It will set that animator parameter we called charging to false. Keep in mind, these are two different things. This is animator property. This is a separate variable, a flag we use to prevent the boss from entering idle or charge while it's already in that state. When Boss two enters charge state, we call animator, set Bool, charging true like this. If I save and play, Boss is animating idle. When it enters charge state and starts moving fast to the right, it will animate charge. It will switch between the animations as it switches between idle and charge. I also want the boss to react to player's position and movement. Let's keep track of player's horizontal position and save it in a variable. It will be equal to player controller dot instance dot transform dot position dot X. I do this so that I don't have to write this long line multiple times. I use or operator here, and if boss' horizontal position is less than minus four units, if it's almost touching the left edge of the screen, or if boss' horizontal position is less than player's horizontal position, in both of these cases, entercharge state. Okay. So now if the player moves to the right of the boss, boss will react to it by speeding up. I exit play mode, boss two game object selected. Layer will be boss, which will give it interactions with asteroids because earlier we set up that objects on boss layer collide with objects on obstacle layer. Tag here doesn't have to be boss anymore. After the refactor, we use this tag to identify that bullet collided with boss or enemy. I will access its take damage method and it will pass its weapon damage along. This boss now inherits from enemy base class. Let's give it a tag of enemy. And actually on Bos one prefab, I can do the same. I keep the layer as boss for asteroid interactions, but tag can be enemy like this. So after making this change, I go to Phaser Bullet Script, which is currently our only weapon. And down here inside on collision Enter two D, we check what this bullet collided with and we pass the weapon damage to it. I can now completely delete this boss block because for the purposes of this code, boss now falls under enemy. Bosses have enemy component and take damage method on there will pass weapon damage to Bs one, and I'm careful about brackets and syntax when I do this. I save that Bos two will need a collider component. I set rotation to zero for a while. This will make the collider setup more intuitive. At the bottom, I add component, capsule collider two D. We have to make sure we always choose the two D version here. I leave the direction as vertical. Horizontal size will be two units, vertical size will be three units, and I move the collider down a little bit like this. I'm happy with it now. I can rotate the boss by 90 degrees to the right again. Object spawner. I grab this little list item by a corner and I drag asteroids wave up here. I set spawn interval to 0.3 seconds. If I save and play, I try not to hit many creatures. I don't want Bs one to spawn right now. I just want to check if Bs two is interacting with the asteroids and if it's pushing them around. Boos one charges in and it also interacts with asteroids and it destroys them instantly. When I try to hit Bus two with bullets, they slide along. Something in our code still needs attention. Usually, console is a good place to check if you don't know what's wrong. I can see it's coming from T damage method on enemy class and it says object reference is not set to an instance of an object. It's looking for flash, white component, but it can't find it. I exit play mode. Boss two game objects selected, at component flash white. Now, if I save and play, it flashes on hit. Great. I exit play Mode. I right click Create Empty boss to pull. I reset transform, at component, Object puller. I go to prefabs NEMs and I drag and drop boss two game object in here, turning it into a prefab and I can delete this bit. With boss two pool selected, I drag and drop Bs two into the prefab field here. Initial pool size will be one. I drag it under Object pool to keep hierarchy clean. Object spawner, and the first wave will be Bs two pool. Spawn interval one, objects per wave one. Now when I start the game, I have Bs to pushing through the asteroid belt cruising along with the player. If I hit it, currently, it's very easy to destroy. Let's increase both lives to 400. 42. Enemy that Follows the Player: In this lesson, we will put together everything we learned so far to create a boss that shoots a small enemy, that shoots a small criticized enemy at the player. This can make the game much more difficult depending on how fast and sturdy we make these new enemies. It will give the player a proper positioning and aiming challenge, and it will further increase the gameplay variety and make the game more interesting in general. The art assets and sounds we will need are available to download in the video description down below. I created a spreadsheet I call Squid Critter. I called this enemy type squid Morph because it's soft and squishy and there are some tentacles and teeth involved. We already have an enemy type with critter, basic and boss evolutions for Beetle Morph, and this enemy type will have the same three levels, boss, regular sized enemies, and critters. I added an extra fifth option for each just for fun. If you want to mix and match these body parts and create your own enemies, you can sign up for my newsletter, where I share bonus content packs that you can download for free and use in the games we make. I drag and drop Squid Critter Spreadsheet into Assets art enemies, and I open Sprite Editor. As always, slice grid by sel size, 80 times 80 pixels, slice and apply. I drag one of the frames into the scene. Certain layer is enemy, or the in layer is two. I adjust position and rotation. Although, in this case, it doesn't matter. We will move and rotate this with code. I rename it to squid grater. At component circle collider two D. I will go a little bit faster because we have done this so many times in this class. So I'm sure you can navigate your way around these menus if you follow it all the way here. Radius of the collider will be 0.4 or 0.35. Add component flash white. Whenever I add this component, I get an error. It doesn't actually break anything when we play the game, but to make sure this error doesn't appear like this, let's see what it's complaining about. Something inside reset method we wrote before. Okay, only set this back to default material, which if you remember, is this field. If we already captured the reference to the default material in a variable, this should fix the error message. I add another component, float in space. Tag for the previous critter was critter, but that critter type works in a bit different way. It has different animations when we destroy it and it has no lives and it doesn't damage the player as well. For this critter, I wanted to behave more like a regular enemy so that we can give it multiple hit points and things like that. Even though I call it a critter and it's the smallest of these three evolutions, I will tag it as enemy. Layer will also be enemy here. Enemy layer will make it ignore other enemies and asteroids in terms of collisions, but it will make sure it collides with the player and projectiles, which is what we want here. Assets scripts folder. I create a new mono behavior script I call squid grater. I attach it to Squid Critter game object as a component and I open it like this. This critter will have multiple lives. It will damage the player and it will reward experience. That's why I make sure it inherits all the basic features from the enemy base class. I need this critter to do everything we define here, so I make enemy the parent class of squid gritter. It will be its subclass, derived class, also called a child class. We will basically handle it in the same way like we handled Beetle Morf enemy type. So squid critter extends enemy. That's why I want to do the usual thing where I said start method to public override, where I first call the start method on the base enemy class, on the parent class for all the shared code, and then we will add some code unique only to this Squid critter enemy type. Same for update method, public overt void update. And inside, first, call the update method on the parent enemy class on the base class. If I save that, Squid critter is already inheriting all these fields from the enemy class. So let's set Max lives to three. Damage it will deal if it touches the player to one and experience to give also to one. There will be lots of these critters everywhere if you let them multiply. This enemy type can completely overwhelm the player and fill the entire screen if not kept in check. We optimized our code base with object pools. Let's see if it can handle this or if I need to implement some further optimizations like grid based partitioning with quad trees to only check nearby objects, not all objects on the screen. I want to start by taking all five frames and assign each enemy a random one. We did this before, so you might remember that we start by defining an array of sprites, I call sprites, and inside start method, we access sprite renderer component, which we don't have to get here because we are already doing that on the parent enemy class here. Defined here, get component here. So here we already have a reference, and I can simply access its sprite field, which I can see here. And I want to assign it one of the five sprites we will put in this sprites array. For example, the first one with the index of zero. So this sprites array is here plus to add elements. I put all five of these sprite frames in there. Now, to randomly take one of these five and assign it to the sprite field, I say that the index is random range between zero and sprites dot length. I save and play and this field should have one of these five sprites assigned and anime will look different every time. Yes. I try again. Yes, that works. On collision, we get an error just because we didn't define some pieces of animal logic. We need hit sound and destroy sound as usual. I sampled some frock sounds and rubber noises and I created a custom set of sounds we will need for this enemy. You can download all of them below or feel free to use different sound effects if you want. I drag and drop all seven files into Assets audio folder. We have so many files because we will use them for all three evolutions of this enemy type, and we want some variation there. We will have to destroy sound two hit sounds and three different shoot sounds because these enemies will be shooting each other at the player from their cannon like trunks. So let's prepare all seven of these sounds so we have them ready for use later. I drag and drop all seven into the hierarchy. With all of them selected, I uncheck play on awake, and I set output to effects. I open audio Manager script, and I create a public audio source property for each new sound effect. Squid hit, squid hit two, squid Squid destroy two, squid shoot, squid shoot two and squid shoot three. Okay, now if I save, I have all these new fields, and I drag each one of these from hierarchy into its associated field on audio manager component. So we have two sounds for hit, two for destroy, and three sound effects for shoot. I take all of these and I put them under audio manager to keep hierarchy clean. I open Squid Critter script. It will work the same as other enemy types we created before. For example, how we did Beetle Morph. We are repeating the same pattern to keep the code easier to understand. Every enemy type needs these four lines of code. What animated effect will play when it gets destroyed? What sound will play when it gets hit and when it gets destroyed? So I copy this and I paste it inside start method on Squid Kriter. I will leave the destroy effect pool for now. We prepared sounds already, so I will use Squid hit here and Squid destroy sound here. I go inside prefabs enemies folder. I drag and drop Squid Krater game object inside, turning it into a prefab. Create Empty, squid crater pool, reset transform, add component Object Pooler. I drag and drop Squid crater from prefabs folder into this field. The initial pool size will be five. Now I can delete this one from hierarchy. Object spawner waves list here, and the first wave will be squid grater pool. Spawn interval is 0.5 seconds and objects per wave will be 50. I drag squid critter pool and the object pools. Let's try and play. We have critters coming slowly from the right. They get randomized skins. They play sounds when hit and destroyed, and I actually want to use the other destroy sounds for these. I exit Laode here I say squid destroy too. Yes, now the right sound plays when they get destroyed, and we can see they play destroy animation effect from Beetle Morph. So let's create a quick custom destroy effect. I put together a spread sheet I called Squid Critter Pop. As always, you can download all our task sits below. I open Sprite Editor, slice grid by cell size, 70 times 70 pixels. Slice and apply. As usual, I drag one of the frames into the scene. Sort in layer is enemy, audio in layer is ten. I want the animation to be on top of other enemies so that the player knows what's happening. Okay, right? I rename it to squid Crater Pop. I add component, float in space, and destroy when animation finished. Window animation animation as usual because I need Animation tab. With Squid Critter Pop gameObject selected, I click Create Animations folder. New animation file will be called squidretorpop dot m. Save. I left click the first frame, and I shift click the last frame, selecting all the frames in between. I drag and drop all the frames on the timeline. I said speed 220. Okay, this is a bit different. I'm experimenting with these animations. I go to Assets Animations, Squid Creator Pop animation clip file. I wanted to play only once, so I uncheck loop time. I drag and drop Squid Creator Pop game object into Prefabs effects folder. I create empty game object, squid Creator Pop pool. Reset transform, at component Object Pooler, pull size just one to start with, and I drag Squid Creator Pop prefab into this field. I delete this game object from hierarchy and I put Squid Crater Pop pool under Object pools. In Squid Krater script, I set destroy effect pool to Squid Krater Pop pool. I save and play. We have sounds, we have animations. We get experience when destroying them. Perfect. Next step, make the crater rotate to face the player because these critters will be projectiles that are shot at the player by larger enemies. We did the rotation before for the other crater type that other critter rotates in the direction it's moving. To make object rotate towards a specific position, in this case, towards the player position, we will need private vector three target position, and we will also need target rotation. Inside update method, I set target position to the position of the player. This will update as the player moves around. To make object rotate to face towards a specific target position, first, we need the relative position, the difference between the target position and objects current position. All these are in vector three format. If the difference is not zero, we will calculate target rotation. We did this before using quaternion look rotation. We pass it two parameters. The first parameter, which direction the object will look in after applying rotation. I wanted to look forward. This depends on where is your creature facing on the spreadsheet as well. The second parameter is optional. It's a vector which defines which direction is considered up. If you give this second optional parameter a custom value, unity will adjust the final rotation based on that. We pass it the relative position between player and this object to make it rotate towards the player. You can try to pass it different values to really understand how it works, but we used it before. We know it works, so let's move on. This is not vector three but quaternion. We have the rotation that will result in critter rotating to face the player, but we don't want to set that rotation instantly, making the critter snap very fast. We want to slowly animate the rotation towards the target rotation step by step for a nice fluent effect. Unity, it's very easy using built in rotate towards method. We passive the current rotation of the crater, the target rotation, and maximum angle. How much towards the target we wanted to rotate, for the care of update for this one animation frame. Let's say I want the rotation speed to be 90 degrees per second, 90 times time Delta time. Save that. I have my crater prefab here. Let's play and see. As you can see, they are keeping an eye on the player always watching, rotating towards the player as it moves around the screen. Now in mpire survivors style, we want them also to always move towards the player's position, which is also super easy. We save players position as target position, so the position of the critter will be vector three, move towards, and we pass it the current position of the critter the current position of the player as the target to move towards and the maximum distance to move towards that target per function call. I will have a variable, I call move speed, and as always, I multiplied Times Delta time to make sure the speed is based on real time and not on frame rate, which can vary from device to device. I have to define move speed, private float move speed. I want move speed to be dynamic. I will explain what I mean in a minute, and I need move speed to reset to the default value every time we use and reuse the quitter from Object pool. So as usual, public override void on enable method, where I first call on Enable from the base enemy class, and then I add some custom code specific only to this enemy type. In this case, whenever this object is enabled or re enabled, we set move speed back to two. Let's play and test to see what we have so far. They are coming for the player, and there is no way to avoid them. They are everywhere. Perfect. I want the critters to move in a non linear speed because I want the bigger enemy to be shooting these smaller enemies at the player. I want them to start moving very fast but gradually slow down to a speed that the player can actually avoid them. So we will have the current move speed, and we will also need target move speed. Initially, they will move very fast. Move speed will start at eight. Target move speed, the speed I want the critter to end up moving will be a random value between 0.1 and 1.2. So each critter will move at a slightly different speed. As Update method runs over and over, we will be checking if the current move speed is not equal to target move speed, and we will be gradually reducing the current move speed until it reaches target move speed. We will use math arp built in method. Linear interpolation eases the transition between two values over time. We pass it the start value, the end value, and the interpolation value between two floats. I want to go from the current move speed to target move speed, and I want the interpolation between these two values to happen at this speed. This is the step in between those two values per function call. I include Delta time to make sure this runs at the same speed on different devices, regardless of framerate. I save that And when I play in the scene view, we see they start at the high speed and gradually slow down. My plan is to have these little critters being shot as projectiles by larger enemies, so the initial high speed will make more visual sense once we implement that. Okay, let's create that bigger enemy. 43. Enemy that Shoots: I called this enemy type squid morph. I drag and drop the spreadsheet into assets art enemies. You can download it in the resources section below. I made five frames here to get more variants. We will follow the same steps we always do. I open Sprite Editor, slice grid by sal size, 120 times 120 pixels, slice and apply. I drag one of the frames into the scene. Sorting layer is enemy, Audi in layer is one in front of the boss behind the crater. Position and rotation like this, it doesn't really matter. We'll move it and rotate it with code. Tag will be enemy so that it can give and take damage. Layer will be enemy so that it registers collisions with projectiles and player. I add component circle collider two D. I set collide radius here to 0.6. I rename it to squid morph. I I create a new mono behavior script, I call Squid Morph. Let's open it. I will follow the same pattern we did for Beetle Morph, but it will have its own unique thing spitting critters at the player. Squid morph will extend enemy, inheriting the basic functionality that all enemies share. I will also override start as we usually do here, and I will override update as well. Let's start by giving each squid morph one of the five random sprites. We just did it for Squid Critter. I copy this line that creates an array of sprites. What else we did here? I copy this line. Then inside start method, we first call the code on the base class and I paste this line here, randomizing the sprite we display. I also call the code inside base update method as usual. Save that. I attach Squid Morph script to this game object. Squid Morph now has these fields been inherited from the base enemy class. Max lives will be ten, damage is three. Experience to give is three. Sprites array, I add five elements, assets enemies with Squid Morph spread sheet expanded, I drag five sprites in here. Like this. Add Component flash white. Add component float in space. I play, and I get a random sprite assigned. That works. In Squid Critter script, I copy these lines of code. I paste them in here. Hit sound will be squid hit two, which we prepared earlier. Destroy sound will be squid destroy. I keep this as the animated destroy effect for now. I play. It flashes on hit, sound effects are playing. I drag it inside assets, prefabs, enemies turning it into prefab. I create empty game object, Squid pool. Now I can delete this one from hierarchy, Reset transform, add component Object Pooler, squid morph prefab here, Object spawner. And the first wave will be squid pool. I drag and drop it under Object pools. Save that and play. Okay. We have squid morphs coming from the right. It's using destroy effect from the critter, so let's give it its own unique destroy animation. I drag and drop squid pop spreadsheet into Assets art enemies. You can download it in the resources section below. I open Sprite Editor, slice grid by Sal size, 120 times 120 pixels, slice and apply. I drag any one of these frames into the scene, sort in layer me, or in layer ten. Position and rotation doesn't matter. We will control that with code. Animation tab, I rename it to Squid Pop. Create button here. Inside Assets animations folder, I create Squid Pop animation clip File. Save that. I left click the first frame. I shift click the last frame, selecting all the frames in between. 60 is too fast. 20 should be better. Assets animations folder, Squid Pop animation clip file, Inspector tab, and I uncheck loop time. I drag and drop Squid Pop inside prefabs effects folder, turning it into prefab. I can delete it here. Create Empty Squid Pop pool, reset transform at component, Object puller, pull size just one. I drag Squid Pop prefab into this field. I drag and drop Squid Pop pool under Object pools. Inside Squid Morph script file, I want to use Squid Pop pool here. Spelling needs to be the same as the name of the game object. On the prefab, I add component, float in space, and add component, destroy when animation finished. If I play, we have enemies that flash on hit. With a unique hit sound, destroy sound, and destroy animation. They just float passively in space. Let's say that this enemy is a blank slate at this point. Let's give it dynamic motion and make it react to player. Then we will implement its unique ability where it shoots critters at the player. To rotate the anime towards the player, we will need quaternion. I call, for example, target rotation. We just did it for the critter. Inside update method, we will create a helper variable, vector three type called relative position. It will be the difference between the current position of the player and the position of this anime. If the difference is more than zero, we will calculate target rotation. What is the rotation we need if we want the enemy to face the player? We used rotation before in this class a few times. When we know where we want to rotate, we will rotate towards the target, but not all the way there instantly. We will take a step towards the target rotation. Quaternion rotate towards built in method. I pass it the current rotation of this enemy, target rotation, which is where we want it to end up eventually, and the third parameter will be how fast we want to rotate there, accounting for Delta time as always. I set objects per wave to 200 in the first wave. If I play now, they will rotate towards the player wherever the player moves. They are still very easy to avoid. We want a challenging enemy that forces the player to be aware of it and to avoid its danger zone. And we want the danger zone to be dynamic, animated, and interesting. As they reset, if we reuse the same enemy and they spawn here, they will still hold their old rotation value. We want to reset that every time we activate and reactivate them. Public override void on Enable. I call base on Enable first as usual, and I can just set transform rotation of the enemy to 0090 like this, making the enemy face to the left as soon as it activates. I also want the enemy to slowly bounce between the top and the bottom of the screen, let's give it a random speed Y. This will already move the enemy vertically because on the base enemy class, we are defining speedY here on line 18, and we are using it to influence enemies position down here inside Update. I want it to simply bounce up and down. We did this before. If it's vertical position is more than plus five and less than minus five, Switch speedY to its opposite value, making it bounce and move in the opposite direction. I need dot Y here. Just for testing purposes, I will increase these values, so they move up and down faster, and I can see if they actually bounce off the edges. Save and play. Well, we already have a bit more interesting enemy type when we combine the rotations and bouncing, but we can take this so much further. We know that the bouncing works, so I slow it down. Speed Y will be a random value between -0.3 and plus 0.3. Same as with the critter, they will start moving very fast at first and gradually slow down. Inside on Unable, whenever we activate or reactivate this enemy, its speed X will be set to -15, moving very fast to the left. I'm not declaring this speed X and speed Y. I'm just assigning a value to a variable defined on the base enemy class. And line 35 will use these values to actually move the enemy around. With squid critter, we have this helper move speed property for this because critters are rotating and also moving towards the player. With Squid Morph, we are just using speed X and speed Y to handle this movement because this enemy rotates towards the player, but it doesn't move towards it, so we can just keep this a bit simpler. We will also have target speed X, which is the value we want the enemy to slow down too. Every time we activate the enemy, we randomize the target horizontal speed to random range between -0.1 and -0.6 to make each enemy move at a slightly different speed slowly to the left. Speed X is not the same as target speed X. We will slowly change speed X value using ARP again, linear interpolation, which will float between two float values, the current speed and the target speed. And the third argument is what portion of their difference we want to travel in this single call. I will just use some value here multiplied by Delta time, and I can increase or decrease it if I want the slowdown to happen faster or slower once I see the resulting animation. Because of this third argument that always defines a portion of the difference between speed X and target speed X, speed X will never be equal to target speed X. They will basically just be getting infinitely closer and closer to each other, but never exactly match. I will say if they move close enough, snap the values together. I math absolute of the difference between the current speed and target speed is less than one. If they are close enough, stop interpolating and just set them both to the same value, so this code block will no longer run. Mas absolute will return the absolute distance from zero, which means it will disregard plus or minus, minus two and plus two, for example, are the same distance from zero, so they return the same value. I'm just doing this to treat negative and positive numbers in the same way. We start at a very high speed and gradually we will slow down to the target speed using linear interpolation. I save and plate to see if it worked. You can see they are moving very fast, but they slow down. This is exactly what we want. But I don't want them to rotate to face the player all the time, only when they slow down to the target speed. I want them to look around and find the player. To do that is simple. I just put s here. When speed X is equal to target speed X, only then look where the player is and rotate towards it like this. If I save, my prefab is here and I play. But they move fast facing left. Only when they slow down to target speed, they start facing the player. This will make even more sense in the next step. When they slow down and locate the player, they rotate towards the player and they start shooting critters in that direction. I already created the critters, so this part is relatively simple. This enemy will shoot critters in player's direction over and over. We will need to count time so shoot timer and shoot interval. Every time we activate the enemy, we give it a random shoot interval. Let's say shoot a critter at the player every one to 6 seconds. Every enemy will have a specific interval that's somewhere in this range. I enemy is moving fast in this block, we don't shoot. When it slows down to the target speed in this block, it will rotate towards the player and it will start shooting. We will have a shoot timer that starts at the value of the interval. It will be one to 6 seconds randomly, and it will count backwards towards zero, accounting for real time that is passing by. When shoot timer is less or equal to zero, we set shoot timer back to the interval value so that it can count again. We do plus equals. We add to whatever the timer is to account for each millisecond, and then we call shoot method, which we haven't written yet. So let's define it outside update method. But before this closing bracket, private void shoot, we will use our crater object pool as the projectiles. So private object pooler and I call it projectile pool. Inside start method, we do the same thing we did for Destroy Effect Pool. Projectile pool is equal to game object find, squid crater pool, and on it, we find Object Pooler component. That component has G put Object public method, so I can define a helper variable. Game Object type, I call projectile. It will be equal to projectile pool dot Get Pooled Object. We set position of the projectile, which will be the squid critter to whatever position the enemy is. We will also rotate the critter in the same direction enemy is facing. Finally, we set it active. We will also play audio. We prepared these sounds before, and I called this sound squid shoot. Like this. Okay, so each anime has a random interval assigned to it. Tir is counting between that interval value and zero over and over. And every time it resets, it shoots a projectile. Save that Okay, this will be very challenging, I think. There are so many. You can hear the new shoot sound playing, and there are spitting critters at the player. I exit play mode. Object spawner. Let's set spawn interval to 3 seconds. Now they spawn a bit slower and we can better see what is happening. The shoot sound is long and it ends with a little squeak from the critter. I sampled a frog sound for this. But because we are playing the same sound file from the beginning every time an enemy shoots, it resets and we rarely get to hear the full sound effect. Let's deal with the sound. Let's play a random sound when enemy shoots. If random value is less than 0.3, which will be in roughly 30% of cases, we will play this longer sound called squid shoot. Else, in the other 70% of cases, we play squid shoot too. I save that and see if it worked. We get one of two random sounds, giving the shooting a bit more variety. What is how the critters move fast at first, and then they slow down. Critters always follow the player. Squid morphs only rotate towards the player, but they don't move towards it. In front of the squid morph, there is a danger zone. Players should avoid it because it shoots the critter at a very high speed at first. I sampled some frog noises and some scratching rubber to achieve the sound effect for this enemy type. We have an enemy that shoots a projectile towards the player. What if we take this one step further? What if we have a big boss that shoots mid size enemies, and those enemies will shoot the small critters? At this point, we can just quickly repeat all the techniques we learned to achieve that. 44. Boss that Shoots: I created a special animated spreadsheet for Squid Boss enemy type. You can download it in the resources below. I drag and drop it into Assets art enemies. There are a lot of frames and this boss is relatively large, so the spreadsheet is larger as well. With Bos three, spreadsheet selected, I go to Max size and I select a larger value here to make sure it renders at full size. I click Apply. Open Spread Editor. Slice, grad bicell size, 400 times 400. These are large frames. Slice and apply. I drag and drop one of the frames into the scene. Sorting layer is enemy, or the in layer is zero. Around the position numbers to something nicer, but mainly I will rotate it to the left to face the player. I was having fun with designing this alien. It's a squishy space octopus that multiplies very fast and shoots its little clones at the player. Do you have any other ideas for an enemy type that would be fun to design and implement? Let me know in a comment and I might do an extra lesson and do it. I add component, flash white, add component float in space. At component circle collider two D, collider radius will be 1.4. Tag will be enemy, layer will be boss to make sure it interacts with colliders on asteroids. I rename it to boss three. Before we animate these frames, let's program some logic because I want this boss to move around in a very specific way. In assets scripts, enemies, I create a new mono behavior script. I call it boss three. I attach it as a component here. I open the script, and boss three will inherit from the base enemy class like this. As always, we will need public override void start, where we call base dot start. And we will need public overt void update, and base update like this. I save that and now I see some new fields. For testing, I set Max lives to 20, damage to 20, and experience to give also to 20. If I play, I get an error as expected because we know each enemy type needs to have three things inside its start method. Destroy effect pool, hit sound, and destroy sound. I copy this line from Squid Morph script and I paste it here. I won't boom three effect to animate when boss gets destroyed like this. I copy these two lines. Squid hit two sound here, and boom to sound here. Now if I save and play, all the basic functionality of the boss is already in place. Now we need to give it some unique behaviors. We have a game where a player can use a super speed move and it affects how fast the game is scrolling by. So for this boss, I will define an imaginary baseline. I want the boss to always try to move along a path somewhere around here, and if the boss moves to the left because the player used super speed or if the boss spawns to the right from the baseline, it will always try to move back to that baseline. I want the boss to always try to be around this area and shoot its clones at the player from the distance. Let's say plus seven horizontal unit will be where I want the baseline to sit horizontally. And if boss' horizontal position is something else, it will try to move towards it. So I define private float base position. And private float charge speed, the speed at which the boss will move if it's not at its base position. We will need public overt void on enable that runs every time we activate and reactivate this game object. We will slightly randomize base position. It will be Unit seven, so along here. But if we have multiple of these bosses spawned, I want some random offset plus random range between minus one and plus one from the base position, just to make sure if we have multiple bosses, they don't stack on top of each other. Charge speed will also be random for each boss between 1.2 and 2.5, for example, Inside update, we first call all the shared code from the base class, and then we will define some logic for how the boss will move along horizontal X axis. Also how the boss will move vertically, and then boss' special shooting behavior. It's actually pretty simple at this point, so let's quickly do it step by step. I need to save boss' current horizontal position in a helper variable. Current X is boss' transform position X value. If the boss is not at its base position horizontally, actually, if the boss is further away from its base position than 0.1 unit to the left or to the right from it, math absolute to disregard plus or minus. Base position is at unit seven. If the boss' position is not at unit plus seven horizontally with a tolerance of 0.1 unit in both directions, we will make the boss move towards its base position. Helper variable, position X will be linear interpolation between where the boss is right now horizontally, its current X, and its base position X, which is the target position basically. Bos will cover a certain proportion of that distance per call of update. It will depend on charge speed accounting for Delta time. Then we set boss' position to this new horizontal value, leaving the vertical value to whatever it currently is. We don't modify it here. Okay, so if boss is not at its base position, make it move towards it. I save let's move the boss far away from the base position to the left. I play. Okay, that's too much damage. I move the boss away from the player, and if I play again, Boss will move towards its horizontal base position, and it works visually, even when the player uses super speed move. Perfect. What about when the boss spawns somewhere around here? Will our logic work in the other direction as well? Yes. Boss will always move towards its baseline from both directions. This works really well. Vertical movement will be bouncing up and down. We did that before. If boss's center point is more than plus five units from the middle, vertically moving up or less than minus five units moving down, we flip speedY, making it move in the opposite direction. I want the boss to always have some vertical motion so that when it shoots the enemy clones at the player, it covers the entire game area. Speed wy will be this. Let's write it and then explain it. We have expression to evaluate. If true, return this, else return this. If random value is less than 0.5, in 50% of cases, make the boss move down one unit per second. Else, in the other 50% of cases, make the boss move up. This is so called terniary operator. I'm using it here as a simple one line if else statement. If this is true, do this, else, do this. Cos is moving up, and when it moved more than five units from the middle, its speedy flips to the opposite and Cs is moving down. Perfect. We have the movement logic. Et's do the shooting. It's very simple because we did it before for Squid morph. We know we'll need object puller, I call projectile pool, pull of something that this boss will be shooting. We will also need shoot timer and shoot interval. Shoot interval will be randomized between two or 3 seconds. Down here, inside update, we will be reducing shoot timer by real time Delta time. If shoot timer is less or equal to zero, we increase it by shoot interval, and we call shoot method, which we haven't defined yet. So I define it here, outside update, but still inside this class, private void shoot. I can copy these four lines of code from Squid morph because they will be identical. Get a projectile, position it where the boss is, give it the same rotation as the boss and activate it. What this projectile will be will depend on which object pool we will point projectile pool to up here. We can make it shoot anything we want with this code just by swapping the name of the object pool. Try and make it shoot other enemy types if you want, or make it shoot space whales or something or other bosses or make it shoot more copies of itself. I will make it shoot squid morphs. So squid pool here, and we already programmed Squid morph to shoot squid critters. So this should result in a fun cascade of spawning enemies. We also want to play a sound. I copy this line, I paste it here, and I want to play Squid shoot three sound effect like this. If I save and play, Boss will shoot instantly because shoot timer starts at zero and immediately triggers shoot method. I moved the boss up here, so let's play again. Okay, big enemy, shooting smaller enemy, shooting even smaller enemy. We almost got it. Just a few things to tweak. It already looks pretty interesting. When we first activate the boss, I wanted to wait for 1 second before it shoots. And squid morphs will have random range, which is fine. But that first shot will also happen after 1 second to make it a bit more predictable. And also, I want to show off the cascading spawn effect we created. Let's make squid morph a bit slower when it's being shot by the boss. Maybe minus seven speed X here. If I save and play, boss will wait 1 second. Okay. Squid morphs will move fast when they slow down and locate the player, then 1 second countdown and they shoot a crater. Object spawner. I don't want to be spawning this right now, so let's just spawn asteroids. All squid morphs that appear are produced by the boss. Yes, this is good. We have a lot of animation frames for the boss, so let's actually use them and make this more visually interesting. Boss three Game Object selected, Animation panel, and I click Create. Inside Assets Animations folder, I create a new file I call boos three underscore idol dot m. Save that. I go to art Enemies. I expand Bos three spreadsheet. I left click Frame zero, and I shift click frame 38, selecting all the frames in between. I drag and drop them on animation timeline. Okay, slower. 25 frames should be good. I click here, create Clip. In the same folder, I create boos three underscore shoot dot Nim. Save that. I left click frame 39 and I shift click the last frame 77, selecting frames in that range. I drag and drop them here. If I select Bus three game object here, I will see the frames. I play the shoot animation. Okay, that's fine. I open Animator Window, Windows Animation Animator. You can also open it here by clicking on the Animation Controller file. I want the other file that was created the animation clip for boss three shoot, and in Inspector tab, I uncheck Loop time. This is important for what we're about to do next. I want this animation to play only once, and then automatically transition back to idle. Let me show you exactly how to do that. So the first step to achieve that is to uncheck loop time here. In animator, I have these two states Idle and shoot, parameters tab plus here, and I want to create a bully baometer. I will call it shooting. I we click Idle, make transition, and I drag the transition arrow over to shoot. Arrow selected and conditions here, I click Plus. We want to transition from idle to shoot when shooting parameter is true, and now this will be a bit different. I want to shoot animation to play only once, and then automatically switch back to idle. Animator can handle that automatically without us having to write any code. I right click Shoot state, make transition. I drag the transition arrow back to idle state, and I select the arrow. If I want this animation to play once and then automatically transition back to idle, I keep has exit time checked, and I set exit time to one. On the transition from idle to shoot, I disable has exit time. So when in idle, if shooting is true, we transition to shoot state. This will play only once, and it will automatically transition back to idle. Now, all I have to do is to control with code this shooting parameter, set it to true when I want the shooting animation to play. On the base enemy class, we have a reference to sprite renderer component, but classic enemies are not using animator, so I will create that reference here on boss three. Inside start method, animator is equal to get component animator. And once we have that reference, whenever we shoot, we take animator component and we set that bully parameter we called shooting to true. This will trigger transition from idle to shoot state. Shooting animation will play once, and then it will automatically transition back to idle. But if shooting parameter is still set to true at that point, it will transition back to shoot state, and it will play shoot animation again. So I want to set shooting to true here. I want to wait for one frame and then set it back to false. I can do it with a simple co routine. We used it in this class before. I numerator. For that, I need system collections name space up here. I will call it reset shoot. Let's just write it, and then I will explain it one more time to make it clear what's happening. Inside reset shoot, if I say yield return null, it will wait for one frame and then it will run the next line where I take animator component and I set bullying we call shooting back to false. Here, when we shoot, we set shooting to true, and we want to start this countdown. Start coroutine reset shoot like this. This will wait just for one frame, and it will set shooting back to false. I made a small typo here. Line 26 has to say animator is equal to get component animator like this. Now if I save and play, Notice when the boss shoots, it will play its shoot animation once and it will transition back to idle animation state automatically. This works really well. What else could we do with it? We could add a timer on each small enemy and make it evolve to a larger version if there doesn't destroy them fast enough. I could spend a lot of time designing different enemy types. We have a simple and begin friendly but still solid enemy system that's easy to extend with new very different types of enemies. I create an empty game object, boss three pool, I reset transform. At component object puller, the initial pull size will be one. BriefasEems, and I drag Bs three game object in here. I delete this one from the scene, boss three pull, and I drag boss three briefap into this field. Object spawner. And for testing, the first wave will be boss three pool. So let's say span interval 3 seconds and two objects per wave. I put boss three pull under object pulls here. Let's play and see what happens when we have two bosses at the same time. Okay, all seems to be working. This is pretty hard to manage. Especially since if I'm not careful, they will start coming from behind me, and I don't have a weapon that can reach behind the player yet. Maybe we need a different weapon type that can help us in a situation like this. Ir lit. 45. What's Next?: Well done on completing the class. This was a big project. I hope you had as much fun as I did, let me know if you'd like me to create another one. What game genre are you interested in learning next? Check out the resources section for some bonus art assets, and if you found value in this class, feel free to join me in another one.