Unleash Your Creativity: Build Point & Click Game in Unity | Romi Fauzi | Skillshare
Search

Playback Speed


1.0x


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

Unleash Your Creativity: Build Point & Click Game in Unity

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

Watch this class and thousands more

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

Watch this class and thousands more

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

Lessons in This Class

    • 1.

      Course Introduction

      1:10

    • 2.

      01 Project Setup

      8:33

    • 3.

      02 Basic Player Movement

      6:07

    • 4.

      03 Player Movement & Interaction

      11:20

    • 5.

      04 Player Direction

      6:37

    • 6.

      05 Base Action Class

      6:23

    • 7.

      06 Basic Dialog System

      14:20

    • 8.

      07 Check Mouse over UI

      3:59

    • 9.

      08 Message Dialog Window

      20:14

    • 10.

      09 Item & Database

      5:43

    • 11.

      10 Basic Custom Inspector

      15:34

    • 12.

      11 Item Database Inspector

      23:25

    • 13.

      12 Base Inventory

      2:32

    • 14.

      13 Inventory Custom Inspector

      26:54

    • 15.

      14 Basic Data Manager

      5:01

    • 16.

      15 Item Action

      4:05

    • 17.

      16 Item Action Inspector

      26:01

    • 18.

      17 Item Action Continued

      23:50

    • 19.

      18 Message Actions Inspector

      14:37

    • 20.

      19 Activate Actions

      14:35

    • 21.

      20 Importing Assets

      2:08

    • 22.

      21 Player Animation

      10:55

    • 23.

      22 Animate Actions

      15:20

    • 24.

      23 Animate Action Editor

      14:31

    • 25.

      24 Level Manager

      14:09

    • 26.

      25 Change Scene Action

      17:12

    • 27.

      26 Player Spawn Position

      8:00

    • 28.

      27 Player Spawn Editor

      17:16

    • 29.

      28 NPC Move Action

      13:13

    • 30.

      29 NPC Move Action Editor

      8:26

    • 31.

      30 Interactable Custom Editor

      5:14

    • 32.

      31 Entity State Concept

      4:01

    • 33.

      32 Entity System

      26:59

    • 34.

      33 Trigger Interactable

      6:31

    • 35.

      34 Trigger Interact Editor

      5:11

    • 36.

      35 Camera Manager

      14:16

    • 37.

      36 Camera Switch Action

      4:14

    • 38.

      37 Inventory UI

      26:34

    • 39.

      38 Inventory UI Description

      9:35

    • 40.

      39 Save System Extension

      11:12

    • 41.

      40 Save Features Setup

      25:38

    • 42.

      41 Transparent FX

      15:53

    • 43.

      42 Audio Manager

      16:40

    • 44.

      43 Audio Action

      8:33

    • 45.

      44 Interact Cursor

      15:08

    • 46.

      45 Look Only Interaction

      5:56

    • 47.

      46 Preparing City Scene

      10:36

    • 48.

      47 Preparing Club Hallway

      10:32

    • 49.

      48 Preparing Office

      5:11

    • 50.

      49 Preparing Park

      8:21

    • 51.

      50 Office Cutscene

      24:14

    • 52.

      51 City Gameplay

      26:33

    • 53.

      52 Additonal Item Database Setup

      2:44

    • 54.

      53 Club Hallway Gameplay

      32:37

    • 55.

      54 Park Gameplay

      38:57

    • 56.

      55 Menu Scene Setup

      32:32

    • 57.

      56 Menu Continued

      7:21

    • 58.

      57 Add Save Menu In Game

      7:21

    • 59.

      58 Saving Thumbnail

      16:35

    • 60.

      59 Add Thumbnail to Load UI

      13:53

    • 61.

      60 Finish and Build

      11:22

    • 62.

      61 PlayerScript Bug Fix

      6:48

    • 63.

      62 Entities Resets on Scene Changes Bug Fix

      4:05

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

27

Students

--

Project

About This Class

Are you ready to unleash your creativity and build a captivating Point & Click Adventure game in the style of Monkey Island or Full Throttle? Look no further than this comprehensive Unity course!

Not only will you create a complete game from scratch, but you'll also gain invaluable experience with object-oriented programming and deepen your understanding of Unity's C# API. We'll even provide all the assets you need to create your own games, including 3D models and audio.

Throughout the course, we'll explore powerful Object-Oriented techniques such as Inheritance, Editor Scripting for custom inspector development, and Entity State concepts to create a dynamic entity that persists across multiple sessions. Multiple save system with thumbnail on each entry base on the last screenshot. Plus, we'll dive into Unity Timeline for crafting stunning cutscenes and learn how to optimize lighting with Light-maps baking.

While this course is designed for intermediate Unity developers, it's perfect for anyone with a passion for game development. So whether you're an indie game developer, a seasoned pro, or a game enthusiast, join us today and unlock your game development potential!

Requirements

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

What they say about this course:

Roland Simons - "I am halfway through the course and very impressed with what I am learning. The teacher is very competent and helpful, even three years after publishing the course. Excellent!"

Lucas R Pinto - "Excellent course! Excellent! First 10 lessons and I am already satisfied with the course. Excellent programming decisions and techniques. The video resolution is a bit low but taking this apart, I can't complain. The content itself is really not just thoughtless programming but actually well planned and somehow scalable. Keep in mind that you will face some "not so beginner" topics like delegates, events, coroutines."

Michael - "The instructor is great I feel like I am now able to begin to understand very complex work. Instructor is always incredibly supportive too."

Meet Your Teacher

Teacher Profile Image

Romi Fauzi

Game Developer, 3D Artist & VFX Artist

Teacher

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

See full profile

Level: Intermediate

Class Ratings

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

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

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

Transcripts

1. Course Introduction: Hi, welcome to this Unity course where we will create a point and click game similar to Monkey Island or other point click games with me Rome Fozzy. Okay. In this course, we will delve into multiple topics such as setting up scene lighting, light probes, character animations, object oriented programming, scriptable object for defining items database, and inventory, safe load progress, safe entity system for saving scene states such as NPC states and item states, a synchronous scene loading, audio, and we will also discuss editor scripting heavily to create a custom inspector that will ease the development and many more. On each lesson, a completed script will be included, so you can check them against yours. So I hope you'll able to expand your knowledge with this course and we'll also be able to apply the knowledge to any kind of game you'll create in your project. Lastly, I want to thank you for enrolling in this course, and I hope you'll enjoy and find this course useful. Okay. 2. 01 Project Setup: D Okay. Now, we are going to start to create a new project. And for this course, I'm going to use the unity 2018 0.2 0.8 F one really. So you can use any other version as long as not two different from this one. I think 2017 would be okay. So now I've just started the unity and it's still loading. I'm going to cut this. Now it's loaded, and we should create a new project, suppress new here and I'm going to browse the path, and I'm going to create a new project here. Okay. Yeah, for the time plate, we are going to just to leave this to three D, and I think that should do now, let's just press create project. Once the project is open, we are going to import a couple of assets first. Now our project is open already, and we have this new sample scene here. We can just use this for prototyping first, so yeah. And this sample scene is going to be our basic setup scene for created scripts in this project. And later once we created enough scripts, we are going to create a new scene to build our game. So yeah, We are going to use privatives for this purpose. So let's just create a trey object here under the hierarchy right tick and then go to the treat object category and press plane. We are going to use this for our base ground. And I'm going to make this bigger. So I'm going to increase the scale by twice. This under a project folder here. Let's just create a new material, create new folder materials and here, create new material inside that folder and call this ground. So we can create a darker shades of material and drag this ground to this plane here. So we can see the object over there. Let's create a couple of first, I'm going to create a empty game object, and this will be used as a group. So I'm going to reset its tran form and rename the game object to environment. And I'm going to direct our plane to be the child of this environment. So I'm going to create a couple of different object cube here and move it upwards. So it sits nicely on top of the ground here. Okay. And just scatter this, just duplicate the cube here and there. So we have some sort of scene here, and this will be for testing ification mesh. So under our environment, we want to mark all of this game object as a static objects. So just enable this and press change children. Now we are going to create the player object. I'm going to create a new to game object, let's strike this to sits above the ground here. I want to disable our to generate lighting. So I'm going to go to the lighting tap and if there are no lighting tab over here, you can just go to the window, and then I think it's rendering lighting settings, and we'll open this window here. I'm going to disable to generate so it doesn't generate every time there are changes in our scenes here. Let's save the scene. Now, we need to create some sort of navigation mesh here. So let's just open our naviigation window and it's under AI naviigation, and this is the window here, we can just go to the big tab and press big button and it will create a blue naviigation mesh and this is the I as the layer we'll be able to walk to and it can avoid the holes as shown here, and this will be useful for the player and also for the NPC for moving around the sea. Now let's create a new folder and this one is going to be called script. This folder is for keeping all of our scripts over here and I'm going to rename the capsule game object to be our player. Rename our player. The next thing we want to do is we want to add the AI agent component. This type and AV and here, Unity will sort out the F mesh agent component here. This added. I think we will leave the default setting for now and we will tweak this later. Let's save this our scene and we are going to create a simple click to move script. Go to our scripts folder under our sets, and we want to create a new C sharp script, and this will be the player script file, and let's open this C sharp script. Now we open our script here. We want to import the AI library first under the Unit engine and using Unity engine, we want to insert new line and type using Unity engine AI. With this imported, we can create a new variable type of pas agent, and we need this component to grab our phase agent from our component and access it via this script here. I'm going to just call this agent. On start, I want to grab this agent component. I'm going to get the reference. I'm going to fill the component in our game object to be referenced by this variable. Next time we are going to use this phase agent component, we only need to access this agent variable here. So this type get component. And I think it's NMS agent. Save the script. Now we want to create a click method. I'm going to create a new method oi on click to make sure whenever we click the left button of our mouse, we want to execute this on click here. Like this. Oh, sorry, not get buttoned down, it should be get most buttoned down zero is the left click and one is the right click and two, I think is the middle click. Save this for, I'm going to just to the this method and just type left click like this. Yeah. And let's save the script here and now we can go back to our unity and direct the script to our game object here. I'm going to minimize the component here so we can see it better. And I'm going to direct this player script to our player game object. So save our scene and let's try to play this game here. And now whenever I press left click, as you can see here, the click method gets executed by our left click here. Now we can extend this to create a movement for our player. Okay. 3. 02 Basic Player Movement: So now let's create this movement routine here in our script. Now, let's create a new method called move player. And I think we should input the vector three as our parameter target position. And we can use this agent here. So just type a set destination and we can pass the target position variable that we add here as a parapeter or as an argument. Now on our click, we need to modify this. First, we need to create a variable and call this hit and we need to create another ray variable. I think I'm going to call this to screen and this will be a way from our camera. So in order to define this variable here, we need to get a reference to our camera. So I'm going to try new private camera variable, and I'm going to call this main camera. Upon start, I want to grab this main camera. So we can easily grab the camera using the camera class and using the property main. And as you can see here, this is the first enabled camera tag main camera. The camera has to have a tag of main camera, and we can check this if we select our main camera here under the inspector. We can see the tag is untagged we need to change this to the main camera and we can save our scene here and once we change that, this code will work and it will store our camera. And we need to store reference in our start. So the next time we need to use the reference to the camera or to the other object, we can just access it by this variable here. And all of this reference is being cache in the memory. So it makes the program more optimal. So now we can use the main camera and we have this screen point to ray. So what this means is actually from our screen position, it will shoot array to our scene. Okay. And we can grab our input mouse position. And we can use this ray to recast to our scene and get whatever objects or position or information on where that ray is intersecting. So we can just type this f physics, as and open parentheses and there is 16 overload for this method and it will return bullion whenever it hits something. So whenever it hits something, all of the code inside this F will get executed. First, I'm going to pass our ray, this camp to screen here. For the max distance, I'm going to use the math infinity, and I'm not going to use layer mass at this moment, but later, we are going to add this and we need to pass our raycast variable here in the middle between the first perimeter and the second one. I'm going to add a new coma here and we can just type out it what this out means is actually whatever happens in this method, whenever the ray hits something, that something has a lot of information. It can be positions, it can be normal or the collider or anything that information are being safe inside our hit variable here. Inside this if we can extract any information that we need to create this movement here. So let's just create curly brackets and inside this, we can check whether if we hit the glider is not no. So it means that if we hit something, then we want to do some routine inside this. For this time, we are going to move our player using the player method that we have created before. This type move player, and we can grab the hit point and this will be the position, save this. Let's see if this works or not. Let's go back to our unity and now if we press play, And then if you click somewhere, you can see that our player is moving. So if I try to click somewhere behind this box here, I will avoid. So let's get a better view here. I'm going to change our camera position by moving our view inside our scene editor here, and I think I'm going to use this view here. Yeah. So select our camera and press control, shift and F. It will line our camera, choose this view here. So if we go to our game view, now we have the same view as our scene view here. That is one trick to position our camera easily. And we can save the scene. Now if we press play here, if we click this point here, it will avoid our box and it will go there. As you can see, and if we press here, it will avoid and it will go there. So, we have created a movement for our player, but of course, we are going to expand this script as we go on. 4. 03 Player Movement & Interaction: So now we are going to continue our lessons. And in the last video, we have created a basic player movement system. And in this video, we are going to create a simple interactable element. So let's just create another capsule. Object we can pretend this is an NPC, and just rename the game object to NPC, and let's create a new script. And let's call this interactable. Okay. And now we need to declare a couple of variable. We can just delete the start and uplet method first, and let's create a new public void method, interact. And for this method, we are going to pass our player script into this method. So we can just type the class name, which is player script. And let's just call this player as a temporary variable for this method here. And we are going to create a print debug log to the console, let's just type this click by layer. Okay. And we can go back to unity, and let's add this to our NPC here, interactable. Now, we need to add an event here inside our click. Whenever we pick the interactable or the NPC, we need to check that. Insert here inside hit collider is not. We want to create a new temporary variable, and it is interactable. And we want to grab if our hit clider has that component. So we want to check does the object that we click has this interactable class attached to it. And if interactable is not null, then we want to run the interact function, and we want to pass the player script. And since this is the player script, we can just type this keyword to pass this component here, this class two this function here. And we can just type we want to move the player to the hit point, Maybe we can just type the game object name, type gave object name and add it with this ten k. So let's go back to unity and try this. Now if we open our console here, it's still compiling the script. Yeah. If we open our console here, if we click somewhere, I will just move our player. But if we click the NPC, it will tell us that the NPC is clicked by the player. But it doesn't move because whenever we click the NPC, we only run this intra variable. So we need to expand this interractable. So it works with our player script. And the next thing we need to do is we need to create a public void inside our player Script, and this will check if our player arrived on the destination for this example to the interactable. And for checking this out, it is quite simple. We can just return an argument or a condition if our agent pass pending. If there are no path pending currently, so we add this exclamation mark, So it means the path is not pending currently, and if the remaining distance is smaller or equal than the agent stopping distance. So it means that we've arrived, and if we arrive, then we should return this. But I forgot that we should have a return type here. It should not be void, but it should be bullion. So I'm just going to change this and this will return whether the condition is true or false, then it will return that value. And now we can create some sort of routine and just call this wait for player arriving. And we are going to also pass the player script to this core routine here. And since we pass this player, we can check while Player, the check is arrived. We can run this method, but we can make sure if it's not arrived, we add this exclamation mark in front. So it means it's not, then we can just delay or we can just return the whole routine, and when it's true, then it will run the code below when the player arrive. So with this statement, we want to make sure that if the player is not arrived yet, then we want to delay the routine, and once it's arrived, then we want to run whatever code that we have below here. And for now, we can just type player arrive. But this won't work yet because we haven't tell the player to move. But in order to make the player move, we need to declare a position for the intractable. So we can just create a new function, a public function that return type factor tree, and this will be the position. Okay. And we can just return the position of the game object, transform the position, add it with our transform forward, and we can multiply this with some value because transform forward has a distance of one, and if we want to make the object closer than one, we can just multiply it by a value smaller than one, for example, value of half unit like this. Okay. Let's save this. And now we can whenever we interact, we want to move player to the interact position. So let's just type the interactable variable that we've declared here and get the interact position like this. And then whenever we execute this interactable, we want to run this coro routine. So we can just start the coro ruutine here and type the coroutine method that we've declared below, and we need to pass the player parameter or the player object here, that we passed from the script here. And save this and now let's save our scene also, and let's try this. Now we can go here and if we click on the NPC, it will run to the front of the PC. As you can see here, it showed the player has arrived. Let me just show you again. If I click on, there is an issue here because when we click the PC, the player arrives show straightaway. So we need to fix that. Okay. So yeah, I found the issue, why it shows the player arrive right away when we click on the NPC. So basically, we need to switch this line position, we need to make sure that we execute the interrat after we move the player. So yeah, I'm going just to cut this line here and paste this below. And why is it like this? Because for the interact, it will run the routine right away. But if we assign move layer after the interact is being executed, then this will return true on the first frame. But if we move the player, it means that our agent already has a destination and it wouldn't be arrived yet on the first frame. So after we move the player and then we run the interact, then this will return false on the first frame. So it will loop this coroutine until this is true, then it will print this out. And let's test this to see if it's working or not. Now I can go here and there. But if I click on the NPC, as you can see here, player arrive prints out after we arrive on the scene here. And as you can see that 0.5 is near as a target position. So probably we can just create a new float field or variable, and this will be the distance position. And set this default one and we can multiply our transform forward by this position. And basically, what this interact position is returning is basically the position of our NPC, and it is added by the transform forward. So Transform forward is basically the blue axis and it's local to the NPC game object. So if we rotate this, the transform forth will be this direction here. So probably the player will stop around this area, and if we rotate to this direction here, then the player will stop to this area here. So let's give it a try again. And I'm going to click this. And as you can see there, sorry, I think we don't click. There you go. And if I change the distance position, for example, two three, and go somewhere else, and then click on the NPC again, You see, we have a distance here. And if I change to also, it will change the interact distance, as you can see. So yeah, that is basically the very basic script of our interactable. Now we have faces that detected by the script, whenever we clicked it and whenever the player start moving and when the player is arrived. So in the next video, we can continue to expand this feature. 5. 04 Player Direction: So we are going to continue here with our player and interactable script. And now, if we play this, we have no way to know in which direction our character is facing. So let's create a new child object to the player. And this will be a cube here and I'm going to change its scale on the x axis to 0.5. And also w x 0.5, and I'm going to leave on the z one and move this slightly forward. And I want to make sure that this cube here is aligned to our z direction here as you can see, and this is set to local, so this is the local direction. And we want to do the same for the NPC, so let's just create a new cube here and scale it the same value as our player, and let's move this on the z axis. So we know in which direction the NPC is currently facing. So let's just save this. And now, if we move the player, we can see the rotation right. And if we press this, it will go there, but it doesn't face the NPC, and I think one is to close, so we need to go to our NPC game object, and for the distance position, we can safely change this to maybe 1.7. And now let's try this again. Okay. And as you can see here, the player is facing to the NPC when it's arrived so we want to fix that. I'm going to change this first. And for the player, I want to set the NaF me agent component here, the angular speed to a very high value here. So let's just try this seven 20. So whenever we move, it will rotate very quick to the direction, something like that. This is better or maybe we can increase this value here. Okay. Maybe 960 a good value here. Now let's go to our script to our player script. So we need to create two new variable here, and it's going to be private. The first one, it will be a bullion variable, and we'll call this turning and it will default to false. And for the second variable, it will be a quaternan variable, and this will be the target rotation. And now we need to create a new public method void and let's just call this set facing or set direction, we are going to pass a ectrore parameter, and let's just call this the target direction. Now inside this method, we want to set the turning to then we want to set our target rotation value to a new quaternion and we are going to use the quaternion class here, and it has a method to define a quaternion using the rotation method and it creates a rotation with the specified forward and upward direction. And we are going to use only the forward. So in order to get our forward direction to face our player, we can just the position of the NPC, which is the target direction here that we pass here and substract this with our position. Okay. Let's say this after we created this method, we need to update our update method. Basically, what we want to do is we want to check if turning is true and our transform rotation is not the same as our target rotation. Then we want to rotate our player. Let's just set the rotation using the quadrant class and it has a slap function, and this will interpolate between the first rotation, the a rotation here to the B rotation with interpolation value, the speed value here with the float t here. For the first rotation, we are going to get our carbon rotation, and for the target, we want to use the target rotation. And for the lot value, I'm going to set this to a higher value, 15, and we want to multiply this with our time Delta time. So the speed will be consistent across different specs of computers with a different frame rates. So it looks okay, another thing we need to do is whenever we move the player, we want to set the turning back to falls. Okay. Okay, yeah. Let's try this. Oh, sorry, we need to run this set direction and we haven't done that a thing. We need to, we need to do this inside our courting. So whenever the player arrived, then we want to run the set direction, and we are going to pass this interactable position. So just type transform the position and save the script. So basically, when we arrive, then we want to set the direction. So our player will be facing this NPC character or any other object that has this interactable component. Okay. Okay. So yeah, let's try this. Okay. I'm going to click on the NPC here. Yeah. And there you go. As you can see, once it's arrived, it will face the NPC here. So yeah, that is for facing the direction. 6. 05 Base Action Class: Okay. So now we are going to create an action class and we are going to create a base class of action and many action will inherit from this class. So let's just create a new folder and I'm going to call this folder base class. And inside this folder, I'm going to create a new Cb script, and I'm going to call this action. And I'm going to name this with S on the word because I figured that if we use the action name, it will conflict with the system action name class. So just add an S at the ends, and for the class, I'm going to rename this as actions. And I'm going to make this class an abstract class. So basically an abstract class is a class that we cannot attach to a game objects we can only attach a class that inherit from this class to another game object. I'm going to create a contract method and this will be the type of public abstract and turn type is void, and I think this will be like this. With method with an abstract definition, we cannot create the body code or the code inside. But all of the other class that inherit from this action class must implement this g method. So when we later iterate an actions class, we can always execute the class, but each of the class that inherit this actions class will have different definitions of g. So we can create a vast variety of actions component later. This is the base class, and I'm going to go back to unity, and I'm going to create a new action folder. Inside our script, and this will be all of actions derived script will be saved here. I'm going to create basic message action. And instead of inheriting from mono behavior. I'm going to change this to inherit from actions. And as you can see now, we have an error, and it tells us that it does not implement inherited abstract member Act. So withFsotud, we can just type the show potential fixes and then implement this and it will implement a new method if you are using other IDE, you can just write this down and we can just remove this. And I'm going to delete the update and start method. Okay. So now for the message action, we want to create a string array to show this message. But for this video, first, I'm going to create just a single string variable, and later we are going to modify this. Okay. Whenever we run the g method, we want to print out this message. Just type the log, and we can pass the message variable to the parameters inside the debug log function. Now we can go back to unity, and if we go back to unity, we can add this message action to our NPC here. So just drag our message action. We can go back to our interactable. And when the player arrived, we can execute all of the actions that we have inside this interactable. Let's just create a new variable, and this will be type of actions, but it should be an array, so we can add multiple actions to it and just call this actions. Here below the set direction, we can create a new loops, and we can look through the members of this actions array variable here. Type actions length length, and length, we'll grab how many members do we have inside this variable. On each of these entry index of, we can run the function. And this is why we create the base action, so we can just implement the ag or we can just execute the ag and this will run different a method across different type of actions. And since all of the actions will derive from the actions based class, this interactable will recognize this ac method. Okay. Let's go back to unity and let's test this out. But there is a neat trick here. We can do in the message action. We can add and attribute here and just type multi line, for example, if we want to set this to five line long for the message inspector window here. Just insert five as the value. And if we go back unity, we will have a bigger message window, so we can type a clear message or anything, a dialogue or anything. Let's just type, for example. Hi. How are you? And we can expand our actions under the interactable and direct the message action. Now, when the player arrives to the NPC, the console will print out this message. Let's test this out. Let's go to this here. And yes, there you go. Once arrived, it prints out this message. Later, we are going to create a dialog window that will show this message and also a dialogue button, so we can choose between two options when maybe an NPC ask for something, then we can just pass a yes or no answer to it. Okay. 7. 06 Basic Dialog System: Let's continue from our last episode and now we are going to expand our message action, so we can show multiple message, and we want to also create some sort of UI or UI for the message on the game window. Instead of showing the message in the console, we want to show the message in the game window. Let's just create a new UI component, and I'm going to create a new image here as you can see in our game, we have this image, and this will be our dialogue panel. I'm going to create a new empty game object. And this empty game object basically will fill our canvas. Currently, we have this big. So I'm going to change this c preset by holding the button on the keyboard and press this lower preset and it will fill up our screen here. And for the canvas, we want to change the setting also, and I want to set the UI scale mode to scale the screen size and set the reference resolution to 1920 by ten ADP. Then we want to set this anti game object should be our dialogue system. And we want to drag our dialog panel to be the child of our dialog system here, and we can set this around 300 as the height or 250 should be okay. I want to set this to fill the bottom area. I'm going to hold the L key again on the keyboard, select this preset here. The one that above last preset that we have choose before, this one, click and now we have this. But I think I'm going to make this back to 300 and set this again. I positioned correctly. We want to create a gap on the left side, maybe around 25 and the right. And for the position, we want to add 25 to it. So just type plus 25, and it will calculate the new position. Now we can change its color to a dark color to black and set the alpha value to around 0.5 or 0.3. Yeah. So now we have this semi transparent panel, and we want to create a new tax object. We want to use the Tex mesh P if you just create a new project, then you need to import this TMP essential. Just click this button and it will prepare the package. And now it's Tex Mesh P is integrated building with the newest unity. Okay. So now we can close this window. Now we have this text. And I want to make the text window to be the same size as our pattern game object, which is the dialog panel. So hold the button and then just address this three sets again and it will fill out this dialog panel size. And we want to also add a gap to the edges here. I'm going to set this to 25 for each of the position like this, and this will be our dialog text. I think we need a larger gap on the right side, also on the left side. Yeah. And we can save our scene here. And now we want to create a new script, which is our dialog system. So just create a new C sharp script, and this will be our dialog system. So now we can open the script. I'm going to increase the size of our editor. And now we need to create a couple of variables. So I'm going to create a new SS field variable, and this will be the type of text mesh pro. But we need to add the name space in front of it and then search for the GI class here, and this will be our message text. And we need to create another field, which is a game object, and this will be our panel. We also need to create a new private variable, and this will be a list of string. I'm going to name this current messages, and we need to initialize it by typing type of string here, and another private variable, which is an integer type of integer, and this will be our message ID. And this will default to zero. So we want to create a static reference to this dialogue system. So I'm going to create a new properties here, public properties, and this will be static. I will mark this property static, and the type should be our dialogue system. And I'm going to call this instance with capital I. And I'm going to set this properties to be a public yet but with a private set. So we can set this instance properties inside the script, but script cannot change this. A script can rip this properties because we have this public eta. So yeah, and I'm going to create a new wake method for initializing our static incense. So we can just type incense, and we want to set incense to this. Okay. And now on the start method, we want to disable the panel right away. So we want to set active to false. I don't think we need an update method, so we can safely delete this method. So we want to create a new public void method, and this will be the show messages. And this will ask for a list of string, and we can just call this parameter messages. And now we want to set our current messages to this message here, type current messages, equal messages. And then we want to display our panel here. So we can just type panel set act I forget the semicolon over here. Then we want to start a core routine, which we are going to create the co routine after this. But I'm going just to show multiple messages. And since we haven't created this, it throws an error, but we are going to create it now, so just type the return type numerator because every coroutine need to have this return type, and we can just copy this name here and paste it and close it with a set of parentheses. Now we can set our core routine. Basically, we want to look this coroutine while our message ID, This integral variable that we have created is less than our current messages count. So whenever this is still below our count, then we want to loop this code here. But once it becomes greater than the current messages count, then we want to stop this core routine here. So while we'll make sure if this condition is true, then we will keep looping every code inside this while block here. So now we want to check if the user press a space bar, or if the user pressed the left mouse button, then we want to increase our message ID and show the new text. Here on the start, we want to show the first message that we have. So we can just access our message text here, which is a text me PI variable here, and we want to change the text properties. To our current message and the index of our first message, which is zero, and when we start running this score routine, the message ID will be zero, and when we press space bar, it will increase this and it will show a new message. So we can just copy this line here, and whenever we increase this, we show a new message or we change the text text with the new current messages with the new message ID value here. Let's just test this out. Type panel set active two falls. Okay. I think we need to make sure check whether our message ID is still less than our current message dot count. Because C is the total members of our list here list of string, but the highest or the maximum ID is usually count minus one. So if message ID is equal in count, we don't want to increase the message again. And with rot, we need to put a yield return statement. So I'm going to return our coat here. So it will look this while. Otherwise, it will crash our unity, and let's just try this first, go back to unity and go to our dialect system and we can direct this script here. And now I'm going to direct our panel, and the panel is the child object that have this background here. And for the text, we want to direct this text mesh pro game object. Save this. Now we need to modify our methods action. So basically, we want to instead of using the debug log here, We want to access our dialog system do incense this is the benefits of using the static method static way of setting this up because with static reference, we don't need using get component or fine object of type. We don't need that at all. So yeah, we can just type the static name and we can run the method, the public method that we've created here, the public show messages, and we want to pass our list of string. So I'm going to change this to a list of string. And we want to pass this message to our show messages. Now let's go back to Unity and test this out. Hopefully, it works and choose our NPC here, and now we have a list of message. There's 16. I'm going to just change this to maybe message, and I'm going to type you and the NPC will be an officer and maybe we can just reply. Okay. So let's save our scene here and let's test this out. Okay. Okay, now you can see here, we have this window dialog system, but let's press space bar. Okay. It shows our next message, and if I spacebar again, it close. So yeah, as you can see, it works really well. And if we try to conversate with this NPC again, it will give an error that the index is out of range. So yeah, we need to reset our message ID. Let's go back to our dialect system. And whenever we set this two falls, we want to reset our message ID two zero here. Okay. So let's try this again. Okay. Good day, sir. Good day, to two. There's an issue here, as you can see, whenever we try to. Okay. Yeah, it works, but if we click again right away. Okay. We have to leave this first. For the clicking NPC issues, there is a slight changes we need to do and it's a simple one. Here in our statement, we need to make sure that we are using the mouse pattern down, not the get mouse pattern, but the get mouse pattern down. So it will only gets executed in the frame when we are pressing the mouse down. Otherwise, if we using input mouse pattern and it might get executed twice in a row or more, and this will cause issues. Okay. So yeah, that should be our basic dialogue system, but later, we are going to extend this to Heaven options, so it can create some sort of dialogue box and it can give answer. If the NPC asks a question, we can answer it with two options. So yeah. Okay. 8. 07 Check Mouse over UI: Okay. So now we are going to continue to create our dialect system. And in this video, I'm going to create an extension method that we can use on other script, and this method we'll check if we click on top of the UI or not. So, because as you can see here, if I try to conversate with this NPC here, and then if the user tried to click on the UI here, it will show the next message, but it will also move our player to this point here, where we click. This would be an issue and we need to fix that. So I'm going to create a new a folder extensions. And I'm going to put our extension class here, and this will be a static class. Okay. And let's open the script. And we are going to delete this mono behavior, so it doesn't inherit from the mono behavior. And this will be a static class atension we are going to delete our method. And for checking if our mouse is on top of the UI, we need to import the unity engine event system. Okay. And we are going to create a new public static and this will return a bulon going to call this mouse over UI method. And we want to return this event system. Current is pointer over game object, since this is a method, we need a set of parenthese this will return true if we are on top of UI and it will return false if we are not on top of UI. Now if we go to our player script here, we can add a new condition in our left click here. So now we can add a condition using the N operator and we can use our extension class static class here, and we can check if the mouse is over UI method here. So this will written through if it's on top of UI, but we don't want that. We want to make sure whenever we click outside of the UI, then the player is going to move. So just add a exclamation sign in front of this statement here, then this will negate the condition and should check whenever this value is false, and under our dialogue system, we want to make sure also we want only to left click and if The mouse is on top of the UI. And this time, we want to make sure if the mouse is over the UI, it's not outside of the UI but on top of the UI because we want to click on the message window here. Let's go back to unity, and let's play. Now I'm going to try to talk to this person here. And if we on top of the UI, our player will stay there. But if we click somewhere else, our player will move, but this UI will stay so we can click on the UI again and to hide it. Okay. Yes. So this is a neat trick using this event system here. And with static class, we can create a static method that can be used on many classes, and we are going to expand our extension here with many other functions later. Okay. 9. 08 Message Dialog Window: Y. Okay. So now we are going to continue with our message action, and let's open our script here. I've already opened the fiscal Studio, and let's go to our message action. So now we want to create an option for the message to have a dialogue system the player can choose between the right or wrong answer, and we can launch an actions depending on the reactions of the player. So now let's create a new buls field and type of bullion, and we are going to call this enable dialogue. And we want to create a list of actions. And this will be our yes actions, and we want to create another one, which is the actions, and we are going to pass this value to our show messages. Now we need to modify our show message method first. Let's go open our dialogue system. Under our show message, we want to pass our dialogue, and we want to also pass our list of actions for each of the actions and also the list of actions for the actions. Okay. But we want to add a default value here in our parameter, so we don't have to pass every time we use this method. We can simply assign by default to u by adding an equal sign and then keyword null after the equal sign. For the action, we want to do the same. So now, basically, we can opt out if we don't have any actions. If we only want to show messages without dialogue, we can just opt out using the actions here in the show messages, and we will see it here. Okay, now, I think we need to modify the message action first, so let's go to message actions class. Here, we want to pass the enable dialogue, let's just pass enable dialogue, enable dialogue. And for the yes and the no action, we can pass here, both of the list. And if we didn't insert any actions to it, then it will simply pass the nual value, so it should be okay. And save this. And now we need to modify the dialect system. First, we are going to import the Unity engine UI name space. So we have access to the button class. And here below our game object panel field, we need to create a new field, and this will be a type of button, and we can create a new button and also the no button. And now we can modify our show messages. Basically, before starting the routine, we want to assign value to our button here. We want to check if the dialogue is true, then we want to pass those actions. Otherwise, we don't need to pass those actions because there won't be any dialogue. And for this to work, we need to create a custom method here below. So I'm going to create a new method, and I'm going to call this assign actions two buttons. And here we want to pass a list of actions. And let's just call this actions. And we want to create a new local variable here inside this method. And let's just call this local actions. And this will have the value of our past actions from the argument here, and we want to look through our local action do count because we are using list and the length of this list or this array here is using the keyword count. And now we can look through the actions and on each member of the actions, we want to run the method. And we need this because we are going to pass this method to the button here. Now, if the dialogue is enabled or if the message is using a dialogue, then we want to set our action, but button, click, and this is the event and we want to first remove all previous listener. Then we want to add the new ten sorry using the on click event and then add listener. Now we can create new delegates here. With a curly brackets, and we can insert any codes to this statement here. So the first thing I want to do is I want to run the assigned actions to button. And we need to pass a list of actions here, so I'm going to pass the yes action. And then on the second line, I want to disable our panel. We can run the set active method from our panel game object and set it to falls, and as usual, put a semicolon at the end, and we can copy all of this here line. And then we can change this to the no button. And also for the second line, we change this variable to the button, and then we want to pass the actions, and we want to set this to falls. We can just pass this or we need to check this if the actions is not null, then we want to pass the action. And same goes with our no actions. So we want to check if no actions is not null, then we want to pass the no actions to the signed actions to but. Otherwise, this code might throw an error if our local actions is null and trying to lot that. Okay. So we are finished with the show messages, but we need to modify our core routine here. We need to pass a bulon here and just name this use dialogue. So we know. Since we have this dialogue, bon, we can pass this whenever we execute the core routine, and since this value can be true or false, we can check that. We can check if use dialogue is true, then we don't want to deactivate the panel right away, but we want to show our button. Let's just access the transform the parent the game object set active two true otherwise, then we want to set the panel to the activated. We want to hide the window if there are no dialogue, and we only want to hide the panel. Once we click the button if we are using any dialogue system. One thing we need to make sure is whenever we show a new message, we need to hide the button group first. Why are we accessing the parent? Because later, we are going to put those two button, the yes button, and the no button to a anti game object first before attaching to the dialogue system panel. So we can just hide it when we show the message first time. We can set this to false and save this. Now let's go back to our unity and open the Canvas window going to access our dialogue system. Here. And we are going to create a new empty game object. We can just put it anywhere. I'm going to put it below here using this e st here. And let's call this a button group. Let's create a new button. I'm going to create a new button here and I'm going to make the hight to be around 70 and for the width to be around 240 or maybe longer, 350. I'm going to remove the source image, so we don't want to use any source image. I'm going to set this color to black. Also going to remove the text. And we are going to add a new text mesh pro here, and let's just fit the transform. And we can use to size. And also, I'm going to add an outline to our button game object. So let's just type outline to the component. And for the outline, I'm going to set this two wide and with the effect distance value, also five on the y. So we have a border, and you can see here in the game, we have a nice button. And I'm going to put this on the right side, and I'm going to push this. This would be our button. Let's duplicate this by pressing Control D, and this would be our no button. And let's move this to the side. Yeah. Okay. So now we have two button, and we need to create a couple of more modifications to the code. So let's go back to our official studio. And under the message action, we want to create a string for the button text. So let's create a new string. And this will be the tax and the text. We are going to pass this, but we need to modify our dialog system. Inside our show message, we need to add a new string after the actions. This is yes, and we can set a default value to yes. Like this and no string, we can set a default value to. Now we can pass to our mesh pro on our button. But we need to create a variable for it. Let's just add this. Let's call this tax and the tax. Now if we are using dialogue, we want to modify the text. So we can just access our text, the text to be our string that we pass here on our parameter. Copy this and for the we can change this to our string like this. And for the message action, we can pass our text and no text to here. Now we are passing all of the field that we have declared or defined on our message actions and hopefully this work. Let's go back to unity and save this for the NPC here. Now we have this under our message action, we have a couple of new fields here. Let's create two new message action for testing out. For the first one, we are going to enable the dialogue and we can just set this to and this to know. Now we can create a new message, and if we are responding yes, then we can show message nice. If we respond no, then we can show message bed we can direct this message action to our yes action and direct to the no action. Now it will have differ response depending on our play or reaction. Let's just save this and play let's go to our NPC here. Okay, there is an error. Oh, yeah, sorry. Under our dialog system, we haven't set this text and also the button. Let's just direct the button first to each field, corresponding field. Expand our button, and for the text, we direct to the tax, and for the text mesh object, direct this to the text. Save this and run it again. Okay, so let's go back go to our NPC here, and it will show message. And when we click and then we click again, it will show a text. Let's just press. Yes. Okay. There is an issue here. Okay, so there is a slight mistake in our code here. Instead of running the assigned actions button first, because if we run the actions first, when I click button and then set the panel to disable, it will cause an issue. So we need to make sure that this panel set active falls is executed first before we are executing the actions for each of the buttons. So I'm going to move this on top of above the actions code here, and same goes with the actions. And save this, and we need to also move our code where it handles to reset the index message. Let's just cut this code here and put it on top when we started showing message, we reset the index here. This makes more sense, and it's much better because with the previous code here, when the message index equals zero is still on this coroutine, it can cause issues. Let's save this and let's go back to unity. Now let's one game. Now if we go to our NPC here, it will start dialogue, and if you click and then click again, it will show the button. If we press, yes, it will show the nice response. But we cannot click anymore because the button is gone. We need to click on the NPC again, and then try What if we press no, and it will Response bed. But there is still one issue here as you can see, if we click once and then click twice, this is the last message. But to show the dialogue, we need to press it again and we don't want that. Basically, what we want to is whenever we arrive to the last message, the button showed automatically together with the last message. Let's go to our code here and let's fix that. Here in our routine in our show multiple message routine under the dialect system, we want to check if The message ID, our message ID is equal to our con, but substract with one because the last message index is always equals to the con substract by one. So when we arrive on our last message, then we want to show this button here. Okay. But we want to do this whenever the use dialogue is true. We need to add a condition use dialogue, and we arrive on the last message on our list of strings here. Now we can just remove this and we want to disable the panel if we aren't using dialogue. We can add a exclamation sign here before the use dialogue keyword. I used dialogue is false, then disable the panel. Now I think this should work saved this and go back to unity. And let's play this again. Go to our NPC and once we have dialogue. Yes, as you can see on our second message, it shows right away the Button cannot click anywhere. But if we go, the message stay. So we need to fix this also. But it's okay right now. We can just test this out. Yes, it works. And if we talk again, we can press no. Yeah. So we want to test also if the custom labeling works. So let's just set this back to normal. And for the first message action, we want to type awesome, let's say, for the no text, we can just use Let's save this now go to our NPC, and there you go. We have custom button text. Okay. Another thing we need to do is we need to make sure whenever we interact with an NPC and then we suddenly we cancel it. Let's say by moving to somewhere else, we need to disable our message. I'm going to create a new public void it message or hide dialogue, and we want to set the panel, set act two false. And this needs to be public because we want to disable this from other script. Since we have a static pattern with our dialogue system, we can go to our player script. Whenever we move the player, we can hide by accessing the dialogue system, instance dialogue. Save this. Now let's run it again. And try clicking on the NPC here and don't click on the message, but go somewhere else. Okay, let's get disabled. And if we talk again, it will show the message again. And if we click on the second one, if we go, it will also disable. But since the message ID is always reset to zero whenever we show new messages, it will start the conversation all over again. Okay. So yeah, that is for our dialogue system, and later, we are going to create a custom editor for this to make this much more neat and easier for us to design the game later. Okay. 10. 09 Item & Database: Or Okay. Now we are going to create our item class and also item database scriptable object. While we are using scriptable object, because scriptable object is very easy to share across the scene and the content or the values. The data will persist on each scene and basically we need a reference to all of the items that we declare on this game here, and item database will be different to our inventory. Inventory, we can add or remove item on runtime when we play the game, but item database, we need to define this on the editor and once it's built, I cannot be changed the item Davise basically, item database will hold all of the items available in this game. Let's just create a new folder in our script folder. I'm going to create a script folder. I'm going to call this script object. And inside our base class, we want to create a new C sharp, and let's call this item. And we are going to open this item script by going back to unity and double click on our newly created C sharp. This class, we are going to use mono behavior because this is basically a custom class that we are creating to define our item. We want to mark this item serializable, so we can just add square brackets and type system serializable. Basically, if we mark a class serializable, then we can show this value on our inspector later. It means that unity can serialize this class. Now we need to create a new serialized field. And this would be an ID. So we can call this item ID. And for the second field, this would be a type of string, and this would be the item name. And the third one is also a string, but this will be the item description. And another thing we need to add is the pride. This would be the icon or the image, itempt The next one would be a bullion, and we call this low multiple. There will be a couple of items that we can have more than once. So we need to have this bullion flag, and the last one will be a integer and this will be the amount. We can only change this later if we enable the allow multiple flag here. Safe now we have this custom class. I think we can just remove this two libraries that we are not using save this and go back to unity. And under our scriptable object, we want to create a new CSO script, and this will be the item database. Open this and we want to change the inheritance, instead of mono behavior. We want to set this to scriptable object. And we want to create asset attribute. Let's just type create asset menu. Basically, we have these properties for the file name. I'm going to set this is a string, just type item database and them name. We can set this to customa Blas item database. Okay. Now we need to remove this two method here, and basically for our item database, we want to create a new serialized field, this would be a type of list of items, we can call this items and we can just initialize the second field is going to be a list of string, and this will be the items name. And initialize this also. But we are not going to change this value later and we are going to create a custom editor so we can just hide this in our custom editor later. But we need this list of string to create a pop up later when we are creating a custom editor for our inventory. Let's just save this and go back to unity. Now, if we right click on our asset, we have this new custom data menu under create, we have this custom data and we have this item database. I'm going to create a new data folder, And inside this data folder, I'm going to create this item database and now if we press enter, it will have this item database. And as you can see here, we can add members item and we can add definitions to each of the items here. But we are going to automate a couple of processes here using the custom editor. In the next video, we are going to discuss how to create this custom editor for our item database. 11. 10 Basic Custom Inspector: Okay. So now in this video, we are going to discuss on how to create a custom inspector. And here, I've already created some temporary script called some class. And inside this script, we have a couple of variables, and we are going to try to create a custom inspector for these fields here. So let's go back to our unity, and in order to create a custom inspector, we need to create an editor. And all of the script that derive from editor class, which most of these classes are going to handle the way we inspect our class, creating custom inspector here, need to be reside or to be safe inside this editor folder because assets that resides in this editor folder will not get included in the final build. Let's just create a new CSP script, and I'm going to rename this to some class editor. First, I'm going to create a new empty game object in our scene here. We set its value, and let's just drag our SM class here to our game object. Here we have this inspector. This is the default inspector that gets rendered by unity, and we can customize this. Let's go to our editor folder and let's open this SM class editor. Now we need to import or we need to using the Unity editor namespace. We need to also make sure that this class derived from the editor class. We need to tag this class with an attribute called custom editor and open parentheses, and then we type the keyword type off. Then the class that we are going to create custom inspector. In this case, we are going to create a custom inspector for this class here, some class. I'm just going to copy this class name and paste this inside the parentheses. Save this now let's create the custom class. Okay. So as you can see here, we have two types of fields. And basically, the first one is a public field, which I don't recommend this because if you need a field that accessible to the inspector, I would recommend using the serialized field because if that variable should only be changed in the inspector, then this is much safer because other script cannot access this. With this example here, the top one, communication with other script may cause issues if we modified some of this variable from other script, and maybe we forgot with those modifications, it can create issues, and it will be hard to track the bug case. So let's go back to our subcase editor, and I'm going to show you two method on how to create a custom inspector for both of this kind of variable. Let's delete all of this default method, and let's create a new override if we press base, official studio will show us auto complete and we need to create the uninspector GI and safety. Basically, this is where the custom inspector happening, and this base method is for drawing the one that we have, the default inspector here. If we just comment out this code here, as you can see and save it, go back to unity. We can see that now if we select this game object, you can see that some class doesn't have fields. Somehow it's hidden because we oprite the basic inspector drawing, GI, and we don't create a substitute for it. Now, first, we need to create field with the type of our class here, some class, and it can be named anything, but usually we call this source. And we can create a void on enable. Then inside this enable, we can initialize this source by assigning a from the keyword target and target is basically the object being inspected. But since target is an object and source is a type of some class, we need to cast this object to some class, so we can just add a type casting in front of it and type the class here and save it. Now, once we declare this or we define this source and also initialize it, we can create a custom inspector. For the public fields, we can easily type the keyword source, and then the player name, and this will be our string variable player name, and we can create a new inspector by typing the class editor Glayout then we can use the text field or text area. Usually for typing input, we use text field, and then we need to pass this variable inside this. Here. Save this, and we can add level in front of it. So we can put label in the first parameter. So the string text, type let's say, we can type player name. Okay and then save this. Once we save this, if we go back to unity, You'll see that after our script is updating, we have this player name field. Same goes with our float factor. For float, we can easily type speed and type editor GI layout and we have this float field and just pass this source speed. And for the factor three, of course, we can let's say we want to access the player position. We want to draw the custom inspector. We can just type editor GayoutFctor three field here, and we can pass the value right away like this. But we have an error. It needs a label. So let's just add label in front of it. Okay. And this will be our player position, for example. Let's save this and now we will see that once our script is updating. We can see There you go. We have this custom editor. For game object, since this is an object, the same goes with the type of sprite and stuff, we will need to create a new editor object field. Let's just type variable, the fields that we want to set it for this case is player prefs and the editor. Layout object field, and here we need to pass our source prefep here and let's check the other overload method. This one, this is the object and the type. We need to put a type of game object here. But still we have an error because we cannot convert this object to game object, so we need to cast this as a game object in front of it. This is an obsolete warning, I think we need to add a parameter which is the allow scene object. Basically, what this allow scene object is for this inspector. Should we allow the designer or whoever using this script to pick scene object or it has to be a prefab inside or asset. If it's true, then we can pick an object from our scene, and if it's false, then we should only pick object from our asset folder. Let's just type through here. Once we type through, there are no warnings anymore. So, let's go back to unity. Then as you can see here, we have this game object slot. So this is basically how creating G and we can create a group like this. So if you type I lay on top of it and then we can type let's say begin vertical, this is vertical group, and then we close it with G layout, vertical. This will group and nothing will change now, but if we pass a string called box inside the argument of megan vertical method here, it will create a box for all of our fields here as you can see here. It creates a nice dificient group. This is basically how we do with the public method. And now we are going to try to create a custom inspector for the serialis field. The problem we cannot use this method here, because if we type the source and we search for the variable, as you can see, it doesn't show because this is basically a private field that has been marked as serialized field. Now we need to find a way how to create this variable. First, we can create a serialized property object here, and we can type player name here, and we need speed. Also, we need player position. And then last one we need to create player prefabs. Okay. Now for each of this property here, we will find using a serialized object. For the player name, we can simply type like this. We use the serialized object, and basically, this is a serialized object representing the object or objects being inspected, like target, but it can also represent the serialized object. I'm going to re type this and enter this, and then we use defined property method. Inside this fined property, we need to pass the name of the fields here in string. Just type this here. Okay. Now we can just duplicate this line here, paste this a couple of time, and change this to speed, change this to player position. Change this player prefects, for the speed here, we can just type underscore speed, and this would be as underco player position. And this will be our S player prefabs. The naming it has to match with the one that we have here. We if we change one of this field here, we need to also change this accordingly here. Now, let's create a new grouping here, G layout. Sorry, begin vertical, and I'm going to create also a box here and close this with the vertical. Now, save this. Now in order to create a custom inspector for this type of object, we can just using the editor I layout, and then we use a property field. For this property field, we need to only pass this serialized property. We can pass each of this field here together. Let's just copy this field, paste this a couple of times. Then we can put each of this property field that we have declared before. And it will automatically render this. Let's go back to the Unit editor. Now once it's finished compiled, it should update our Suss. There you go. We have this here. But the problem is it has the default name from the script, which is S player Speed and stuff. If we want to change that, We need to create a custom label. We can create a custom label by typing a new I content, and then we can type a label name inside of this parenthese here. Let's type the player name like this and we can copy this I content and paste on all of this property field, and this should be the speed or player speed. This will be the player position, I think, and this will be the player prefabs. Let's go to our editor here. Now once we finish update, it will have a custom name as you can see like this one. If we put a label for this object field and the speed field here, it will render the same as the one below here. Now, since we are using a serialized property, we need to put and apply modified properties here. Because if we don't put this method here, any changes that we've done in the inspector would not be safe. So make sure if we use the serialized property here, put this below. And in this example, we are going to mostly use this method in order to create a custom. One thing though, one neat trick is, we can create a button, for example, if you create button, you need to create statement and then row the button inside as an argument. And you can type the name inside this. Let's say randomize speed, K, and this will return true whenever we press this button in the inspector and we can run some code inside. With this button, we can create custom action here. For example, we can change our source speed here using a random dot range 5-25. If we save this, go back to our unity here. Once it's update, it will show this button here. If you press this, as you can see, we can create random number. Okay. And if we want to change the value of the serialized properties one here, we can just type properties. For example, speed here, the serialized property, and we access its value by typing the float value here. Save this and this will do the same for our serialized field one here. Yeah, that is basically how we create custom inspector. 12. 11 Item Database Inspector: Okay. So we have learned how to create custom inspector on our last video. So now let's start create a custom editor or custom inspector for our item database. So first, I'm going to go to the scripts folder and I'm going to create a new editor folder. And let's call this editor. And all of editor related script or classes, we are going to put it inside this folder. So let's create a new C script, and let's call this item database editor. Once it's created, let's open this on fisico studio, I'm going to increase the phone size. Now from our previous video, we need to import the Unity editor namespace. And then we need to make sure that this class is derived from the editor class. And we also need to tag this as a custom editor and set the type off to our inspected class, which is the item database here. Save this and we are going to delete all of this built in method. Okay, now let's check our item database and let's open our item definition class here. Let's just go to definition, and now we can inspect the fields that we have and which of this field that we need to show in our custom inspector. Since most of the fields is serialized field, then we are going to use the serialized object. So now we have declared this editor. Let's create this custom inspector. First, we need to create override. On Inspector GI, and we want to create a couple of button to create new items. Let's just comment this out here. We need to create two serials property, and the first one would be the items, and the second one would be the items name. And we need to create an unenabled method to find this property here. So for example, for the items, underscore should be s here. And for the S items, we want to find properties from our civilized object and use find property method, and then we want to search for the items array or items list. And for the items names. We want to also find the properties here. Let's check our item database. Okay, copy the Yeah, copy the fields name, to be on the safe site. Then we want to look through our items. We can look using the serialized property. We can access the array size, and it will return the members amount from our list or ray if it's another ray. Then we want to draw the item entry here. We are going to draw the item, but first we are going to create a new button here. Maybe we should create the button on top. So let's just use the I out button and then type the button name at item. And we can create actions to create an item here. We need to create a new constructor. Since all of the item is serialized field. Let's create a new constructor, type public here, item, the name class. Then we need to pass the constructor here inside the parentheses. We need an integer with which is an item ID, and then a string, and this should be the string, description, and then sprite and also I think they should do up to description or let's just create it like this first, and then we can pass the item ID to we are passing whatever value that we put it here later when we construct the item, and we pass this series field of this item ID here. Okay. And pass the name item name item name to our name parameter item description, and this will be the description. And since this have different name, we don't need this keyword here, so we can safely delete this and save this. Now we can go back to our item database editor and we can create a new item and we need to pass our item ID. For the item ID, I'm going to pass this array size because if we don't have any members, then this array size will be zero and zero is usually the first index of any kind of array data. So it suits our need and whenever we increase the array size, the item ID will also increase. For the name, we can just put an empty string and also for the description. And now once we create a new item, we need to We need to pass this item into the item list here. But since this is a serialized field, we need to create a public function. So let's just create a new function add item, and we can pass an item data for our item. And whenever we create a new item, we can add this to our list item. And then we need to pass also the item name. So just type items name, add and we can pass the item Okay, just add an anti string first. And we will change the items names as we fill out our custom inspector later. And now we can just run this method. But in order to run this method, we need to create a source. Object for our item database, create a new source object and we can initialize this on enable source and then equal target, but we need to cast this target to our object class. Inspect object class. Cast this to item database, and then we can run the item method and pass the new item that we have here. Okay. And now we need to draw an item entry. Let's just create a new method to draw this. So I'm going to call this item entry. And since we are going to pass a serialized property off from the array size, we just type here serialized property item. Okay. So now we are going to draw this using we are not going to create a property field for our item ID because our item ID will be set automatically when we construct a new item. So we want to use only a label ID to show this. Let's just create a new GI layout, and this would be a begin vertical. We want to create one box for each of the entry, and I'm going to pass a box string parameter. And at the end, I want to close this with the vertical method. Okay. Now we can safely create our interface inside this blocks of code here. The first we need to do, we are going to create an editor GI label field right away because we don't want to modify this. This will be a static inspector. We cannot change the value here, and this will We can put a text here and we can add this with our item, find property relative and get our item ID and then get its integer value. Since item ID is an integer, then we need to extract the integer value using the integer value properties. And we can set this two a very narrow UI, maybe around 75 should be enough. And this is in pixel, if it's too narrow, and it clip our information here later, we can just increase the size. I'm going to create a new UI layout in horizontal. But without the box perimeter, I want to put this item ID in the same line with our item name entry. Now I'm going to create a new editor GI layout and this time, it's going to be a property field because we want to able to rename the text area. Now we can just fine property relative and get the item name like this. But now we need to close this with a GI layout and horizontals. Otherwise, it will throw an error. Let's just create spaces between, so it's easier to read and save this. Now we have this. We can just type item three inside our loop here, and we can pass as items index of I here. Okay. Oh, sorry, not in x of, but since this is a serious property, we need to use get array element at index and pass the index inside the parenthes save this and let's go back to unity under our data script object, select the item database, we can see the custom inspector here. Basically, we have two item, I think, if we go to the buy let's just reset this two zero first for the item size and go back to normal. And if we press that item, Okay. It doesn't work. Let's check what went wrong with our code here. Once we add item, they should update. Sorry. We need to type serialized object, apply modified properties at the end of the inspector GI because we are using the serialized property here. Let's go back to unity. Okay. Let's remove this first here. Okay. And add item. Okay. Okay. Once I click Add, it actually adds, but, it shows when we press again, go to the bug. Yeah, as you can see here. It creates new entry, and it assign automatic ID, and the first one is zero and the second one is one. And if we go back to normal, it will show two entry here. As you can see, but there is an issue. Whenever we press at item, show it doesn't update the window automatically. So we need to inspect this. Okay. So after adding the serized object apply modified properties, we need to also add a seriz object update on top of our inspector GY. So any changes, it will update on the next frame. Yeah. So let's save this and go back to unity. Now if we highlight the item database here, and let's clear the member first, type zero in this item on the debug mode, go back to the normal mode, and if we press add item, it will add new items. There you go. Now we need to modify this add more entries, and since we already have this item name, we can just copy this line here and below on our horizontal, we can type the item description or I'm going to copy name here. And then I'm going to create a new begin horizontal again for grouping our sprite and the bullion total. Let's try to create our sprite first. We can create sprite using the property field here and type the name, which is the item sprite. But With this case here, if we go back to unity, it will only show our sprite as a name entry here as you can see, it's not an image type. So we can modify this instead of using the property field. We use the object field, like the one in our example, when we creating an object field for our game object field in the previous video. But here, we are going to Get the property relative from our items sprite. Then we want to access it object reference value. Then this time we want to use the object field. For the seres property, we want to grab this item sprite here. Okay, now we declare this, we need to declare a couple of argument. The first one would be a string for the label, and the second one would be the object, and we'll need to access the object reference value again. And I think I'm going to break the line here. And then after the object, we need to specify the type, which is, And for the last entry of our parameter argument, we are going to set this allows it object to fall since it's sprite. So whenever we assign sprite for our item, it should be from our asset asset folder. Save this. Now let's go back to Unity. Now, as you can see here, we can see the sprite window, and we can pick and sprite like this. The last thing we need to do is not the last thing, we need to add Bullion toggle. Inside this big horizontal, we can just copy this editor property field and pass this B field its name to the fine property relative argument here. Okay. So if we go back to you today, we can see the window. Okay. There you go. We have this items sprite and allow multiple. We want to create some sort of delete button. So let's just put it on top here. Let's create a new button. I side by side with our item name field here, just type I lay out button for the string, we are going to set this two x. So and then we want to make sure the width of our button. It's small, so just pass the width and I'm going to set the width to 25 or 20 should be enough, and we want to delete the item. Now in order to delete the item, we need to access as items here and delete the entry. First, we can access the item names and we can just use the delete array element at index of, and this would be our item ID. We can just grab this integer value. Since the item ID will always be equal as the index. And now we need to also delete this one and pass the and once we delete this, we need to recalculate the ID because if we delete the index, the rest of the object that we already created, will not change automatically the ID, so we need to create a method to recalculate this. Let's just save this here below, I'm going to create a new recalculate ID. Basically, this is quite simple. We need just to look our item cells property. And then we need to make sure that the items and get the element at index of. And once we get the index of I, we need to find the relative property, which is the item ID here, then we need to change the integer value. As you can see here, the property of our integer values can be get or set so we can change this value here. We need to change this two. Because the index will automatically shifted, but the item ID will not be automatically changed. So whenever it's shifted, we want to set the we want to set the item ID to be equal as our value or our index value. And for the items name here, we want to also updated. And sorry, since this is a less off string, we can just grab the string value right away. We don't need to use the fine property relative. And we want to set this string value here to our item name. So we can use this and we can grab the fine property relative, the item name and grab its string value. Like this. I'm going just to break this here so we can see it better in our code. Now, once we created this method here, we can just run the recalculate ID. Once we recalculate ID, we can just return this function. Once we recalculate this, we can ignore this line here and it will render the whole item entry in the next frame. Okay, let's go back to unity here and wait until it updates. Now we have this x button, and let's give it a name. This one is chicken. For example, sorry, chicken. Then let's say this is a key. This one is a gun, and this one is a chest and this one is money. If I delete this key here, You see, the gun will have item ID of one and the chess will have item two. And if I did the chess, the money will change this I automatically to here. And if we add a new item, it will create a new entry. Now with this custom editor, we can create a very nice custom editor, and we can set up our item entry and all of the item that will be available in this game or will be used in this game, we need to declare this first inside this item database. 13. 12 Base Inventory: Okay. Next, we are going to create inventory system, and this inventory system will be also a scriptable object. So let's just create a new script here inside our scripts folder under the scriptable subfolder, right click and then press create and then create a new subscript and let's just call this inventory. Open the script here, and we want to change the inheritance to scriptable object. We want to also create an asset menu we can just copy from this item database attribute here and paste this here and change this value to inventory Let's call this inventory for the menu we want to delete both of this start and update method. The first thing we want to do is we want to create a serialized field, and this will be a type of item database. Let's call this item database with lower sei. Basically, this will be the slot for accessing or reference this item database object in the inspector. Because for our inventory, we will need this item database data to create each of the items entry. All of the item entry will be based on the item in our item database here. Let's create a new serialized field also and this will be a list of item. Okay. And this will be our inventory. Okay. Now we have this inventory created. Let's save this and go back to unity. If we go back to unity, after it to finish compiling, we can go to our data folder, and then we can create a new scriptable object, create under the custom data, we have this inventory ta, and this will be our inventory. Now as you can see here, we still have the default inspector and we can add inventory over here, for example, and we can create item. But we don't want to create this manually. We want to copy the item automatically from the item database and for this case, we need to create a custom inspector for it. 14. 13 Inventory Custom Inspector: Okay, so now we are going to create a custom inspector for our inventory. So let's just create a new class script inside our script editor folder. Let's call this inventory inventory editor. And let's open this. First, we want to make sure that this inherit from our editor, but we don't have that yet because we haven't using the Unity editor name space, so we need to do that. Then type inherit from editor, and we can safely delete the start and uppit method. Now we are going to create a couple of methods. The first one would be the nenable this is for initialization. The second one would be an overwrite for inspector I this is where we draw our inspector. We can just comment this out. Okay. And let's tech the the item editor, but let's just move to this side here, so it's easier. Basically, what we want to do is we want to do quite like this. Inspector the item database editor, but a couple of things are going to be different. First, we need to open our extension. I'm going to go to our extension folder and oper our extensions. Here inside our extensions, we need to create a new public static method for copying item. Let's just do that and this will return type of item. And let's call this copy item, and we will need to insert the item and call this item. Then we are going to create a new item. Let's just call this new item. We are going to build this using the constructor here. Okay. But since the constructor only have three parameters, we need to modify this. Let's go back to our item class here. Now we need to also extend to add the sprite parameters and also the boon parameters to complete the constructor parameters. Now we can just assign this to each of the fields here. Sprite be assigned to the item sprite. And this allow multiple to be assigned to allow multiple parameter that is passed from this argument here, and save this. Now if we go back to our inventory, inventory editor, our extensions, we can bill this using the item currently, all of the object is serialized, so we cannot access it. But we can create a public or to it. Let's just do that. And basically for creating public getter, we can just create a new public field and the data type, which is integer for the item ID, and I'm going to create a new item ID, and this will have a capital in front of it. So to differentiate that this is a property and this is a variable. Inside this, I'm only want to give a getter, so I've created a curly bracket and get keyword and then here we're going to return the item ID with lower case. We want to return the item ID value here. And the next one should be a string, and this would be the item name with capital. And then we also want to only get and then return the item name item name variable value, and so forth. So for the description, we want to do that also. Return the item description. Then for this sprite, we want to create a sprite. Then we want to also call this item sprite with capital I, and then return the items with the lower case, which is the variable here. Then for the bullion, we want to also create a new get a public er, and we want to return this allow multiple variable. Now once we create this, if we go back to our extension here, we can access the item ID, but we cannot modify this. We can only get the value, we cannot set the value here. This would be safe from any unwed modification from a script for the second parameter, it should be the name. Third one should be the description, and the fourth one should be the sprite Okay. And the last one will be the multiple billion. And once we create this new item, we want to return this item. So let's just return new item. Okay. We want to create a public fight for adding item to our inventory. Okay. Just like the one in our item database here, but we want to add this item to our inventor here. Type inventory list here, and we want to do the add method and pass the item as a member and save this. Now let's create our editor here. First thing, first, we need to grab our inventory serialized field here. Let's just type serialze property, and this will be the underscored inventory. And we want to find this inventory here by accessing its serialized object and then find property and this should be search for the inventory list, and we can just copy the name here. And we need to also create the serialized for our item database. Okay. And let's just search for the item database object. Now in our inspector, we want to render this property field for our item database first let's just do that editor UI layout, property field, and we can just render this as item database. Now we need to create some loop to draw our inventory member here. We can look it's size, and then we need to draw every item entry. I think we are going to copy this method here. Let's just copy the method. But we are going to change a lot of things and we will still use the serious property item as an argument. But instead of using property field, we want to use only label field. Most of the item names value will be read only. We cannot change this value here. Let's change this to label field. Let's grab its string value. Since we know that item name is a type of string, and we can create item name. Plus this value here, just like the one we have this label field, we want to have a delete button, but we are going to change this later. Let's just set up the other properties that we need to render. Let's grab this string value. And I think we can add a label like this. Then we can make the UI lay out to have a certain hide. Let's try for 70 pixel, so we can read the description better. Now we want to draw sprite but we don't want to make it editable. We are going just to delete this all of this here. We are going to create a label that are going to show a texture. We need to create a variable. Let's just call this sprite fewer. And we are going to use the asset preview. We're going to use the asset review here and we can get asset preview and this will ask for an object, so we can grab the item, find property relative and grab the item sprite, and then we can get the object reference value. This will return the type object that we have here, which is a sprite. Once we create this variable here, we can create a I layout, label, and we can put this sprite viewer as our label. So label can show a text or it can show also a texture. This asset preview get as a preview. We'll render this sprite as a texture and it will be saved into this texture variable here, and we can render it using the layout label here. And we don't want to show the allow multiple here, but we want to render the amount, we want to make sure that this is editable, so we can just use the editor Go and this should be the property field. And we can get or we can find relative property, which is the amount. I think, let's check this amount. We want to get this. Let's just close this here and save this. We need to delete this here. And we want to delete only this inventory here. Something like this, we can delete this second line here and save this. Now, once we have this draw item entry, we can just use that method and pass our inventory by accessing the array element at index of I Now we are going to create this debugging function for adding items for the inspector. But before you do that, we need to expose a couple of field that we have on our item database and also from our items from our inventory. In this case, we need to access this item database here. I'm going to create a public getter for it. This will be a public and type will be item database, and for the name, I'm going to call this also item database with capital. And we want to get and we want to return the item database value here. Okay. And we need this because we want to access the member, especially for this we want to access this item names. Via this public ter, and we want to get this list string form. We don't want to get an object form or anything because if we use the object reference value, like this one here, if you see our sprite here, this will return an object and we need to return this as a list. That's why I expose this and we will also need to expose item names here. We need to create a public der and I've created this. As you can see here, I create a public and type list of strings with the same name, of course, but with a capital I, and then we want to only return these item names. I'm going to just lay out this. It doesn't take too much space, so let's just type this, return the items names here. Now, once we have this, we have access to our item names, we can read this from our inventory editor. One thing I forget, I forget to create a custom editor tag here, attribute, and this would be the type of our inventory class. We need to create a couple local variable inside our editor and this will be the item ID. I'm going to also create the inventory field here and this will be our source we can read this right away from our so our cilize object on our enable, we want to grab this inventory class from our target. Okay. Now once we have this access to our source here, we can check if our item database is initialized or not. So we can check this using the public error, and if it's not null, then we want to draw the inspector below. We are going to put this four loops inside of our F statement here. And we want to create a drop drop down field, and basically, we want to create an editor GY layout. We want to create the pop up for the pop up, it asks for an integer, so we want to pass this integer. For our pop up. Then if we check the other overload here, it asked for a string array. This where we are going to use the item names. Then we can access the item names together since we make this item names public inside our item database here. As you can see here. Now we have this. But since this is a list of string, we are going to convert this two array using the two method, and basically, we need to set this item ID to whatever value that we select. We need to put this item ID in front of us and then equal sign this. Whenever we change this pop up, it will assign the new item ID to our item ID. Now, another thing we need to do is we need to create a button. Okay. And let's call this item. And let's create a new item. This time, we want to use the extensions copy item that we have created. But to copy this item, we need to grab a specific item from our item let's just create a new public method. Okay. And this will return item, and let's call this get item, and we can just pass the ID here as peter. Basically, what we want to do is we want to look our items here, items do count, and we want to check the items ID if the items I items item ID properties equal to the ID that we are searching for, this ID here, then we want to return that item. Return the items I here. Else, we will return null. If the get item doesn't found the item that we're searching for, it will return type of null and we can check if the item is or not. Okay. Now we have this method here. We can go to our inventory editor, and then we can use the extensions class, we created and copy item, and then we can get the item by accessing our source item database here, and we can run the get item method here, we can pass our item ID. Basically, the item ID will be the item from our pop up that we selected, and it will save the item ID and then we can get this. Once we create this new item, we want to add this to our item. Let's just access our source, and we have this add item function and we can pass the new item to it. Okay. Let's save this before we try this. Let's run the apply modified properties from our ers object. Since we are drawing the most of the inspector. A couple of inspector, we are using property field here, so we need to make sure that we apply modified properties and on top, we need to add the update method. Let's save this. Next thing we need to do is let's go back to unity here and try this. Okay. Okay. When we change, the constructor here, there is a couple of things that we need to also change, for example, in this item database editor. Before we only have three parameter inside this line here, and if I save this, I've already changed this before, but if you save this, it will throw an error because it as for five argument instead of three arguments. In this case, I'm going to pass null for this pride and falls for the default allow multiple options for our item database editor. Once we add this, it gives no more error. Go back to unity. Now, if we highlight the item database. I'm going to check this first DD bug because we have a lot of item names here as you can see here, and we need to make sure we only have one. These item names and items should have the same member value. Let's try this if we add another item and then we delete this. As you can see, maybe those other seven entries and the entries are the leftover from our previous testing. But now if we add new item and then remove this, it will also remove our item names here. Now, if we go back to our inventory here, we have this pop up. This is the pop up. For example, if I create another item and let's call this key here and just add description some key for opening certain locks. Or type A K and a big size chicken meat for the chicken description. And for the key, let's just add a check mark. Now, if we go to our inventory system here, we will let's just refresh this. Let's just browse the item database again. Okay. There is a small issue with our item database here. Whenever we add a new object here for the key here, if we go to debug mode, as you can see here, it adds an item names, but it doesn't save our key because this item names gets created when we add a new item and then after we add we are setting the name for the item name here. Whenever we change the GI, we need to also update this item names here. It's quite easy to fix this. We can just go to our items database editor here. And here below our four loop here, we can create a statement, and in the editor, we have the GI class and we can check if change return if any controls, change the value of input Data. It checks for any changes in the inspector, and if there are any changes, then we want to recalculate the ID. We run this recalculate ID because basically this recalculate ID refreshing the ID and also refreshing the items name here, as you can see. Once we recalculate this ID here, if we go back to unity and go to our debug mode here, You see, we have this empty element. But if we go back to normal and let's say I delete this and I retype this to key, and if we go to the debug mode, you can see that we have the key saved. Once we have this modified this fix, we can go to our inventory here, and if we browse, we have two items. We can add chicken and we can add the key item. And this pop up and this button for adding items is going to be used for the bugging or if we want to create a couple of items that should be already inside our inventory from the start of the game, then we need to add this and the other items will get added some item will be removed if our player gives some item later. We will create an action for that. This is for the inventory inspector. Now we can just delete this and for the key, we are drawing the amount here. Let's check this. Oh, there is one thing we need to fix because we have disabled this allow multiple here as you can see, but in our inventory, the options for amount is shown. We need to make sure that doesn't happen. Let's go back to official Studio here in our inventory editor. We can check its value here. If the item find property relative, and get the allow multiple. Ban here and gets its ban value b value like this. If it's true, then we want to draw this amount property field here. Otherwise, if it's fall, then we don't want to draw this. Let's go back to our unity and now it won't render the amount. But for example, if I change the chicken to a low multiple and then go back to inventory here, Let's remove this and draw this again. As you can see here, we have this amount. If I add the key here, then we have this object without the amount field here. This amount will get rendered depends on the options, if this is enabled or disabled inside our item database. Basically, we are going to define the item database here, the name, the description, the sprites, and the possibility to have multiple or not, and in the inventory, we can change how many amounts that we have currently. There is a small bug in the inventory editor here, when we try to delete the entry, it will try to delete the entry based on its item ID. Since the order of the item in our inventory lease won't be the same of item ID because the item ID will be the order of the item in the item database. In order to fix this, we are going to modify the draw item entry in the inventory editor and create a new argument or parameter, and let's just type the type, which is integer, and we can just call this ID. Then whenever we want to delete that item, instead of finding the item ID, we need to pass this ID here, when we look through the inventory list of items and row the item entry, we need to pass in the I value here, the iterator. Let's just type I and save this and this should fix the issue. 15. 14 Basic Data Manager: Okay. So now we are going to create a manager, and for this manager, it will do it will do mostly holding our player inventory that scriptable object. And this manager will be a Singleton so it can be accessed from anywhere or from any other script. And this manager will also handles and safe load, and we will going to do that later. Now here, I've opened our scene here and let's create a new folder. And let's call this folder manager. Okay. And inside this manager folder, let's create a new C sharp script, and let's call this data manager. And we are going to open this manager script. Now we have this de manager open. First, we need to declare a static reference to this class here. Let's create a new public properties, public static and for the type, it should be our Datager itself. Let's call this instance with capital and open the brackets to define our getter and tear. We can get public and we can privately set this. In order for this singleton to work, we need to create a awake method. It gets initialized before any other script or any other start method in other script gets executed. We want to check first if instance is equal null or if no other object already used this instance keyword, then we want to grab that. We can set instance to this class here, this object and we want to don't unload this game object. Okay. But else or if the incident is not in this condition here, then we want you to destroy this one, destroy game on. This is how we create a single ton and this will make sure that our object here, this data manager or the game object that holds this class here will stay throughout the scenes. If we put data manager in the scene one and also another one in the s the one in the s will get destroyed automatically if the data manager from SN one already exists and persists when we transition to another scene. Save the script, I'm going to delete our start and update method. And We are going to expand this da manager further in the later videos, but right now we need to create a series field, and this would be our inventory. Let's just type the class here inventory, which is our script object fields here and we're going to put our inventory in this field here, and let's just call this inventory. But we want to create a public getter. Let's just create a new one here, public type inventory as the class here. Let's call this inventory with capital since it's a property. And we want to get and we want to return our inventory field here, this one. Ascrip can access this inventory, but can only get its value. It cannot change its value here. It cannot set its value. Let's save this and let's go to unity and let's set up our data manager. Let's create a new empty game object. Let's call this anti game object data manager. Let's rename this. I'm going to reset its value, it sets 20000. It doesn't have to be on the center of the world, but I like it this way. Let's save this and then drag our deaminator script here. If we drag our deaminator as you can see here, we have our inventory slot and if we go to our data folder, we can drag our inventory to the slot here. Okay. So now we have access to this inventory from any other script. And in the next video, we are going to create the item action, so we can remove or we can add item during runtime. So for example, another NPC as for an item or another NPC gives an item. We can use that item action to add or remove some item from our inventory. 16. 15 Item Action: Now we are going to create the item action, and we should create this class inside our actions folder. And this item actions will functioning as a class that can give or receive items on run time. Let's just create a new Cb script, and let's call this item actions. We are going to create the base structure of this class first. Basically, this class should be derived from the actions class. And since the action class implements act abstract method, we need to also implement this. Let's just implement with is Studio, you can automatically implement this. I'm going to just to cut this and put it here. We won't be needing the start function too so we can safely delete that I'm going to remove this throw new system not implemented and We need to create a couple of fields here and most of them should be sterilized field since we only want to change the value from our inspector. This would be our item database and call this item database. We want to also create a new bulon Maybe we can call this item and this will decide whether we are giving or receiving the item. Another one would be our actions, depending on true or false. So let's just create new actions, and this would be the Yes, actions, and no action. Oh, sorry, I think that should be an array, so we can run a multiple action, last one, we need to create a private item and this will be our current item. Whatever item we pick will be safe in this current item, and we are going to use this item data to compare whether the user are going to give this item or not. Basically inside, we are going to check if g give item is true. Then give the item else receive the item. This is the basic condition and inside giving, we need to check if we own the item, and also if the item are multiple or if the item has the allow multiple option or not. And if it does have the multiple option or not, check how many items needed. And we can create here L give and remove the items. Here we can add give and substract item. This is the basic structure of our condition and we are going to extend this later. But first, we need to create the editor for this item action script. So we are going to create that on the next video. 17. 16 Item Action Inspector: Now, let's create our item action editor. Go to our editor folder under our scripts, and then let's create a new HR script, and let's call this item action editor. Let's open this. Once we open this, I'm going to search for our item actions, and I'm going to put it besides the item action editor. It's easy for us to switch between this class here. For the item action editor, we want to make sure that it's using the unity editor namespace, and we want to derive this from our editor. We want to also make sure that we are giving an attribute custom editor and set the inspected item, which is the item actions here. Okay. And we can just remove the start and update method. Okay. And we need to create erz property for our field here. Let's just save this and then create a new item actions class first. This is for the source object that of course we are going to need this. We need to create a couple of seriz property. Basically, this would be the item database. I'm going to as usual, for the seriz property. I'm adding the underscore prefix and this will be the item database. And this would be the gift item, and this would be the actions and the underscore, no actions. Language to add this at a S at the end. We know that this is an array. It's for plural. Now we can create for enable and also an overwrite for our inspector GY. Let's just delete this based on in y. Now we need to find for each of this property and also initialize the source here. For the source, as usual, we can just type the keyword and then equal target, but we need to cast this target into the item action. Just type the class name here. Then for the serialized property, we can just assign one by one by assigning the serialized object, lower case, and then using the fine property, and we can just search for the item database field. And we can just copy the name if you are not sure and then paste it inside the string argument. And for the next should be the gift item and just find the give item field. And for the actions, we are going to find the actions and the same goes with our no action. Now we have created all of this serialized property. We can start draw this serialized property. First, we need to make sure that we update if there are any changes, and then we need to apply any modified properties at the end, and we will create the code between these two lines here. The first one, we want to render this item database. Let's just type an editor I layout, and this will be the property field here, and we can just pass the item database, and then we can add a new I content with the string, and let's call this item database. And then end it with semicolon. The next one would be our billion. I'm going to just to copy this, paste this below here, and pass, past the as give item variable, this would be we would label this give item. And for the actions, for now, we want just to draw the property field, but later, we are going to create a custom drawer. Pass the serialized property and also the serialized, the actions. And this will be D. Yes. And this will be the no action. Okay. Save this. Now if we go back to our two unit here, I'm going to create a new empty game object debug our item ed here. Let's just create a new empty game object. Let's just call this item action debug. Let's add our item actions class to this game object here. There you go, we have this custom inspector, but it looks like just the default because we are not using the UI layout, begin horizontal or begin vertical or creating a box between entries here. It's okay. We have this. For the yes and no actions, I think we need to pass we have this over we need to pass a true value to include the children. It will draw the array window here. If we go back to unity, we will see that now it draws the array. But we will create a custom editor for this action. Don't worry. For now, just for testing out and we want to be able to pick a database. Once we pick a database, we want to show a pop up or in field just like the one we have in the inventory to pick the selected item that we want to set as the item to give or to receive. Now let's continue. For the item action here, we want to copy whatever item database that we pick to the current item. Now we are going to create a new integer and this for keep track of our item ID, and it will be type of integer. Let's just call this item ID. Now let's go to our item actions editor. Here, we want to create some sort of a pop up. Between this give item and the actions, we want to draw the item entry. In order to draw this item entry, we can safely copy the method from our inventory editor, draw item entry, select all of this. Then copy this and we can paste this to our item action editor. Here, let's just paste this code here. And we don't want this delete button. So we can just remove this eight method because we can we don't want to delete any item from our item access. We only want to change whenever we change the item pick using the pop up. Here we can just throw the pop up or for selecting items. Now let's do that. Since we already create this item ID, we can just access this using the source and then access this item ID, then set the equal and we are going to create a pop up and for this pop up, we are going to pass this source item ID. Value, and we want to display an array of string. For the second overload here, we want to show the display options using a array of string, and this will be the item names from our item database. Let's check that. Go to our item database here. We have this item names and we can get its item names. So in our item actions, we can create some capsulation by creating a new properties, and this will be the time of item database. Let's call this item database with capital I. We want to make sure that we can only get its values we want to return the item database field that we created on top here, but we only want to get this. Doesn't want to set this now we can just grab from our source and then grab the item database and get its items name. This is a list so we need to convert this to array like this. Save this. Now if we go to unit here, you'll see that we have this pop up below our item abase. We can access between chicken and key. So far, good. Now let's draw the item entry. Now we want to make sure that we want to draw this GI or the custom editor whenever we already pick a item database. We want to make sure that if the item database is not new, then we want to draw all of the code here below here. Let's just cut this and paste this here. Now we can draw the item using the draw item entry and we can pass the item that we have from our item database. Let's just grab this as item database and get the array element at index of our source item ID like this. Now we want to Whenever we change this value here, we want to fill this private current item. Let's just create a public method to change item, public void, change item, and we want to pass an item. Whenever we change this item, we want to set the current item to our pass item or we want to copy this. We want to use this extension copy item and pass the item here, save this. And we want to make sure that we can only do this if our item database is not T, not. We want to also check if our current item ID is equal to the item, the item ID that this item we pass here have. If it's equal, then we are basically selecting the same item, so we don't need to change the items. So just execute return, so it will skip the code below. Once we have this public method here, we can save this and we can make sure if the I changed, then we want to run the source change item, and we want to pass the item that currently we are changing. Basically, we can grab this item database and get the array element index, and we can I think it's object reference value, this one, but I think we can just grab this property here. And then we can pass the item using the get item and pass the source item ID. Let's check our get item method here inside our item database. Get item, it will return our items using the item ID, we can just use that, save this. Since the source item ID, it doesn't using the property field or it doesn't using the serialized object. I want to mark any changes here. We can just use the editor utility, and we can run the set dirty and we can just pass the source object like this and save this. Now let's test this out, see if it's working or not, go back to unity, and I'm going to save the scene first. Now we have this. But there is an error, as you can see, there is a unexpected layout group error. Let's just check this out. There is a mistake on my end and upon drawing the item entry. We need to draw not the item from our item database, but the copy it item from our current item. Since the current item is private, then we don't have access to this. I'm going to create a public inspector instead, I'm going to change this basically to a public item, but this will be with capital since this will be a properties. I'm going to get allow script to get this value, but I want to set a private set. Now we have this and I'm going to compete this and change this keyword here using the capital C one that we modified here. We want to set this via this method, but we want to able to get the value. Another thing we are going to create is we want to create a real field amount. And this amount, it will be how many amount that we are going to receive or we are going to give. We can set this on the inspector later. We aren't going to use this amount here because this integer amount on our item, this would serve a purpose to keep tracking amount items that we have in our inventory. And this is the item action, so it's different. This is the amount or the amount or the receiving amount when we finish running this item actions. So now we can just access our source object and get the current item. But here we have an error because the draw item entry is asking for serialized property. We can just change this to item class of item, and this will work. Now we need to modify this. It's okay. We can just grab the ID, and we have the properties for each of this here. Let's just delete this and then grab the name. For the description, I'm going to delete all of this value here and grab our item description. For the sprite viewer, we are going to grab the item sprite right away. So we can get these items right. For the allow multiple, we can just get the allow multiple properties. And on this is true, then we want to draw our the integer on our serialized field here. Now we need to get a reference to it. I create a entry first on our serials property here, and then we can just search for it by accessing the serialized object, find property, and then type the variable name, which is amount. Now we can just draw that serials property. And save this. Another thing we need to do is we need to mark the scene also dirty upon changes. Let's just do that to mark the scene dirty, we need to using the Unity editor scene management name space. Then we can I think it's the scene manager, Mark dirty to the scene here. We can grab the source. What's wrong with my keyboard here. Now, source the game object, we can grab the scene of the scene where this game object is a part of the game object recite we want to mark that. Whenever we change the value, it will add asserc sign on our scene name so we can save it and those changes will get safe in our scene. Let's go back to unity here and let the script compile here. Now if I select the item action debug here, and let's select the chicken object. Now, it works, as you can see here. If I select chicken, then it asks for an amount and it shows the object that we want to interact, whether we are going to give or receive this item. If it changed the key, it change also the value since the key is not allowed multiple items, then we don't have this amount option. This is basically for our item actions. Later, we are going to create a custom drawer for our actions, so we can create a better representation for our actions and easier modification for adding and removing the member of these actions here. Now, let's create this custom inspector for our actions. In order to do that, we need to create extensions for our editor. I'm going to go to our extensions folder and I'm going to create an editor folder inside this extension. Now inside this editor, let's create a new CHF script, and let's call this editor extensions. Let's open the script. We are going to remove the mono behavior and we want to use the Unity editor namespace, and we want to make sure that this classes static, so it can be accessible from anywhere from any script. Now, let's create a new public static void and this will be our draw actions array. We want to pass the serialized property for the array. Save this. Now we want to create a GI layout and this will be the begin vertical and we want to mark this argument with box. It creates a box, and we want to end this with the vertical. We want to also create a label. But we want to create a custom level that we can pass through this function. Let's just create another argument, which is a string and just call this label. Then we can pass this label parameter inside our label field here. First, we want to check if our array size is equal zero, then we want to create a button. Let's just create a button here, and label this button at actions. Whenever we add actions, we want to insert an element to the array using this function, insert array element at index, and if it's zero, then we should insert at zero. Here, we want to look through our array size. We can just type the array size here. Inside this four loop, we want to create a new G layout, and this would be a horizontal, begin horizontal, and we want to close this with a horizontal. Like this. Now we are going to draw the properties field. Let's just use the layout and property field. We want to draw this array using the array element at index of, and we want to set the content to none, so it doesn't draw anything as a label or stuff. And we want to add a delete button. Just use the GI lay out class and button, and then for the deleting button, we can just simply use the x character, and if it's pressed, then we want to delete the array. I think we have this delete array element at index of and we want to make sure that if our i is equal to the array array size minus subtracted one. This means that if we are at the end of the array or less member of the array, then we want to add a plus button. Let's just copy this code here, paste this here and set this two plus or positive sign. Then we want to insert array element at x of i. Index of I but our array size. Since we are at size negative one, then we want to get the array size. It will insert a new member after our index, after our last index, so it will create new entry. For each of this button, we want to make sure that it only has a width, a small width. I've tested it before and 20 pixel seems to works great with it. I'm going to copy this and then add a parameter also to the positive sign and then save this. Now we have this editor extension script. We can go to our item actions editor here, we can draw the actions. Instead of using this, we can just type our editor extensions and then draw the actions array, and we can pass this serialized array, which is the S actions. Then for the label, we can just grab this. Okay and then close it with copy this line here. I'm going to paste this here. This will be for the no action, and rename this no actions. For this old code here, just comment this moment and later. If we want to, we can just delete this. We have saved this and let's go back to unity. It's still compiling. After it's compile, let's go to our item action debug and now we have this. Yes, actions and no actions. If we delete this, it looks like this. If we don't have any member in this actions array, we need to add actions first. Once we have actions, it will create a new actions, and it will have this plus pattern to add another one. We can just plus this. The last one, the last the last member actions will have this plus icon to add more icons. To delete this, we can just safely delete this by pressing the pattern. This will certainly makes setting up our scenes, our actions quite easily. I did the draw actions array on editor extensions on purpose. Later, we can use this method to draw a custom actions array field on another class easily. 18. 17 Item Action Continued: Okay. Now we are going to continue our item actions, and if we open our item actions script. As you can see here, we haven't really defined the act function over here. Now we need to create this. In order for this method to work, we need to create a couple method inside our inventory, and we are going to do that in this video. Now, let's just start creating code inside here. First, we are going to check if the gift item is true, then we are going to give item from our inventory. Let's just copy this comment here. Cut this and put it inside and we want to make sure that the inventation is right and else is for receiving. In this blocks of code here, we are going to receive the item. First, we need to check if we own the item and in order to do this, we need to create a custom method. Let's go to our inventory and we can create a new public and this will return integer. We can just name this check amount for the item to be check, we need to pass the item that we are going to check. First, we are going to look through our inventory and check if the item in the current loop have the same ID as our item that is being checked at, then we want to return the amount. Let's just look through our inventory list. Since this is a list, we are going to access its count, and we want to check if inventory index of the item ID is equal to the item item ID that we are currently passing here as a parameter. Then, first, we want to check if the item in inventory index of Alow multiple bullion is true. We want to return the amount value. But we need to expose the amount from the item. Let's go to our item database here. Items the item. Go to the definition and open this and we need to create a public integer and this will be the amount with capital A, since it's a property, then we want to return the amount value here. Save this and we can close the item. Now we want to return the inventory index of amount. Else. If we do have, but this allow multiple flag is false. Then we want to return one. Since object that doesn't have this enabled, we can only have one in our inventory, so we can safely return one. If we don't find the item, the item that has equal item ID, it means we doesn't have that item. We can just safely return zero at the end here. Basically, if it's more than zero, we do have that item and if it's zero, then we don't have that item. Let's go to our item actions. Now we can access our inventory from our dinger access our single t here, instance and inventory, and we can run the method that we just created, check amount for the item that we want to check is our current item. This one here, let's copy this. Once we paste this, it returns an integer. Here, we need to make sure it's greater than zero. If it's greater than zero, it means that we have this item. If it's greater than zero, then we want to check if the item has the allow multiple option check. Let's just check from our current item. If it's low multiple, then we want to check the amount that we have current item that amount is less or equal than our item that we have inside here. Since this will return the integer, how many items that we have, if the current item amount we need to give is less or equal than the one that we have in our inventory, then we want to pass that. Pass the item L. We don't have enough or simply don't have the item. It can be not enough or it can be that we don't have any of those items and we need to create another LF. This is for if the item doesn't low multiple, then we need to make sure that the item that we have is at least equal one. It means that we have this one. But to make things simple, I think we can just create an integer called item owned, and we can pass this method to this item own here. Then after that, we can just only compare this item on and we can replace this, it's much easier, and of course, it's faster because we already the result of this method already being cash into this variable, it should be faster. And pace this. So to reiterate the conditions. First, if the current item inspected has its allow multiple bull to true and currently we have more than needed or asked, then we want to give the item. And if the current item allow multiple bull is false, and currently we have one, then we want to remove the item from the inventory. And then invoke actions. And for this, so we want to do that. Invoke actions. Now we need to modify our inventory. We'll need to add more methods inside this class here. Let's just create a new and this will be a type of void and remove item and the first type will be the item, and the second one would be the amount integer amount, we will set default to one, it will default amount of one. Now inside our remove item, we can just our inventory. Look our inventory count. Then we can check if we do have the item with the same ID. As our item ID here that we pass as a parameter, and we want to remove that. Basically, what we want to do is if inventory has the allow multiple flag enabled, then we want to remove the amount. Let's just grab the item from inventory. But in order to remove this, we need to create a method to subtract the amount, let's go back to our item. Let's just open this again. And we can just create a new public void, reduce amount with the value here that we have here or we can just name this modified amount, which sounds better we can add or we can reduce. Basically, what we want to do is we want to set the amount to be added with our value here. Okay, let's go back to our inventory here. Now, if it's allowed, then we want to modify the amount by negative amount that we use here. And if we don't allow multiple, then we want to just remove the item from our inventory. Remove at and using the index of. Just remove the item from our inventory list. Here, we want to check if inventory amount less or equal and zero, then we want to also remove this. Let's just remove from our inventory. Here. Let's save this and let's go back to our item actions. Here we want to run the remove item method. Let's just access atature instance, inventory. Then we just remove item and we can pass the current item. For this case, actually, I create a mistake here, as you can see here. The one we want to check is not the current item amount, but this amount we are setting up in our SLS field. Let's just change that. Amount. Yeah, this should do and we can just pass the amount here. It will remove our item, and if we can copy this here, and then we want to remove also. But this time we don't need to pass the amount value here, just pass the current item. Since we are successfully giving our item, we want to execute the actions. We are going to create a method in order to execute all of the method inside our actions or actions array. If we don't have the item, then we want to execute the no actions. We can just remove these nodes here. Since we are going to use a lot of actions array. I think it's best if we put this method inside our extension class here. Let's go back to UT. I'm going to open our extension folder and open the extensions class. Here, just create a new public static void and run actions and pass the actions array as the actions, and then open this and then look through our actions length. And then we can just access the actions index of i and then run the method like this. Once we have created this, we can use this inside our item actions here, for example, we can just access our extensions class, and then we can run actions, and then we can pass the actions like this. Same goes with our second condition here, and for the last one, we want to run the no action. Save our script, and this is basically done for the give item and for the other condition, we should receive it. Basically for the receive item, there can only be two. First, we need to check if current item low multiple. Then if it's low multiple, we want to modify. Do we have the modified amount or we can just change this to modify item amount and think we don't need a default value here. Like this. I think we can just go back to our item actions, and this will throw an error because we modify the method, change this to modify item amount, and this is also to modify item. But this will throw an error because we need the item amount. We can just remove using the item on integer because if we don't low multiple, then the item on would be one, so we can just pass negative item amount. Now we can use this method to also add our item. Let's just Okay. Now, let's just add a return statement here. Whenever we found the item that has a matching item ID that we do whatever we need to do here and we return it. And here below, we can just add another code, which we're going to add the item. We need to copy the item first. Let's just copy it. And item class item new item, and then using the extensions, we want to copy item and the item that we want to copy is basically the item that we pass here, and then we want to add this inventory add item or we can just run this add item. It's better this way. We add this item here, not the item, but the new item. Then we also want to add the amount, how many amounts that we are going to add. Maybe before adding this new item, we can modify the new item. Modify amount and then we set this value to the amount that we passed as a parameter, and then once we set up the new item here, then we add this new item to our inventory. Yes. Let's go back to our item actions, and now if it's a low multiple, then we can just pass and pass the amount. Let me want to add and If we don't low multiple, there will be two conditions here if we already own the item. So let's just using the check amount again. If it's equal one, it means that we already have this, then we want to already have and we can execute the actions, and we want to add this, we want to add the item. Let's just use the modify mon, and we want to add just one. Then if I succeeded, then we want to run the actions. For the one on top, we also want to run the succeeded actions. Now we have to sort out. Let's test this out, see if it's working or not. Let's go back to unity. Let's test this out and for the item action debug, or we can just disable this thing here, and for the NPC. Let's just create a new PC by duplicating this one. And on our scene editor, disabled Judy Togo here, go to our object. Let's move this to somewhere here. Now we can just remove the message action. All of the message action here, remove. Now let's add the item action. And get the database. There is an error here. I found the issue and it's quite easy to fix this. Instead of checking if our property field here, the item database or the seized property is null, we can just check the item database, the properties that we expose in our source class. If it's not null, then we want to do all of the remaining actions, and we are going to copy this here and when we change anything inside our GI, this will get executed. If the item database is still null, then this will throw an error because we are trying to access the item database. Let's just create a flag here. To make sure that if the nata base is not null, then we want to change the item. Otherwise, we want to only mark the editor utility and the C manager to dirty. Save this and let's go back to Unity. Now if I press our NPC here, we can browse our eatase. Click and now we have this. Perhaps we ask for a chicken. And press give item and then create two message items. This is the first one and the other one is the second one and increase the message size to one, so we can create two different messages and say thanks and say, you don't have enough. For the yes and no, we can just pass this first message, four tanks and the second one for, you don't have enough. We can test against key here for chicken test against chicken. Let's say it as for two items for two chickens, then we can try to open our inventory here. Here, we only have zero chicken. Let's is two one. Let's try test this out. Let's go to NPC, the second one here. There is an error. There is a slight error on my end and I apologize for that. But here, as you can see here, if we run the play button, it will throw an error with our item actions. I found the issues. Basically the issues are if I go to the b here, for example, We have this current item with the idea of chicken and stuff description. And if we play this, it will reset two and empty item. That is an error here. And since we are on the bug, this doesn't shrow an error. But if we go back to our normal, this should throw an error, as you can see here. So We can easily fix this. Let's go to our item actions. Now, basically, we are using a property and property is not serialized, and that's why this was causing an issue. We can simply fix this by creating a public field, but I want to recommend that because if we create a public field, we might accidentally change those value from other script. So I'm going just to create a new serialized field. And this will be the item and with a smaller C item. This is a new field, but we are not going to draw a field for this serious field here, but we want to only for holding data, and this is basically what we want to do. We want to set the gap to return this current item that we just created. Now we have this, this will draw an error. Because we cannot assign value to the properties again, we're going to copy this current item field, the serious field and paste here. Whenever we change this, we want to change this seriz field. The rest should be the same. Hi. This is rooming from the future. I got a bug reported by Dario Munez. Thank you so much for spotting this issue. Basically, we need to create a slight modification on the inventory script and also on the item action script. First, on the inventory script, the changes that we need to create is here. Under the modified item amount. We need to add a bullion parameter to decide whether we want to give or we want to receive the item. So here I'm going to declare a bullion here, and let's just call this gift, and I'm going to assign a default value. So we don't need to change all of the other object that don't need this bullion value to be true. So it will set default to false. But if we need to give the item, then we can set the bulon to true whenever we are using this method. So here inside the modified amount line here, we can check if the gift is true and I'm going to use a ternary operator, and if this value is true, then we want to subtract based on the amount. But if it's false, then we want to add based on the amount value. Okay. So this is basically we'll tell the code here if this value is true, then substract by the amount value. But if this falls, then we want to add by the positive amount value. And here, whenever we remove the item, we want to make sure that if the amount is less than zero, and if we are giving the item. So we need to check if the gift bullion is true. Otherwise, we don't need to check this because we are going to receive the item, so we will never run out of items if we're receiving the items. And the next one would be on the item actions script. So if we scroll down here. Okay. Under the give this part here, we need to modify the code here. Whenever we are using the modify item method that we have just modified before. We need to pass the true value. So the method we know that we are releasing the item or we are removing the item. And here, I'm going to also add the boolean value true here. Here, I forgot to remove the negative sign, but please remove it on your code. Otherwise, it will reverse the result from modify amount method on the inventory. And for the rest of the code here, we don't need to change anything because this will default the gift value to false. Okay. So yeah, that is the fix that we need to do. And thank you again, Dario for spotting the issue. Okay. Let's go back to it. Now, let's script compile. Once it compile, I'm going to change key and chicken, basically, this PC will ask for che chicken and if we have those items, it will say tanks, but if we don't have this much amount of the chicken or if we don't have the item, it will say, you don't have enough. Let's go to the inventory. We have only one chicken. Let's run this and let's click on the NPC, and it will tell us that you don't have enough. If we change this value to three, for example, and then let's go to that NPC again. I will say tanks and our amount will be subtracted two one. It will be subtracted by two because this PC as for two items, as you can see here. This is basically works. Now if we try to as for key and since key doesn't have the amount allow multiple added. Let's just check this and play this. Now if we go to this NPC, it should delete this entry. As you can see, thanks, it gives our key and we don't have that key anymore. Now let's test if we have a multiple item, for example, chicken again and it as for che chicken, and then we set the amount to. Let's play this and see if our chicken gets removed from our inventory. Yeah, there you go. So we have test all of the conditions and basically, it works, and now we have a working item actions, and we are going to need to create a couple more different actions after this video. Okay. 19. 18 Message Actions Inspector: Okay. So we already created the custom inspector for our item actions. And now we want to create a custom inspector for our message actions also, so it's much easier to manage like this actions here. We have this custom drawer. Let's just go to our editor folder and let's create the new Ccript let's call this message action editor. And let's open up. Once we open this, as usual, when we are going to create a editor script, we need to use the Unity editor namespace and we should make sure the class derived from the editor class. We want to also add a tag custom editor tag and then set the type using the type of keyword and then the base class that we want to modify, which is our message action. Let's save this and just delete this two method. Now if we reopen our message action, we can just go to definition and then keep it open here. We can see that we have a list of messages string. A bullion enable dialogue, string for yes and no text, and then list actions for our yes and no actions. If we are using the enable dialogue option. So let's just open our message actions editor, and then we are going to create a serialized property for most of those fields here. Let's just check. Okay. The first one should be our messages. The second one will be our enable dialogue. Third one would be the tax, and then the no tax, and then the action. And then the actions. Now once we've created all of this here, let's just grab each of those erized property here inside our own enable. For the messages, we are going to grab from our erzed object, and then we can easily find properties using the string values, which is the messages. Oh, message without second one, it should be ale in total and this would be the enable dialogue. And I think it is called enable dial. I'm not sure. Just copy it. Okay. Yeah. That's correct. And the third one, we can just copy this line here and then change its its member. So its name. This is for the text, this is for the no text. This is for the S action. Okay. Then this is for the action we don't have no action yet, so we need to paste another line and then copy the no actions name. Now, let's check the name. We can safely type the name. This is not test tax, and this is the no tax, and this should be the yes actions, and this is the actions. Once we have this initialized, we can start drawing our inspector GY. Okay. Let's comment this out sir first. And then I'm going to make sure that we are updating if there are any changes, and at the end of the unexpected GI, we are applying any modified properties. Okay. So now, first, we need to look to our message list. If there are none, show a message, first we can show a message, and then look through our message list and then show enable dialogue Tgle enabled, then show the dialogue properties. Okay. Okay. So now for drawing our message list, we can simply create a new method, and let's just call this draw messages entry, and then we can pass our serialized property, and this should be the message array. Oh, no, sorry, message entry. Because we are going to look this inside our uninspected UI, and now we need to create a button first. So let's just create a new UI layout button. And then add message. Okay. And whenever we're adding a message, then we want to insert a new array element at index of its size. So we can just grab the S message that array size. And we are going to look through our messages size here. Let's just look through the array size, and then we want to draw the message entry, and we want to pass the message member at index of I. Now we have this. We want to draw the message entry. Since we know that message is a list of string, then we can easily draw the field editor GI layout and dro property field, and we can draw the message entry. For the I layout option, I think we can create a string label, and we can draw a new content and pass the label value here. We can also make the width using the with the height to around let's say 50 pixels, it's quite big. It's easier to write a long messages or long dialogue. In the inspector, and then we need to pass the string here message, and we can add the i plus one string. If it's zero, then it will be message one and if it's one, it will be message two, so we can see the order of the message. Save this and think for every message entry, we want to create a layer layer and we want to begin vertical. And we want to create a box. And then we want to close this with the vertical, and let's save this now. Once we save this, let's go back to our let's go back to unity and check how does it render this message actions once it's compiled. Now as you can see here, we have this message, good day, sir, and the officer good day to you two. But we want to create button on the right side on each of the message. In order to do that, we can just pass an integer After the label, we can pass an integer ID, and after the label here, we can pass the. Now we can create a G layout begin horizontal because we want to set the button side by side with our property field here. Here we can just close it using the horizontal. Before we closing it, we want to draw the button. Let's just create G layout button, and set this x character, delete, and then we can set the width the width to around 20 pixel. So it's it's quite small. The button should be small and then here we want to oh sorry, the layout should be reside inside the button argument here like this. Now we can just delete the S from our messages, and then the delete element index of ID here because we already passed the index on our loop. So let's just save this. Okay. Now if we go back to unity, we can see we have this delete button and I'm going to save the scene first, whenever we delete this button here, it will delete and if we create message, it will create new message here. We can just change this. We can just undo this. Save the scene. Now we have a very nice custom inspector for our message actions. Now we need to define this part here, show enable the go. Right now we can just Create a GI layout and begin vertical, I guess box here, and then we want to close it. Becomes a group. Then here we want to draw the property field of our enabled dialogue. We can just this enable dialogue. Then we want to pass a text here using the new I content class, and the text will be the enable dialogue. Ks and we want to we want to get this value here. If enable dialogue b value is true, we don't need to put anything else because this means it's true, and if we use exclamation means it's false, shorthand version of checking whether the bully value is true or not, then we want to the properties here. Let's just copy this here. And I think, make it twice and make the layout smaller, the smaller, and for the level, this would be the button label, and this will be the button label, and we want to draw the text and the text. Underscore text. And for the text and the no text. In between, we want to draw the action. Now, we already created this editor extensions, how to draw an array. We can just use that. Let's use our editor extensions and then draw actions array. Then we can pass the action. Once we created this here because this method is going to be used by a lot of classes that implement actions array. That's why I put this in editor extensions. And we can just pass a new UI content for the label, and then we can just type this actions. Close this. Oh, the content. We only need to pass a string value, so this here because we declare it using a string label, and it will draw the label automatically, and then copy this paste this below the button, no text here, and pass the as no actions. The thing is that with this bully and checking, we will only show these options if the designer or we choose to enable the naval dialogue using this property field here. Let's just save this message actions editor and let's check how it looks in unity, go back to our unity. Once it's compile, it should have a here as you can see here. It has the enable dialogue options. If we disable this, then it will not draw the dialogue again. As you can see here, it's empty because we haven't declare the actions and the label for this one here, but this one is empty because we already set this before. That is pretty much how we create the message actions editor. Okay. 20. 19 Activate Actions: Okay. Now we are going to create a new actions and this will be the game object actions. Let's create a new C subscript under our scripts folder and the action subfolder. Let's call this script activate game action. Or we can just call it this activate actions. Much shorter, and let's open this up and we want to make this class derived from the actions class. We want to implement the abstract class, and we can just put it here. Okay. Let's just little line here. For this class, we want to create a custom class to hold our specific data for activate actions fields here. Let's just create a new public class below here. Let's call this custom game object. We need to mark this class to serializable. Let's just do that. And we can open the class. Inside this class, we want to create two new serials field, and this first one would be a type of game object. I think we can call this GO game object. For the second one, we want to create a bulon this will be the active status. Now we've created this. We want to create a public getter. Let's just create that. I'm going to rename this to a smaller case GO. And I'm going to create a new public getter for our GO game object and we want to get and we want to return the GO value. And for the bullion, we want to also create a bullion getter, let's call this active status, and we want to return the ban value. Something like that. Now let's create a new serialized field here, and this would be a type of list, the custom game object that we have just created below. Then we want to call this custom game objects and initialize it. Then here for the action, we want to look through our custom game object members. Okay. And each of these loops here, we want to activate the GO, the game object, the public getter, we want to set active. Based on it, active status. Let's just grab the accessor here and find the active status, equals, but the active status. Okay. Now we have this script created. Let's create a custom inspector for the script. Let's go to our editor and create a new CSO script. Let's call this activate action editor. Let's open this newly created editor script. First, we need to import the Unity editor and also make sure it derived from the editor based class and add a custom editor text on top of it, attribute and pass the type inside this parentheses and access the activate actions. I'm going to move my script to be side by side with its editor class. Once we created this, we can safely delete this and now we need access to our sterilized field, but serialized property to our custom GO list. Now we have created this serialized property. Let's create a new unenable function and let's search for it for the erilized property by accessing its erized object and then find property, and we can just copy its name here, and paste this here. Now we need to create a new override method, which is our uninspected UI. Let's just delete this base on inspector I. I want to create a custom method should row our custom object fields. We can just pass the serialized property here. Call it custom list and save this first. Let's look through its member, since this is a sized property, we need to access it array size. For every member, I'm going to divide it using a begin vertical method and add a box parameter to it, it will draw a box. Then at the end, we want to close it with vertical. And inside this loop here. Let's draw the custom list here, and we can also create or since it's quite small, we need to only access activate the game object and the bulon we can just use a big horizontal and horizontal also. We can draw using the editor, Go property field, and we can get from the custom list. Element at index of I and we can find its relative property for the relative property, we want to access this here, the game object and the active status. Let's just grab this. I forgot to add the quote sign. Then we want to draw this active status. Just going to copy from this class here, and let's paste this. But I'm going to make sure that the toggle here will only have a width of a very small width, 25 pixels. Most of the space will be occupied by the game object. For the game object, we can add a label using the new GY content, and this will be the game object. Okay. Let's save this. Now in order to draw this, we need to make sure that first we run the api method from our cerlized object. And then at the end of the inspector UI, we need to apply any modified properties. And we can run the method that we just created and passed this custom GO list. Let's save this. This is not a semicolon. It's a full column, so I need to change that. Now we've already saved this and let's go back to Unity. I'm going to create a new empty game object. To test this editor, go to our actions and activate actions. And we forgot to create a button, so we need to do that. Let's just create a new button here on top of our draw custom object fields here. Using the GI layout, and this button is for adding at three. We can call this button at entry, and this is for adding a custom object fields here. Let's just access our custom GO list and then we can insert using the insert array element at index and we can just pass its array size. Yeah, we already created a button, but if we add entry feature, we also need to add a remove button, so we can just add a remove button here and let's just draw button. With an x character, and then set the width to also 25. And inside this statement here. Oh, I forgot. I need to put this GI out inside the argument here. And then we can just safely delete the customer list here. And we can use the delete array element at index of because we look through the index inside this function here, so we can grab the index right away. Okay. And perhaps to make this tidy, we can just create a GUI layout, and we can run a big vertical, and we can end it. We can also put an n vertical here. The activate toggle and the delete button will lay on top of each other in a single horizontal space. Let's save this. Let's go back to unity and once it compiled, render our buttons, and once we press at entry, it will create this. Here is an issue, as you can see here. The active status label it gets rendered, so we don't want to do that. A we can fix that by adding another entry as a parameter before the GI layout. Here we can just type GI content. We don't want to render any label on it. Let's just save this. Go back to unity and wait until it updates. Now we have this here, but the position is off here and we can delete this, we can add another entry and we can delete this is the activate status, but the layout is not really nice, so I think we can fix this. Now in order to move activate status and delete button to be at the edge of this inspector here, we can just copy this I layout with value. And put it on the begin verticle inside the parentheses of begin verticle. I think I'm going to make this button smaller, maybe 20. Save this. Let's go back to it and see Now here as you can see, it lays out nicely and we can delete and add more entry to it. Now we need to test the script out. Let's just use our PC here or I think I'm going to create a new MPC. I duplicate the first one and put it here and rotate it. I'm going to delete the message action. And I'm going to use the activate actions, and I'm going to direct the actions as the actions for our interactable. And I want to enable some of the box and disable some of the box. I'm going to create a new cube here, and I want to disable this one. If I go back to the second PC here, I want to direct the Q five to be the first slot here, and then I want to enable this. I want to disable the third one and put the third as the second three on our game object slot here. I want to make sure this is unchecked, so it will be hidden. Let's go to let's run this and test this out and see if those game objects start appearing and disappearing. Let's click this. There you go. Once we arrive, it can enable and disable the object. And we need this class for enable and disling status later for disling the child object of every NPC. So whenever we already give some items or receive some items, we want to set a different behavior, different message, so we can enable and disable the child object and those child object will contain the message actions or any actions that we need to create a different behavior. Okay. 21. 20 Importing Assets: Okay. Now in this video, we are going to import the assets needed for this project, so we can go to the asset store. Once we open the asset store, we can search for tiny people. This one. We are going to download this one, this free one, this demo, and this will act as our character in our game, press import or if you haven't downloaded, press download and then import it and just import you our assets. Now it's already imported on my end. Another thing we need to import is the everyday animation motion pack. But we need to search for the free one and this will have a sitting animation and we are going to need those sitting animation. Let's just download it and inport to your project. Okay. Once we finish to download this, the next thing we need to import is our environment. For the environment, I've already provided the package file, the Unity package file on this lesson here. The link is on the video description, and once you download it, just import it. I'm going to import package and choose custom package. Then here, I'm going to browse to my environment package that I've already prepared. Once you found the file import all Now, after it is imported, we will have all of the environment needed to build this point and click game. I think this is all for importing and after this, we are going to continue develop this game. 22. 21 Player Animation: Now we are going to change our player here. Instead of using a cylinder or a capsule, we are going to use our character objects. Let's open our T people and under the prefabs folder, we have this male B and this will be our protagonist. Let's just direct this male B to be the child of our game object and reset its value. Okay. So now we can just delete our mesh mesh render also, and we can move the capsule collider on the y axis. Should be around and we can just delete the cube here also. Now we need to make sure that our game object is facing the same way as our z direction of our parent de player game object. Let's go to the child object and reset the y rotation two zero. Now we need to adjust our capsidr and our knife mass agent gizmo here. Let's just moved and make this smaller, maybe 1.7. Then we can see it from the side here and I can just slid our y offset of our capsule here. It rests It rests on. Something like this, for the nin, we want to set the height to the same value as our capstort's just set it to 1.7. Then I think Can we just offset this? Yes. Using the base offset here, we can offset it and set it two zero. It will sit nicely with our game object. Yeah. I think I'm going to set this 20.5. We have this set correctly. Let's go back to our perspective view. Let's move our player to rest on top of the ground here. And now if we go to our player game object, we don't have any animator controller currently created. So let's just create a new folder, and let's just call this animator. And inside this animator, let's create a new animator controller for our player. So let's just call this player animator. Then we can drag this player animator, this object but the child object and drag this player animator to be the controller of our animator. Now if we open the imator we have this empty mechanism state, we can just create a new blender and this will be the idle state. We are going to use a blender it will blend nicely from idling to moving. Let's just go to the ileu click it and we can open the blender here. If you can see here, It creates a new parameter automatically. We can just delete this and create new one or we can just rename this. I'm going to rename this from blend, change the speed and this parameter has type of float, is a type of float, now it's being used by our blenre let's create two different motion. The first one would be the male idle and we have this I think we have this maid A or B. We only have male idle A, so let's just use that for the movement, we want to use the male walk. The mail walk, the one without the underscore r at the end. Now we can see here if we play this, let's say we scrap its value here. It will switch to running. To walking running, but walking. Now we have this setup. We need to change the speed here via our script. Let's go to assets folder and let's go to the scripts folder. Let's create a new script script and let's call this player. Okay. Animation. Now we have created player animation. Let's open the script. This will be actually very easy to do I want to try to minimize using a mono behavior class in a game object. We can just remove this mono behavior class and we will intandla animation onto our player script. Since we are not driving from mono behavior, we cannot use methods such as get component and final object of times. We need to create a new private animator. Let's call this animator. We want to create a new public void and let's just call this initialization. Or we can just call this and we'll need to pass an animator component, and we can pass this to our animator. Let's just type animator and equal. We need to run this public method on our start method inside the player script. We need to also create a new public method, and let's just rename this. I'm going to delete the command here, so it's not confusing. Let's just call this update animation. To make the animation work nicely. We can just access our animator. The basic thing we need to do is we need to modify our speed parameter. We can just access that by setting the float here if you see here, we have a string name or we have also a string ID. We can just create a hash ID for this purpose. Create a new integer and let's just call this speed and we can set this value to meter string to hash and we can pass the string name. In this example, we have our parameter is called speed with capital S. We need to make sure that we type the name of the parameter, and this will convert this to a hash ID. We can use this hash ID for passing or setting the float that use this parameter. This will be much quicker instead of if we're using string for every frame because we are going to run this method every frame. For the value, we need to we need to pass the speed, but we don't have speed here, so we are going to pass a float this method, we are going to use this speed to drive our animation. Let's end this with semicolon here. Save this. And now we have this class created. I'm going to delete this unused libraries here. And let's go to our player script, and we are going to create a new private and let's just get player animation. And let's just call this animation. On start, I don't think we can use this. Let's just call this player. Let's just instantiate new player animation here on declaration. On start, we want to initialize, so we can just access and call the init method. But since it as for the animator, since the component is not on this game object. We need to search for the animator in children and search for the type, which is animator. Since this is a method, we need to add parentheses and this will return animator, and this animator will be passed to our player A we want to pass our falsity from our anthems agent. We can just run the method inside update player AM and I think it's update animation. I asked for a flute here, so we can just pass the agent and I think we have not current fellow City. This is the setting for velocity, but let me check. Yes, we want to use the velocity and since this is a vector, we want to get this magnitude. But because magnitude it requires a root square root calculation. It's not very performance. We can just use the SQR magnitude and it doesn't really matter. The value difference if we are idling, this value will be zero and if we moving, of course, it's going to be greater than one, because our maximum speed is around 2.5 or three in the FMS agent in the inspector. Let's just set this like this and save this. Now, once we finish modifying our player script, we can see here. Now it's already added, and we don't need to add this player animation because it's not a mono behavior, actually, we are running the script via our player script by creating a new instance here and then initialize it because this class here cannot find animator on its own. And then we are running the update animation every frame inside the update function of our player script here. Let's just save this and go back to unity and save the scene also. Now if we press play, it should play the animation here. Right now it's link and if we move here, as you can see, if we move there, I play the walking animation. So this is how we create walking animation, and as you can see it creates a very nice effect using the blendery here. Okay. So that is basically for the player animation. Okay. 23. 22 Animate Actions: Okay. So now let's create a custom actions for playing custom animation, and this actions is mainly for the NPC. Let's just create a new script inside our scripts, actions folder, create a new CS script, and we can call this animate mate action. Once we create this, let's open this in Studio. Now we need to make sure that this class derived from actions, and let's just implement the abstract class here, the override, and we can just past this here and replace our update function. Now, we are going to need to create a custom classes and this custom classes will act as a serialized field to setting up animation parameters. Let's just mark this as serializable. We can access this from the inspector and let's just create a new public class and let's call this parameter. Okay. Basically what we need to have as a field here, we need to create a new SS field and this should be the type of string. Let's just call this trigger name. The next one is a type of float and this will be the invoke delay. The last one we need to do to create this, we need to create a public properties and the type would be integer. Let's just call this hash ID. Hash ID is basically a integer values that can be accessed for accessing the trigger name, and we can convert the string teger name to a hash ID using a special function from the Amter class. For this public properties, I'm going to make sure that we can get it from under script, but we can only set it as a private set. Like this, we need to end the private set with a semicolon. Then I'm going to create a new public method and this would be called hash ID. Basically, what we want to do is we want to set our hash ID to be the value from the animator class, and then we can search for a method called string to hash, and we need to pass a string name. For this, we are going to pass our trigger name. Basically, the string will be used for setting a trigger to transition from one animation state to another animation state. I'm going to show you how to do this in a moment after finishing the script. Now we have this class created. Let's just create a new serialized field, and let's make this a list of parameter. And I'm going to call this anyms let's just initialize it. Another thing we need to create is we need to create a new RS field, and this will be a list of actions, and let's just call this actions and let's just initialize it. This will be a chaining actions. Whenever we finish all of the animation playing, if we want to run a certain actions, we can put another actions into this actions here. Save this. Now we need to initialize our animation first. Let's just create a loop. For the loop here, we want to make sure that if I is lesser than the count at length that count, then we want to initialize it. Let's just run the names index of I and run the init function. Basically, this function will populate this hash ID properties and later when we want to set trigger some of the animation, we can use this hash ID instead of a string trigger name, and this is much more performance. Now we have this. I'm going to delete this system not implemented action. Let's create a new routine enumerator, and I'm going to call this animate. We are going to create a new integer. It should start from zero, and I'm not going to use a loop here because I want to halt the thread or the coroutine whenever the animation is not finished. I want to use a while and if I is less than our any co then we want to run the loop inside this while here. For the first line, I'm going to make sure that we are going to yield return and using the keyword new weight 4 seconds. I want to pass this invoked delay here. But since this is a private field, we cannot access it right away from our named class. I'm going to create a new public properties type of flow I'm going to call this invoke delay with capital. Then I want to set the get value and I want to return, it's Invoke delay field value here and close it with semicolon. We want to return whatever value that we are going to feel here in the inspector. Then once we have this setup, we can just use the NMS list and then xy and then we can get the invoke delay value here. We want to only get its value and we only want to set this value in the inspector. Okay. Now, once we delay this based on the invoke delay, we want to trigger the animation. In order to trigger the animation, first, we need to create a new private animator field. And let's just call this animator. Okay. On start, I want to grab this animator. Let's just run the animator and then let's just use this get component in children. Because the animator might be might be added on the child object, the mesh object, not on the parent object. This way, we are going to make sure that this get component searched through the child object also for any animator component. Then we also want to make sure that we take this with a required component type of animator. Once we have this animator, we can just trigger the animator by using the set trigger method from the animator object here. Instead of using a here, as you can see here, if I close this, let's just try to retype this. Instead instead of using a string, we are going to use this integer ID, and we are going to use this hash ID. Let's just access our index of I and then grab the hash ID. Once we setting the trigger, we are going to increase the value, and then we want to halt the cotan up to this point here. We can just type yield return, and then after finishing the while loop, we want to run any actions that we assign in the inspector. Let's just look through our actions list. Then for every actions, we want to execute the ac method. We cannot use I. I'm going to double click on the I here and set it to J and change all of the other integer. We are not going to use the I, we are going to use the index of J, and then we want to run the method on every action that we assign on the inspector. Now, once we have this animate, let's just run the routine, let's just start routine and then pass the rootin name, which is animate and the set of parent. And then close it with semicolon. Once I think this should work. Let's go back to unity. Now let's try to set up some NPC that we can interact with the player here. I think the first one has some dialogue. Nice. It as something. We can just expand this NPC here and now we can put a character. Let's go to the two tiny people. And go to the precept folder and I'm going to direct the police game object and set this as a child of this NPC here and go to our scene here and let's set it up. I'm going to set this to zero. I want to delete the cube here and also delete the capsule mesh filter and also the mesh render. I think we can set this to the same value that we have to our player. Let's just copy our capsule coder from the player. Since the character size is the same, we can paste the copy value to our caps paste component values here. Yeah. So we have the same alignment for our collider. And also for the I think collider is enough because we don't have enough mass agent. So let's just set this two zero or 180, so it face our character. And if we I think we need to set this two zero, the Z value will point to the player. The player will stop in front of this police officer and we can just rotate the child object on the yx20, so it's facing the same direction as its parent and we can add the animate action into this child game object and now I'm going to set the two one, and we are going to set a value here. But first, we need to create some animator for the NPC, let's just create New animator inside the animator folder, I'm going to call this call this police animator, and we can direct this police animator. Now if we go to our animator window here, we don't have any state. Let's just create two different states here, and this one will be idle, and the other one will be talking. And we can create a transition from the idle, make transition, right click and then go to the talking. Then from the talking, I'm going to create a transition and go back to idle. For changing a transition, we need to create a trigger. Let's just press the plus button here, create new parameters on the parameter windows, make sure it's a parameters, not layer and go to the parameters and then press the plus button, and then press the trigger option, let's just call this talk. For the transition from the idle to talking, which is this one, the one with the arrow pointing up, we want to set the condition to talk. Let's just press plus button in the conditions here and choose the talk trigger for a trigger, there are no parameters that should be set up, choose the trigger and it should be okay. And we want to disable the has exit time and for the transition from talking to idle, we want to make sure it's to has at time, but the conditions is empty. So we want to once it finished doing the talking animation, we want to go back to idle. For the idle animation, let's select the state here and then choose the motion, and I'm going to choose the male idle A. Okay. And for talking, let's just try using the set male at set up on chair because we don't have talk animation yet, but we are going to import some animation later. Let's just use this one and see if the animation is changing or not. And I think this is we already set up on the im of site. So let's just select our NPC here and reposition here. So it sits it rests on top of our ground. It's not floating like before. And now, whenever we are interacting, we want to add a new action, and then we can drag TTD pole object here and it will detect the imit action automatically and save this. For the nate action, select the game object that has the animator component for the imate action, we need to set the trigger name to talk. I don't want to give any delay, so I'm going to set this to zero, but if you want to delay the animation, you can just set this to some value and this will be in second, for the trigger name, make sure that the trigger name is the same as our parameter name here. It will trigger this transition. Let's save the scene again. Now let's run this as you can see here, we have a idle animation, and you can see that in our NPC here, animator, the idle is running with this blue bar here, you can see it's running. If we try to click on the police officer, you'll see it plays a different animation. It starts talking, but once it's finished, then it goes back to the if we click again, as you can see here, and we can just dialogue. Okay. Okay. So yeah, this is basically how we create animate actions, and of course, we are going to change the inspector appearance using a custom editor. Okay. 24. 23 Animate Action Editor: Okay, so now we are going to create a custom editor for our mate action, and let's go to our scripts folder, and under the editor, let's create a new CSO script. And let's call this animate action editor. Now let's open the script. As usual, we want to modify this. It imports the unity editor name space, and then we want to make sure that the class derived from our editor class. Make sure this will inspect the script that has type of and action. Yeah, save this and we are going to delete this method. Now we are going to create a new serlize property, and this would be the anyms and also the actions. Yeah. Okay. So now we are going to create a enabled method. And for the enable method, we want to search for this erzed property for the ys. Let's just search it from this erzed object and using the fine property method and search for the parameter or field that have this name here. Let's just open our animate action. I'm going to move this to be side by side with our editor, and I'm going to copy the any field names and paste this here. For the actions, let's just do the same using the fine property, and then access it by its name, which is actions. As you can see here, save this. Now we are going to overwrite the on inspector GI. Let's just do this base on inspector GY. First, we need to create a button to add parameter. Let's just create a new G layout here. Button then let's just call this ad animation parameter. And as usual, we need to make sure that we are updating any serialized object in start of our uninspected GI, and then at the end of our uninspected GI, we need to apply any modified properties using the apply modified properties method. And then. Basically, whenever we add new parameter, we want to add a object or an entry to our s list here. Let's just access our nyms. Then we can using the insert array element index and we can pass the size of our nyms array. It will always increase by one. Now we need to draw the inspector. Now we are going to draw the an inspector. Let's just create a new method. Draw, for this, we are going to need a serialized property also let's just call this entry also the integer ID. Okay. Now, as we can see here, our yams has two post field that we want to draw. Let's just do that. We are going to create a new go layout, and we are going to create a new begin horizontal, I think horizontal so do we want to pass the box parameter, so it will draw a nice box for every e n we want to end this with a n horizontal. And now we want to create a editor out, and this should be a property field. For the property here, we want to get the entry and we want to find the relative property and the relative property. I think it's called a trigger name, call this. For the label, we are going to create a new I content for the label, I think we can call this trigger name. Close this. Then the next thing we want to draw is we want to draw the property field also and this would be the fine property relative and this should be the invoked delay, so let's just copy this name here and paste this here. L but I content, and we can just call this delay. Like this. And since this is a float field. I'm going to make sure that the width of our field. The second field here is small, so I'm going to make sure that we are using the GI layout. I think I don't know. Let's just try the 60 pixel. If it's enough or not or if it's not, then we can just change this. And now we are going to look through our any array. Okay. And then we want to draw inspector and pass the nyms and then get the element at index of I, and we want to pass the number as an ID here. I think we need to change this, we are going to create a quick changes here. We want to create a new begin vertical box, and we want to end this in vertical fashion. Then inside here, we want to create a layout option, layout options, but lay the normal layout. And we want to set a begin horizontal here without the box parameters, and we want to create a delete button. Let's just horizontal here, and we want to align this delete button with our trigger name field here. Let's just create a new statement, layout and then button, and I'm going to pass x as a string for this button here. Let's just set width of this button to a very small one, which normally we are using 20 pixel. Okay. And sorry, we are one less parentheses here. Okay. We can just enter this and create gap, so it's much easier to read. Okay. Okay. Now whenever we delete we press the delete, but then we want to delete the ys, and then we can just delete element at index of ID. We want to delete the array index of the ID that we are passing through the method here. It will make sure that we delete the same entry that currently we are modifying here. Another thing we can do is we can create a action. Let's check our editor extensions here. As you can see, we have draw actions array, so we can just use that right away. For the extensions, we can access the editor extensions and then we can just draw actions array. Then we can pass the actions array here, which is the actions field here, we can just label this action or actions chaining something like this. Let's save this now let's Is that all? I think this is all. Let's go back to unity and let unity compile and see if there's any error or not. There are no error. Let's go to our NPC and the police game object, and let's check this. Now we have this drawn here. But I'm going to fix this here as you can see. I'm going to make sure that our property field, the second field here, the invo doesn't have this layout. Delete this layout with altogether and save this. Okay. Okay. Now, as you can see here, it lines up nicely, and if we delete this yes, there is an error, as you can see, It tries to draw once we have deleted this. We need to fix this. Whenever we delete the array here, we need to return. It will stop this and it will not draw this anymore. It will ac this method and it will try to draw the inspector on the next frame again. So that compile and once it compile I think it should Okay. Let's try this again. Now we have delete this If we add eimation, it creates new one and if we delete this, it delete automatically. So we can create a lot of animation and we can chain animation using this delay in second here and just delete this. Okay. So now let's just set the top trigger back and set this delay in sec two zero and we can add actions. Let's just once we run the action. We want to hide the police officer, so we can just use the activate action, add an entry and direct this action as a action chaining here. We want to hide the NPC, the parent game object. Set this to height to disable and save this. Now let's play the game and let's go to the police officer and once it plays this animation. Okay. It's missing. But it's missing right away, so there is an issue here. Okay. I found the issue, and basically, the problem is when we add a changing action inside our animate action. It will execute the actions right away, even if the animation is not done yet. Because as you can see here, we have a delay in second, which is zero for our top here, when the idle goes to to right away, our script also execute the actions right away here. We need to modify here and we need to grab the length of our current animation. Let's just do that. For the grabbing the imator current state length, we need to type here, return new and using the new eight 4 seconds. Inside the parameter here, we can access our imeter then we can get the next state in full. Because whenever we are getting the state in this frame here, this will still return the current state, which is idle. It's not talk yet because we are just setting the trigger just about now, it hasn't transitioned yet. We need to get the next im state info. And this is a method and it asks for a layer index. Since we are using the animator or the mechanism from our base layer, which is index of zero, then we can just pass zero here as our index. Then we can grab its ling. As you can see here, the current duration of the state. Now, but if we try to run this, it will still cause an issue because when we set this trigger here, this will still return a wrong value, and when I test it, it returns zero. We need to add a yield return. New weight for end of frame. Basically, this yield, it will return at the end of frame. After finish rendering, then it will run this code here. Basically, at the end of frame, we will already initialize the new state and this will return a correct length value. Let's just save this. And let's go back to unity, and we don't need to change anything on the inspector side. So let's just run the game once it's finished compiled. Now if we try to talk to the police officer, it will try to sit down first and then after sit down, it will de activate it. So it will finish the animation and then it will run the chaining actions that we assign in the inspector here. Okay. 25. 24 Level Manager: Now, we are going to create an action to change scenes in order to do that. First, we need to create a manager for handling level transition. Let's just go to our scripts and manager folder, and then create a new subscript and let's call this level manager. And let's open this level manager. Now we have the script opened. First, in order to create a transition or in order to create a function that enable us to switch between scene, we need to import the scene management namespace. Let's just type here using Unity engine scene Management. The next thing to do we need to create a new Cerus field game object variable, and let's just call this panel. And for the next one, it should be a regular transform, which is transform, and this is basically the base transform for a object. Instead, using the normal transform, it is using this transform and this would be the load bar. And we want to create a new private factor three, and this would be the bar scale. Let's just set this by default to factor three one. Factor three one is basically a shorthand version for writing vector three, one on the x and one on the y and also one on the x. Vector value on all x will be one. Let's save this. The next thing we need to do is we want to make this pal manager has a static reference. I'm going to create a new weak method. On top here on the field area. I want to declare a new public static properties and the type will be our level manager. I'm going to call this instance. Then I'm going to set to have a public getter. But for the setter, it will be a private like this, so we can set it only on the script, but other script can get reference to this static reference. Okay. So let's just set this instance to this. We won't create a Singleton pattern here because at this level manager will recite as a child of our data manager. So it will persist across this scene. So we don't need to check if there are any other level manager because it will stay always together with the data manager. We can safely delete this update and start method because we aren't going to use that. I'm going to create a new show panel method and a panel method. For showing and hiding panel, I'm going to use this panel set active to true for the hide panel, we want to set the active status to falls Okay. So whenever we want to enable the loading panel, we simply run the show panel, and if we want to hide it, we can simply run the hide panel. And now on start or on awake, we want to hide the panel right away. Now we need to create a new co routine to create a synchronous loading screen. Let's just type this a syn loading. We want to pass a string for the scene name as a parameter. We will define the In co routine here. But before that, I'm going to create another method, another local method, and let's just call this bit bar. Okay. For updating the bar, we want to pass a float as a value of the bar. Inside this method, we can simply just access our bar scale, a private factor tree variable, and we want to modify its x value to be equal to our pass value on this update bar parameter here. Once we pass this, we want to apply the new changed value here to our load bar scale. Let's just access the load bar local scale, and then equal the bar scale. S like this. Now we have a method to update our bar. We can start create our synchronous loading process. Basically, what we want to do is we want to show the panel first whenever we try to load the new scene here, and then we want to yield return weight for frame. We want to wait until the end of frame process or frame rendering. And then we want to create a new asynchronous sin operation. And this would be the load and for the value for our asynchronous, we want to run the sin manager class and we want to use the load scene asynchronous. Then we want to pass the name, the string name here as the target loading scene. Now, once we have populate our asynchronous load object with this scene manager, it will have a properties such as can check whether this operation is done or not by using the sync load and it has this done property. Also, it has a progress properties and this will return a float. What is the operation progress and this will return between 021. We can use this to pass that value to update our bar. Now in order to loop our Anker is weighting loading, We can type while, then we can type the object name, which is the assing load and we can check is it done or not, and this is check has the operation is finished. If you want to make sure that while it is not done yet, we can add an exclamation mark in front of this bulon here, and this will check for if the *** load is not done, then we want to look through this code here. I order to look this, I want to put a return, and we want to update our bar using the value from our progress. Let's just type update bar and save it first. Let's create a new float variable called progress. For the float progress, we are going to use a clam zero one and this will clams the value between 021 and the returns value. I want to clam our sync load progress because as load to progress, we return 0-1, but it is actually the loading progress is 0-0 0.9 because the last 0.1 value is assigned for preparing the scene. We want to show the update value 0-0 0.9. Using this clam, it will return our progress to one. Let's just divide this by 0.9. And what this actually mean here. Let's just use calculator and what this means here. If our as load value is 0.9, we can test this zero point 9/0 0.9, and we will get one. Basically, we are setting the maximum value to one. When it's reached at 0.1, we want to reap the value to one, and if it's zero and it will stay zero, and this clam we'll make sure that this value won't go below the zero or it won't also go over one. I will just keep the value safe between 021. Once we create this line here, we can pass the progress value to our update bar. Basically, once it's done, or if the sing load progress reaches one, it means that it is done and it will leave this loop here and we can then disabled. We can then hide our panel like this. Now we have this coroutine declared or defined. Now we need to create a new public method. For it. This would be, let's just call this scene load. Then we need to pass the name as the target scene that we want to load. Then we can use the start co routine and then run the loading routine that we created below. Then we can pass the s name here. Whenever we need to switch level, we can just run the scene load from any other script, since this level manager has a static reference and we save this. Now we have this level manager setup. Let's go back to unity, and let's create a new UI Canvas, and this will act for our level manager Canvas. For this canvas here, let's just copy our scalar properties, copy the component and just paste this on its canvas scaler, it has the same pixels values or resolutions settings. We want to make sure that the sort order is greater than our default canvas. Since this is zero on our level manager canvas, we want to set this two one. This canvas will get rendered in front of our UI whenever it's being used, and we want to create a new image. Let's just call this panel. And let's just maximize the panel, so it fits the screen, and I'm going to change the color to bland. Another thing we want to do is we want to create a new tech mesh pro and I'm going to increase its size to 300 by 75. Then I'm going to set the alignment to the center and also the middle and change the text to loading, and I'm going to use the ose. It will fit our transform width and height setup. Now we have this loading. I'm going to push this slightly on the y position around 35 pixels. Safe and then I'm going to create a new loading bar using the UI image. I'm going to set this to round 205-20-4205 and I'm going to set the value of the y posin to run negative 25 pixel. It moves to below this text here to the bottom of the text, and we want to set its width to run 200 or 300. Now we have this nice loading bar. Later, we are going to modify its scale here on the x axis. But at the current setting at the current anchor point, this won't be feasible because it has the anchor point in the middle. We need to fix that. In order to fix that, we want to go to the anchor free sets, and then we want to hold shift so we can move the anchor to the left side of the bar here, we can choose this. But this will also move our pivots and move our anchor point also. Once we move our pivot here, we want to click the middle anchor again, so the anchor stays on the middle, but the object pivot will be on the left side of our bar here. Now if we change the value on the x axis, it will keep the pivot on the left, we have a nice bar progress like this. Set this back to one and save the scene. Now if we go back to our level manager canvas, we can wreck the level script to the canvas object. Then we want to drag the panel as the panel field here. If the panel gets disabled via script, it will hide all of the left switching graphic or UI, and if it's enabled, it will show this window here. Okay. And we want to direct also the image as the load bar. So whenever we load the scene, this will get change, depends on the load progress value. Let's just save this scrip. On the next video, we are going to create an action to change scene. Okay. 26. 25 Change Scene Action: Okay. Now we are going to create actions for changing scene and this actions will access the level manager to change scene and show this loading progress. Now let's go to the scripts folder and under the actions folder. Let's create a new CH script, and let's call this change scene action. Okay. Now let's open this CHR script. Now first, we need to make sure that this change in action class derived from the action based class and we need to implement the abstract method member. Let's just fix this by creating this public vero I'm going to delete the void update and move the egg method should be below this start method. We want to create a new serialized field type of string, and this will be the s target. Okay. And whenever we run the x method, we want to access the left manager instance, and we want to run the scene load method and we also want to pass the scene target name as the scene name parameter. It will change to that scene. I think we don't need to start method too. Let's just delete this. And the next thing we want to do is we want to store our previous scene name, and this will be useful to reposition or determine the player position relative to the previous scene. So the player can start from let's say from a taxi or can start from a door position if the previous scene is the interior of the club, for example, we need to create some sort of dynamic reposition at start and this will depend on the previous name. So let's just hold that data inside our data manager. Let's open our data manager. And then we want to create a new public properties and this will be type of string. And let's just call this previous scene or prep scene name. And here, we want to make this a public get but a private set. Okay. We won't be able to set this previous name from another script, but we can create a method to do that. Let's just create a new public void, set previous scene. Let's just pass a string name, call this name. Then using this method, we can access our pre name here, use the eqsine and pass the name. When we run this method, it will change the previous name. Later we are going to use this for the players paint position. Let's go back to change scene position and now we want to access the data manager instance, and we want to run the set trap scene. Now we want to get our current name. In order to do that, we need to first import the scene management class or name space. Let's just type using Unity dot engine scene management. Then once we import this name space, we can access the scene manager class and we can get the active scene, and this is a method. And after we get the active scene, we want to get its name like this. This will return string, and the scene name will be set to our current previous scene in our deminer. Let's save this, I think they should do. In order to test this change scene action, we need to create a new scene. Let's just hide our panel here. And I'm going to make this data manager as a prefab. Let's just create a prefabs folder. I click here under our assets and create a new folder and this will be a prefer this is wrong. It should be pre open this prefs now we want to save the base canvas here. I'm going to rename this as our base canvas. This is where it has this dialog system object and we want to set this as a prefs we want to also set the data manager as a prefabs. And also we want to set the player as a prefab. Whenever we create a new scene, we can wreck this three object right away. Let's just save this. Now, let's just go to our environment here. I'm going to set this cube here or this one. I'm going to make this interactable. First, I want to create a new material so we can see the difference, create a new green material, change this color to green. And directly to this cube here. Now for this cube here, we want to move this out of our environment. We want to make sure it's interactable. Let's just use the interactable script. For the action, we want to run the change scene action, and let's just save this scene here. Under the scene, we want to create a new scene. Let's just create a new scene here. Let's call this city. For this cube here, Let's just set the scene target two C. Whenever we click this green cube here, it will switch our scene to scene here, save the scene and let's open our C we have previously imported our scene model. Let's just access the point click folder, and if we open this, it has a prefab and I want to direct the city scene here and once it's imported, as you can see, it has this nice city model. Now, let's just put our player somewhere inside the city. I'm going to put the player to be here. Sorry. I want to put the player to be around here. I want to put the data manager and also the base canvas. This is basically baking, but it takes too long because it has lights and stuff. We want to go to the lighting properties and we want to disable the auto generate. Now we want to change the indirect samples, if you don't have the lighting windows open, just go to the window and under the rendering, we have this lighting setting, and this will open this lighting settings. We want to set this to not shadow mass, but big indirect. Then we want to set substrative. And then we want to set the indirect examples to a quite low. I will set mine to 50 and the direct examples to around 24. For the light map size, we can decrease this to 512, five 12, save the scene and make sure that the atto generate is disabled and less generate lighting. Of course, we are going to tweak this lighting later. But right now, we want to set this to a quite low value, so we can run this scene without baking every time there is a changes on the lighting and stuff. If you can see here, bakes the light nicely with the settings. Once it's finished baking, we can continue. Let's just reposition our player. I want to rotate the player so it will face to this building here. Let's just rotate to 180 on the y axis. Okay. Now if we go to our city game object, it has a static properties check, and this is also applied to all of the child object. So now we need to make sure that we go to the navigation. We need to make sure that we bake the scene, so it has naviigation mass. So let's just run this and press bake. Okay. Okay. Now we have this navigation mesh, and the lighting baking is also done. Here, it's saving the light map to the EXR files. Now we have this set up scene. Let's just save our scene. Let's test this. If we plus play, can we run or can. We need to set up our camera. Let's select our camera here because it's in the center here. I want to set the few something like something like this. Let's just select our main camera. Once we have this on our perspective view, we can press control shift and F to set up the camera, the same position as our preview here. If we go to the game view, you can see here, we have set up nicely, but we want to more because we can see a hole here. Let's just zoom once again, and then realign our camera. Now we have this nice scene here and save this again. If we press play, Okay, there is an error. Let's check what kind of error? There was an error previously. And the first thing we need to do is we need to make sure that the city has a default layer first. So let's just set this and apply to all of the children. And There is an error on our extensions. This method when this method is for checking if we are clicking on the UI or on a game object, if we click on the UI, it will move our character just like in the previous video, the error arise because we don't have the event system on our scene. Let's create a new under the UI and let's create a new event system. Save this. This is created automatically when we create a new canvas, but since we drag this canvas from our prefabs, it doesn't create this automatically. We have to create this by ourselves. Now if we press play, you'll see that we will move on the scene here. Now we have the setup. Let's test our change scenes action. Let's go back to our sample scene here. Now let's press play. Then I'm going to click on this green box. Once we arrive, it will switch our scene. Okay. It doesn't switch, let's check our cube here. We already set the change scene action, but we haven't assigned to the intertable so let's just direct this script to the action, and it will create a new entry and will access this change scene action and state the scene again and let's test this again. Now, it open, but there is an error. Let's just check. I also forgot to put the scene in the build setting. Now we need to go to our build settings and all of the scene that needs to be accessible by the scene manager needs to put inside the scene in build here. Let's just go to our project, our scenes folder and drag the scene to this sins build. Once we have put the c here in the build settings, it should work. Let's test this again. Okay. Now it loads and change scene as you can see here. For example, if let's say on our scene here, let's say we want to create a new empty game object, and this empty, we'll have a box collider. Then we want to move this box collider to be around this do For example, we can just edit the collider and change its size. And then we can easily set this to intable then we can use the change scene action, and we can change this back to our sample scene and assign the actions. Let's go back to our sample scene here and we can go back and forth of these two scenes here. If we go to our city scene here and if we go to the door here, it will go back to our sample scene. There was an error. Whenever we switch scene on the next scene, we cannot find the level manager instance, the static reference. We need to change how this works. Basically, if we go to our level manager script, we don't need the static reference right now. We can just cut this first. And we remove this static setup here. Set hide panel on awake and go to our data manager and we want to paste this static reference, but we want to make sure that this is not a static anymore. Let's just delete delete the static keyword. We can call this instance because instance is already reserved for the static reference. Let's just call this left manager. And then upon k, we want to fill this with the level manager component. Since the level manager is the child of our data manager, we can just type level manager equal, get component in children and this will search the component in the children of this game object, which is suitable for our case here and search for the level manager class. Okay. Okay. Now we have access to level manager via our data manager, and we need to change a couple of things for level manager is already working, it should be working. We need to change the change scenes action and right now instead of accessing the level manager, we need to access the data manager instance. But the scene load is under the level manager object, so we need to access the level manager properties and then run the senad method like this. Now once we modify this, this should work, I've tested before and now go back to unity, save our scene. And we need to apply this prefs one more time. Our prefs on the assets folder gets updated. Now if we test this once again, it will load to another scene, and if we go to this door here, it will load back to our previous scene here. Now our change scene action is working and the next thing we need to create is the player spawn position. 27. 26 Player Spawn Position: Okay, so now we are going to create the player position manager. In order to do that, let's create new CS script under our scripts manager folder. Let's create a new CS script. Let's call this player Spaw position. Once we created this new script, let's open this on aficio Studio or Monell. Now let's just create a new private and this will be a type of transform, and this will be our player. We are going to create a custom class to hold the data. Here below the players pon position class. Let's create a new class and let's mark it as serializable. Let's call this poner. For this punter, let's create three field. The first one would be the previous scene or prep scene. The second one would be a type of vector tree, and this will be the position, or we can just call this saw position. The third one would be also a factor, but this will be a saw direction. We will create a public getter for each of this field here. First, let's just create a new public string properties, and let's call this the same name with capital letters. And we're going to only set together, and this will return our prep name. The next one will be a vector tree, and this will be the spawn position with capital S. Then we want to return the saw field value. The third one would be also a vector three, and this will be the spawn direction. We want to also return the spawn direction field. Now save the script. Now we can create a list of our spawner. Let's just create a new series field in our player spawn position and then create a new list and the types should be our spor that we have just created here. And this would be the spawn and trees, and let's initialize it by typing the new less spawner. And we are going to delete the update method. Basically, on start, we need to find our player. Let's just type the player field here. Then we can use the game object class and then find object with tag, and we can search the player tag. But since find game object returns of game object, we can access it transform by typing the transform because player is type of transform, so we need to search for the transform component of the found game object here, the search game object. Then we want to reposition once we found it. This is a method and we are going to create the method now. Let's just create a new method and call this reposition and we want to look through our spawn entries. Let's just create a four loop. Then for the length, we want to type entries. We want to search through the spawn entries and If the data manager instance previous name is equal to the pw entries index of and we want to get this previous name. But since this variable has a type of private and serialized field, that's why we are using this public gather. Let's just type the name. Then if it's equal, then we want to set our player position to be the same as our spawn position and the direction to be looking at the factor direction here. For the position, we can transform, but player position equals to this entries index of I saw position for the direction, I'm going to set the rotation to be equal to quaternion class, and then we want to use the rotation, and then we want to insert the saw entries and we want to get the spawn direction. Let's save this script. Now we've created our players spawn position, we can save this and let's go back to unity. Here, we are going to create a new spawn position manager. Let's just create a new anti game object. Reset its value, Let's just call this spawn manager. Then let's drag the script spawn position and we can create a new entry. Okay. And now we can just for example, we can just put it if we are from the CD scene here, we can type the previous name and we can set its position, for example, to be maybe around let's check this here. We can set the x23 and the z two negative five for the direction, for example, if we want to make the player looking at the negative x direction, we can just insert negative one on the x axis and it will make the character looking to the right here based on our camera few. We are going to save this in order to make this works, we need to tag our player game object to have a tag of player. Let's just do that and I'm going to apply this prefabs Save the scene and now I'm going to reset the transform value. But we have this value already set up in our players pon position. Right now, if we press play, the player will start from this position, as you can see here. But if I go to the city here, After we load this. If we go back to our sample scene, you can see the player, we'll start from this position here. This will be useful if we are entering a building, and then we go back out from that building. We want to start from the door position of that building in the city. With this spawn manager, we can create as many entry as you want. If we are arriving from different scene, we can set a different spawn position. Of course, we are going to set up a custom inspector to make this setup easier. 28. 27 Player Spawn Editor: Okay. Now we have position script working nicely. Let's create the custom editor for the script. Let's go to our script editor folder and create a CH script. Let's call this player Saw editor, and let's open the script. Okay. Now we have this players editor open. I'm going to set up a couple of things before we continue the script. As usual, we need to import the Unity editor namespace, and then we need to also make sure that inherits from the editor based class. We also need to mark or this custom editor and insert the type class that we are going to inspect, which is the player spawn position. And for this script, we need to only create a serialized property. This will be the spent the array of our sponor entries. Let's just delete the start and update. First thing we want to do is we want to create an enabled method for enable method, we are going to search for our sponor entries and we can just access the serialized object, and this is the inspected object. Using defined property, we want to search for the serialized field here. Let's copy this name here, and then I'm going to paste this to our string argument. And this will search for this field here. Now let's just create an override for our inspector GI method. Let's delete this based on inspector GI. As usual, we need to make sure that we are going to update before we are modifying the inspector. Then at the end, we need to apply any modified properties using the apply modified properties method. Now we need to draw the re. Let's just create a new method to do that. Let's create a new method called drop entries. Then we are going to pay pass the serialized property here. Let's just call this spawners. We want first to create a new Q layout and this will be a begin vertical, and we want to pass box as parameters. It will create a custom box inside our inspector, and then we want to end vertical. After creating the begin vertical, I'm going to create a new. Editor. Sorry, it's wrong editor I layout, this would be a field Label field is a fixed label that are not editable. Let's just call this per entries. We want to check first, if the per array size or the count member is equal to zero, then we want to create a new button. Let's layout button. Let's name the entries. And we want to add a new entry for our sponor entry. Let's just use the insert array element at index of and we want to pass the sponor entries array size. It will always add new member at the end of our array. We want to loop through our entry so let's just create a new for loop. We want to look through our sponor let's just use this keyword here for the poner entries and also for this one because we're already passing our son are going to pass the poner entries to our son argument here. And we can access the poner array size. Now we need to draw each of the entries. Let's just create a new GI layout and this will be a big horizontal, and we want to make sure close it by horizontal. We will need to draw the sponer settings. We have three settings, which is the previous name, the position and the direction. Let's just draw edit g layout, and this will be a type of property field. Property field, and we need to pass the seriz property for the property, we're going to use this poner and we are going to get the array element at index of I. Then we want to find the relative property, and for the first one, it should be our previous name. Let's just copy this name here and put it here inside a and then For the next one, we can just copy this line here and paste it a couple of times for the saw position, we want to grab the saw position, and for this saw direction, we want to grab the spawn direction. This is going to draw a basic property field for this entries. Then we want to draw a set a begin vertical and we want to close this with a vertical. And this is for creating a button. We want to create a button that will lay out from top to bottom and not horizontally. This button will resides on the side of this beside the three properties. Basically, we want to create a button to delete to be able to delete. Let's just create a new button and we can put x character. For the size, I'm going to set this Q layout to be 20 pixel. For this, whenever we press this button, we want to make sure that we are going to delete the array element of index of i. Here, we want to make sure that if i is equal to the array size minus one, which is the last member of our entries, then we want to create an ad button. The ad button will be only available to the last entries of our spons. Let's just create a new button. And at a plus sine. Let's make the width the same as our button above around 20 pixel. Then when we add this, we want to add new array, just like this at entries. Now we've created this sponor entries. Let's draw that. Let's just run the method entries, and let's just pass our sponor entries serialized property here. Okay. And save this and let's go back to unity, and it's still compiling, but once finished, we can check our spawn manager, and now we have this here. There is an issue here. I forgot to put a vertical layout. For this saw or settings, let's just create a new vertical settings, and we want to close this with A and vertical. Okay. Okay. Let's just go back to unity and see if this fix the issue. There you go. We have this entries. As you can see here, the second entries has the plus pattern, so we can add new entries, and we can also delete each of the entries, and I'm going to copy the value first, but if we delete this, as you can see, we have this add entries button. Let's just paste the component value and save the scene. Let's create a better layout for this. For this horizontal. Begin horizontal, we want to create a box parameter past the box parameter with lower case B. For each of the entries, we want to create a space in between, let's just use I lay out, space, and maybe put a space of five pixels. It doesn't stand so close to each other to each entries. Now let's save this script and once it's compile, we should see an update. As you can see here now, we can see the separation very clear. And the remove button occupy a lot of space here. In order to fix that, we can just here inside our begin vertical where we have this button implemented. We can add a I layout. That space and make sure that the width is the same as our button, 20 pixel. Let's save this. Now, if we go back to unity, you will see that our layout is very tight to the edge here, and we will have the rest for our settings entries. Let's just do the second one, and let's just save this. Now we are going to create a transform gizmo on the scene, so it's easier to set up our spawn position. Let's go back to our player spawn editor script. Here, we want to create a new method and this will be the onsen I. Basically, OnsenI is a build in method and if we want to create something like transform on the scene editor, we need to put it inside this onsen UI. So now we're going to look through our, but our spawner entries. We want to look through that and we can just use the field serious property here and get the array size. Then we want to set its value, each value, each factor three value. We want to get the array element at index of and then we want to find the property relative, and this would be the position. Since we know that son position is a factor three, we can access the factor three value here. Then we can set this two equal I'm going to enter, put a line break here, and then I'm going to access our handles class, and this is a custom treeGI control for drawing in the scene view, and we are going to draw a position handle. For position handle method, it asks for a rotation and a factor three position. We can just set the position here. Let's just get its factor value again and put it here. For the quaternion, we are going to put this quatern identity at this moment here. And save this. Then we want to create a label. There is also a label in the handles class. There's a label method and it asks for position and a GI content. We can just paste the position here, which is our vector tree value. But I'm going to move this slide up from our position. I'm going to put a addition with a vector tree up and multiply this by 0.5. For the label, we can put a string or AGI content if you want to. We are going to put a string and let's just create text here, spawn from with colon full colon space and then I'm going to put a line break here, and then I'm going to pare fine property relative. But we are going to get the previous scene. Let's go back to our player position and copy this previous scene name. And paste this into the fine property relative argument, and then we want to get its string value and then end this with semicolon. This is basically two different lines here. If you go to the end and then press enter. As you can see, this is the first line. This is one line because I didn't put any semicolon at the end here. This is actually a continuous line, and this is also a continuous line here. As you can see, we are concatenating a string with a string spawn form, and then we are adding with the previous name value. Here, We need to also update this realized object on top of it, and then we need to also apply any modified properties at the end. If we save this script, the player spawn editor and go back to unity. Now once it compile, it will show the position of. Our spawning position as you can see here, spawn from city. Now we can move this and if we move this position here, it will update the spawn position entry. We can also modify this gizmo, the z direction we're always facing our saw direction value here. In order to do that, let's go back to our saw editors script and we are going to delete this quaternion identity. I'm going to put a line break here so we can create a new line, so we can see the whole code and then just type quaternion class and then rotation. Here, we are going to put the factor three value, but instead from our spawn position, we are going to grab our spawn direction. It will take this factor value from our spawn direction, and then it will convert it to a quaternion. It will be applied to our handle gizmo on our seam. Let's go back to unity and Now it's compiling. As you can see here, because the z is negative one, so it's facing backward against the forward set. If we set this two zero, this will be the default value. If we want to make the player face to the right direction, relative to screen after spawning from CD, we can just insert negative one as the spawn direction, and it shows that the direction of the player will be facing to the right. This z vector here shows us in which direction will our player be facing. 29. 28 NPC Move Action: Okay. Now, let's create an actions for moving the PC. So basically, this action will allow the NPC to move whenever it gets triggered by the interactables. So let's go to our scripts and actions folder, and let's create C subscript and let's call this NPC move. I'm going to add action MPC move action to its name. Let's open this in so Studio. Now it's open. The first thing first, we need to set the inheritance to actions. It will inherit from this base class action, and we need to implement the abstract class act. Let's just cut this and put this below update, and we are going to need this update method. Since we are going to use the FMS agent, we need to use the Unity engine namespace. Now let's create a couple of fields, and the field will be a private type of names agent. Let's just call this agent. We will also need a cerliz field and this will be a vector tree, and this will be the, the direction, the target position. Okay. And then under the start method. We can just initialize the agent by typing the variable name agent and then using the G component method, and let's search for the Name agent class or component. We have set up the agent using the get component method. Now let's modify our method. Let's create another serious field, and this would be a type of float and let's call this delay, we can delay the action, and for delaying, we are going to create a coroutine. Let's just define one. Let's call this move NPC, and we can pass the float here, the delay. Then we can just delay by using the id return, new wait 4 seconds and pass the delay value or the delay parameters. And then we can just start moving the agent using the agent keyword and then set destination to the target position variable that we've declared on top here and save this. Inside our act method, we can just run the co routine and run the move PC and pass this delay variable as the delay. We are going to use the update method for defining the animation. In order to create the animation, we can reuse the player animation class that we created way before in previous video. Using this class here, this generate class, we can incentiate the class and run the method inside our NPC move action. Let's just create a new private and for the class, it's player animation, and let's just call this PC. On start, we can just initiate create new player animation. Then we can run I think it's in it and ask for animator. Let's just get component in children because for the NPC, probably we are going to put the game object or the visual representation that use animator component inside as a child object. Let's just use to get component in children and let's search for animator. And then close it with parentheses and then semicolon. This is for initializing. Because with the play animation, we don't have we are not inheriting from mono behavior, so the animator needs to be initialized because we cannot use the get component method inside this class here. Save the NPC move action script and inside the update, we need to make sure that we are passing dispute value. Let's just access our NPC and then we can type update animation. Then we can pass the c the agent velocity. Since this is a factor, we can pass the magnitude, but I'm going to use the square magnitude value because it's more performance. Since there are no square root calculation inside this method inside this properties. We don't want to calculate this every frame. Let's just create a, a bullion. Let's call this is moving or we don't need to create a bulon we can just check if the agent is currently stopped or not. But this is for stop and resuming. I don't think we can use this so. Let's just create a new bon. Let's call this is moving, and this is false. Whenever we start moving, we want to set this. We want to set the is moving. Okay. But whenever we arrive at a destination, we want to stop this inside our uplate we can check if it's moving and the remaining distance is less or equal than the agent the stopping distance. This means that the agent already arrived at the destination. Then we want to set the moving back to falls. Okay. Now we have this bulon for checking whether we are currently moving or not, we can put it inside the statement here and make sure that we want to only update the animation whenever it's moving. Whenever we stop moving here, we want to also update the animation. But instead of passing the velocity value, we can just pass a value of zero. We'll make sure that whenever it stop, our speed parameter here will be also zero. Okay. Okay. Save this and let's head back to unity and try this action. Now let's drag our newly created script, which is called NPC move actions to one of the other NPC. For example, this one, yeah. Let's just drag the NPC move actions to that object. There is an error, I think the error is related to the name class because we rename this to NPC move action and the original name is NPC Move. Let's just add actions to it and save this. And a unity. This showed work now. Choose this or instead of modifying this, let's create a new one third NPC, and let's hide this to other NPC. And let's drag this NPC move action to the third one. Now it should work. As you can see, we can add this let's just delete the message action. Since we are copying this from the previous NPC, it has this item action and message action. Now let's drag our move action as actions for our interactable. Now we want to add also a message action. Let's just add a message action. Basically, we can type message. Basically, we are asking for this NPC to move out of our way, and we can direct this message action into our interactable action, so it will run two different actions. Let's set a delay maybe around 1.5 second before the NPC starts to move. Let's move him to the zero and y also zero, but on negative four on the x axis. It will move to run this position or positive for, so it will run this position, if we look at the world transform, the positive sign is to the right side of the screen here. Let's just save this now run the game and click and it will. Now it's working, but since we don't have the Names agent, it throws an error. We need to add a Names agent. And we can just use the default value. For the child object, we can we can delete the cube object and also delete the capsule mesh fielder on the parent object, and also the mesh render. Now we can probably add a model, the tiny people model and go to the prefers folder and we are going to use the male A as a child of this NPC here. Okay. And let's zero out the y position. Okay. And we can copy our settings, the names agent settings. Let's just copy coonent then paste this to the PC, paste the values, and also for the capsule collider, we can copy from the player capsule collider and paste it to the third PC. It will have the same settings. Now we can make sure that the PC is rotated zero on the y axis, it's facing the same z direction as its parents and I also have a controller. For now for testing out, we can use the player animator. Okay. Since we need to access the speed parameter inside the player animation object here, Okay. I'm going to save the scene and try this again. Let's go to player B and. As you can see here, it works very nice, this NPC object. We can also not P object, the NPC move action, and we can also chain the action after giving some item or receiving some item. In the next video, we are going to create a custom editor for this NPC move action. Okay. 30. 29 NPC Move Action Editor: Now, let's create a custom inspector for our NPC move action. First, go to the scripts folder and to the editor folder and I'm going to create a new sub script, and I'm going to call this NPC move editor, and let's open up the script. Have you opens. Let's try to open it again. Now we need to import the Unity editor name space and also change this model behavior inheritance to editor, and also define the target object to be inspected using the custom editor tags, and type off and then another set of parentheses and this will be our PC move action. Now let's just delete this two method. For the first one, we are going to overwrite the inspector GI. And then we are going to also create a void on C GUI. This is for drawing the target position factor. Now, let's just create serial as property and this would be the delay or S underscored delay. So it matched the other convention that we use for cerilized property with this as underscore and then another one is underscore target position. If we go back to the NPC move action, here we can see that we only have two curized field. So, we only need to access this and we want to only draw these two actions. Okay. So now on Inspector, let's create a UI layout, and this would be be vertical, and we want to add a box argument, so it will draw a nice box to it. Then let's end this layout with the vertical method. Now I'm going to draw another layout. But this time is begin horizontal without the box argument, and then another one for ending the horizontal layout. For the begin horizontal. We want to draw the delay custom inspector. Let's just use the editor I and property field, and we can pass the underscore delay. For the label, we can just type new I content and pass the text here, and this would be the Let's just call this action delay. Okay. And we can also I'm going to add a another label. And I'm going to type this sc or we can just say this in second in sec Okay. But we haven't initialized this, I forgot. We need to create a void on enable method. Let's just search for this as delay under the serialized object, find property, and this would be the delay because we name this parameter or variable delay in the move action here. Okay. And for the serialized target position, we need to search for the property that are called target position. Like this, we initialize this. Now we can use it right away. For drawing the target position, we don't want to draw the editable, but we want to draw a read only field. Let's just type editor layout and then use a factor three field and ask for a factor three value. We are going to use the target position. But we want to grab its object reference value. We also need to insert a label. Let's just type target position like this. Shouldn't be object reference value, but the vector three value. K. Yes, we won't be able to edit this factor three value. But we want to edit the factor three value inside the s GI just like the players pawn editor. Here inside this sin, we want to access our S target position and it's factor three value. Then we want to use the position, and we want to pass the vector three value inside this handle, so it will modify Then for the rotation, we want to set this to tern and identity. Then we can draw a label. Let's just draw a label, and we can pass this factor three value, and for the label. Let's just use a string text, and this will be the target position. Or we can add NPC target position, and end this with the semicolon. As usual, since we are dealing with civilized property, we need to update the civilized object on start on the beginning of inspector GI and also apply any modified properties at the end, the saving goes with our ons I. We need to update this and then apply any modified properties at the end of the method. Let's save this and let's head back to unity. Since we are not using this name space, we can safely delete this and save the editor, the editor class again. Let's go back to unity. I'm going to select the third NPC here, and one it's finished compile, I have this custom or for the NPC. As you can see, we cannot modify this target position. But if we move this gizmo here, it will update our target position. For example, if the character will move to this position here, we can test this by playing and then if we try to talk to this character, he will go to this position here. Okay. Okay. So this should do with the custom editor for our NPC move action. Okay. 31. 30 Interactable Custom Editor: Now, let's create a custom editor for our interactables, because it's still using the default inspector and we already defined the action how to draw actions array. Let's just use that and create a custom editor for interactables. Let's go to our scripts and editor folder and then inside this folder, let's create a new CS script and let's call this editor Okay. Then let's open this up in fico Studio and let's import the Unity editor as usual. Also, change the mono behavior, inheritance to editor, and also add a custom editor tech to access the inspected object. And this would be the and say this. And we are going to create a serialized property, first. The first one would be the actions as underscored actions, and the second one would be the distance position. Since if we open our interactable class here, we can see that we have two serials field, which is the distance position and the actions. So we need to create those reference in the editor script. And then we need to create a un enabled method. Inside this, we can just search for the serialized proper field by accessing the serious object and then find property actions. And let's make sure that it has the correct names. Yeah. Okay. And for the distance position, let's just search for the distance position property. Now, we are going to create an override for the uninspector GI. Basically, what we need to do is we need to make sure that we update this realized object on the start of the method. And then at the end of the method, we apply any modified properties. Okay. Let's create a layout, begin vertical, and this will be we put a box argument inside the parenthesis, so it will create a nice box layout and then close it with a G layout vertical. Now we need to draw two different property. The first one would be the distance position. Let's just create an editor I layout, and then the property field method. Then we can pass the as distance position. For the label, we can just type I content and pass the string inside the argument here inside the parentheses. Let's call this distance position. And then we are going to use the editor extensions that we've created, and we are going to use this row actions array, and this as for a serials property actions array, which is our as underscored actions. Let's just type that. Then for the label, we can just call this actions. And then close it with a semicolon. Now if we save if we save this editor script and go back to unity, this will update our interactable. Let's just select our third NPC here. Now we can see that our interactable has a very nice custom inspector working, and we don't need to create complex coding with the actions array anymore because we already defined this in the editor extension. So it will draw it the same way like our previous actions array on other classes. Okay. 32. 31 Entity State Concept: Okay. Now, I'm going to explain first how we create some sort of a state for every object in this point and click games. So basically, for any entities such as NPCs or players or anything, we are going to represent this with an EmpS one. For example, if we have an PC and we are going to build that PC with a couple of CL in it. For example, the first one will be an empty game object and this antame object will have a as items component and also intractables, and also the needed components such as collider for clicking detection, and whenever we click it, it will ask for items. Then another antigam object will have a different actions, which is a message actions, and this will only be enabled whenever we give the items, then the PC will say tanks. And another example, if for example, if we deny the items, then the NPC will curse the player or we'll say some bad things. All of this object here will be an empty game object and it will be a child of this NPC one. Each of this object will have its own collider and its own intractable. But the first ig object, we have a item actions. The second one will have a message action, and the third one also a message action. Of course, as any other object, NPC will have positions and rotation recite in the transform component. We are going to save all of this information, the position, the child object into an entity data. This is a custom class that will hold all of this data for the position on a rotation, it will hold the vector values and the coon values. For the object, it will only hold the active or enabled status value, and this will be a type of bullion. If it's enabled, then the activate status will be true and if it's disabled, it will be false. Okay. And why do we hold the bullion data or the enabled data, the game object enabled or not? Because when we give, for example, if we go to the NPC and then the NPC as for the items and then we give that items, the as items, then we are going to disable the first game object, the first child game object, and then the second sorry, the third child game object. And we will leave the second game object to be enabled. The next time we try to talk with this NPC, the NPC will repeat this tanks message. It will not reset. For example, if we leave the scene and then we go back and then we meet this NPC again, then the PC will still say thanks because we are going to record the state of the child game object. For another example, if we go to the NPC and then the NPC asked for the items and then we refuse to give the items, then the first game object and the second game object will get disabled. Then the third one will stay enabled. When we talk to the NPC, then the NPC will curse or say bad things to the player. The same goes, if we leave the scene and then we go back to that scene. Since we save this condition into an tide data, then when we start the scene, we can load the data to the NPC and the NPC will still say the same thing. There is basically a safe entity state works. In the next video, we will try to implement this feature. 33. 32 Entity System: Okay. So now we are going to create the entity safe system or entity data system. And let's create a new folder inside the script folder, and this will be the entita we are going to create a custom class, and let's call this entity data. Okay. And for the folder, I'm going to rename this to entity system. So it explains or describe the class inside this folder better. So let's just rename this to entity system. The next thing we need to create a new interface. Interface is basically like a class, we can inherit from this interface without sacrificing the mono behavior inheritance. It's a different inheritance, but it's not a class, it's an interface, and you'll see later, I'll explain it. Let's call this I savable because by standard convention, worldwide convention in C sharp, whenever we declare an interface, we use the letter in front of the interface name. We will know that this is an interface, and let's just open this entity data first. We need to create a new couple of public variable. The first one would be the float, and this is the position for holding position data. Let's just create three different folds. The first one is x, y, and z. The next one will be for the rotation. This will be the Q, Q, Q, Q x and Q, and then Q z. The other thing we need to create is we need to create a dictionary. This will be a dictionary, and for the key, we are going to use an integer and the integer will be the index of our child ant gave object, and then the second one would be a bullion, and this will be the active status, whether it's enabled or not. Let's just call this child active status, and let's declare this. For this class, we are going to make sure that this is a public class and we want to mark this serilizable so we can save this data and since we cannot serilize factor tree and quaternion, we need to break those value into this float here. That's why we create a couple of float variable. Save this and now we need to create a couple method. The first one is to save the position. Let's just create a new public fit and then we can call this set position and we can pass a factor tree as a parameter. Since we want to save the vector re values that we pass here as a parameter. We can just type the x flow here, and we want to store the position x and the y, we want to store the position for the z, we want to store the position like this. The same goes with our quaternion, create a new public fit and this would be a rotation, and it will ask for a quaternion. Let's just call this rotation. And now we can just pass the rotation y rotation to the Q float. Then for the Q float, we can store the rotation dot x and the same goes with the Q, we can pass the rotation. And for the Q z, we can pass the rotation. It works the same like the position, but with position, we only have three components with rotation we have four components, we want to also get position and get rotation method. Let's just create a new public for getting the position, we want to return a vector. Let's just type vector for the return type instead of void. Then we can call this position and we don't need any parameter for this. We can just type return, and then Set a new vector three value and we can pass our x and our y, and z vector three component values like this. For the get rotation, we need to create a new public method, and let's just return the type quaternion here and let's just type rotation. And we can return a new quaternion. Here we can pass the x y z and the W value. Let's just pass that. First would be Q x and the second one would be Q and the third one would be, and the fourth one would be QW Now if we save this, we have this custom class, and now we can just delete the unused name space here. We have defined this. Now, let's define the interface. We cannot use this yet because this is custom test and we are going to use this object in the other script. Go back to unit. I'm going to open the interface. For this interface, we want to delete using namespace, and then we want to delete the meno behavior also and also the method inside. We want to mark this save as interface. For this interface, we are going to create two method and the first one would be safe, and the second one would be load. We cannot we can only declare the method name, but we cannot declare what's inside of it. But other class that derives from safe must implement this two method. Let's rename this safe state, so it describe better the function, the method, save this. Now go back to unity, we are going to create a new C subscript. And let's call this safe entity. Okay. And let's open this class here, and we want to implement the savable. In order to implement the interface, we can just type a comma after the inheritance, keyword, the mono behavior, and then type the savable. Now it throws an error because we don't implement interface members, so we can just try to implement interface and it will create new implementation here. Save this. We want to create a new cerlize field and this will be type of string, and this will be the instance ID. And let's create a new private entity data. Let's just call this entity data also with case, and then we can just initiate the entity data like this. We want to create some sort of a unique ID for this instance ID. So what I'm going to do is I'm going to create a reset method. In this reset method, we want to fill our incense ID with the game object name, and we want to join it with the game object, get incense ID. Why do we put this inside the reset method? Because if we put it on the reset method, when we add this script to an object, it will generate this automatically, and we don't want to change this actually. Currently, I'm tag this as serialized field, so we can see it on the inspector, but later we're going to hide this from the inspector. Okay. Let's save this safe entity here and let's go back to unity. Now let's add this safe entity component to the player. As you can see here, once we add it, it generates automatic instance ID to the safe entity. In order to make this safe entity works, we need to modify our data manager script. Let's just open our data manager here and we are going to create a safe data, first, a public class for saving data. Let's just create a new public class here below, and let's just call this safe data. Then let's mark this safe data serializable. We need to access the system namespace and then type that serializable. Safe Inside the safe data, let's create a new public dictionary, and for the key and value type, the key would be a string, and the string will be the instance ID of the safe entity component here. It will hold reference for each of the object with this unique instance ID. Then for the value, it would be an entity data. With this entity data, we are going to hold the position, the rotation, and also the child active or inactive status. Let's just call this entities data, and let's initialize this. Now that we have this safe data, we need to create a reference under the ta manager. Let's just create a new private and this will be the safe data. Let's call this also safe data with lower case as. Let's initialize this. Now we have this safe data. We are going to create a couple method for saving entities data and also for loading entities data. Let's create a public method. Let's call this safe entities. And the other method would be void load entities. Now we have this two method. For the load entities, we should return an entity data. Let's just change the void here to entity data. For the safe entities, we need to pass a ID and the entity data itself. Let's just call this data. For the load entities, we need to find it by accessing the ID. Let's just pass a string ID for searching. K. We are going to check if our save data entity data contains key of our ID. If it contains, then we want you to overwrite that. Let's just access the save data again, entity data, and then we can pass the string key inside this square brackets, just pass the ID, and then one to overwrite this with the data that we are passing through this method. Let's just set equal to data and then run a return. And if it's not contains then else, we want to save or we want to create a new entry into this entity data. Let's just type and pass the ID and also the data for the value. For returning the entities or loading the entities, we can return. We can just check if the save data and entity data contains key of the ID that we are passing, then we want to return that value. Let's just return We can just copy the save that data and then pass the ID to the square brackets here, so it will return whatever data that we have with this key, and then else, we can just return, no. Save this. Now we can save and load entities from our safe entity component. Okay. Now, let's just do that for saving, we are going to modify the save state part first. For saving basically, we want to save the child status and then also the position and the rotation of our game object that holds this component. Let's save this entity data and we can run the method set position, and for the set position, we can pass a vector tree. Let's just pass our transform that position. And for the rotation, we can set the rotation. And then we can also pass the transform rotation. Okay. And before saving and setting the position and rotation. We want to clear the entity data. So let's just type the t data keyword and then let's initialize a new entity data. And then we are going to look through our child object. So let's just access the transform the child count, and we want to save the enabled status. So we can just access the entity data. Okay. The child active status and we can add a new entry, and then we can add the as the key because the child count or the child member will start from zero to it depends how many child this game object have, and we can pass those value via the i integer. Then for the Boulan status, we can access transform and then get child and then pass the index here, and then we need to access the game object and get the active hierarchy properties and this will return a bullion, and this defines whether a game object is active in the scene or not. Let's just pass this value, and this will record the active status. Once we've created all of this, we want to push our entity data to our safe data. Let's just access the taminger instance and we can use the safe entities method, and we can pass our instance ID, which is this unique ID that we have when we are adding this component to the game object. Then we can pass the entity data that we have just previously built here. This will save this data to the safe data object on our data manager. For the load state here, First, we need to load our entity data. We are going to get the entity data by typing the entity data variable itself, and then we want to get this from our data manager instance. Then we can use the load entities and this will ask for a string ID. We can pass the instance ID that we have here, and then we can check if it data that is Then we want to return this method. Don't go further and if it's not no, then we are going to access the code below here. So if the does contain some data, then we want to get its position by feeding to our transform position and we can just access the transform position and then we set to the D get position. For the rotation, we can do the same transform the rotation, and then we can get from the entity, rotation. For the child object, we are going to look through our child count. Let's just transform the child count, we are going to access the child index of the game object, we want to access the game object because child will return the transform. Then we want to set act based on our entity data. And the child active status, and we want to get the integer as the key, and this will return the bullion status that we saved before. Let's cose this with semicolon. We can just remove the update method. We don't need this update method on our entity save. To test this out, we need to create a event a public event on our data manager and public event, we are going to use this in the final game also. Let's just create that the event would be a public event and the type would be a system that action. And we can call this on save, and we can create a empty delegates. So It would be safe to run this event in this data manager. Even though if there are no other component or other classes that are subscribed to this event, we can still run it for the other event, we need to create system action, and this will be the unload and let's just also create an empty delegate for it and save this. Now we have this two event. We can create some sort of di method on how to save load, for now, I'm just going to create a FoI update method and this method update will have a input key action, and we want to use for example, for loading, we are going to use the keyboard, L. For saving, we are going to use the keyboard character as on the keyboards for saving. Now inside the input, get keyed on key code L, we can run the load. And for saving, we can run on save. We have this created. Now, because we already created the event, we need to go back to the safe entity, and we need to subscribe both the safe state and load state method in the safe entity class onto the unsafe and unload event that we defined in the data manager. In order to do that, first on the start method, I'm going to subscribe by typing the data manager, that instance, and we can access the unsafe and whenever unsafe is happening, we want to run the safe state method like this. To subscribe a method to an event, for example, the safe state, we need to search for the event first and then we add a plus and then equal sign and the method name. This will subscribe this method name to this event. Whenever the data manager run this event here, this method here will get triggered. Let's just copy this line and paste it as a second line. Then for the second line, we are going to change this to unload and this will be the load state. But we need to unsbscribe whenever this object is destroyed. This is for initialization when this object gets created in the. When it's destroyed, we can access the built in method, which is called destroy. Once I close this, it turns to blue. This is a built in method that unity provides, and we can just copy this line here. Then instead of adding with a plus sign, we change the plus sign to the negative sign, we unsubscribe this event. This method will unsbscribe itself from this event. This will prevent a memorial leaks or an error if this object gets destroyed and somehow the data manager running unsafe. I will cause issues if we don't unsubscribe. Now we have set things up. Let's go to unity. Okay. And let's add the safe entity to the player game object and to the PC game object here. So, let's just add this safe entity, and save this now let's test this out by running then we can move to this area here. Now I want to save the state of this two object here. I'm going to press S, and this will run the unsafe event, even though we cannot see anything, it's okay. Let's just test this then now let's talk to this person and the person should move. Once the person move, let's press L and C, you can see that our object gets loaded. But since the agent has a destination a previous destination, it tries to move to that point. Now in order to fix that, we can access our NPC move actions, and also the player which is on the script folder and the player script, and we want to set a stopping status for the agent object or the agent variable. Whenever it's not moving again here for the NPC move animation, we can set the agent is stop This will stop, even though we load a different position using the entity eta. It will stay stop and we can copy this and whenever we are moving the NPC, then we want to set this two false. We want to move the agent again. For the player script, we want to also do that. For the player script, we want to set the agent is stop when we arrive, so we can use this method that check if arrived Here we can check if the agent is stop is false. We can add an exclamation mark in front. It's not stop, currently is moving, and then we want to check if arrived, then we want to stop the agent. Let's set the stop value to true we want to set this false again whenever we start moving. We can just put it here. Before we are setting the destination, we can set this theory set this back to false. And this should do the trick. Let's go back to unity and test this again. I'm going to save this state now, and then I'm going to talk to this NPC here, and I will move and I'm going to move to this position. Then let's try to load this. Now when we load this, in its position and we can again and it will move again if we load the state again, it will load again. Okay. 34. 33 Trigger Interactable: Okay. Next, we are going to create a trigger in component. And because so far for interaction, we only have this interactable. So let's just create a new CH script on our scripts folder. Let's call this trigger in. And let's open this. Basically, the trigger interact will be a component and it will trigger an action whenever a certain object with a certain tag enters the trigger of that object or exiting the trigger. We are going to delete the start and the update method, and let's create a serial field, and this would be a type of string let's call this selected tag. For the next series field, we are going to create an array actions. Okay. And this would be the enter action. Okay. The next one would be the exit action. Let's just copy this line here and paste this here, and this would be the exit actions. Basically, what we are going to do is we are going to create the fit on trigger method. For this method, we are going to look through the interactions. Let's just create a four loops through the interactions length, since this is an array, we are using length. And I've decided using array because we are going to set the actions on the inspector. The difference between array and list. With ray, have a fixed member on run time. But with list, we can add and delete member on run time. Array should be faster if we don't need the ad and delete member feature. Let's just look through the interactions based on the next of i and then run the method. And we can copy all of this method here and paste this below and change this to trigger exit. For the exit action, for the untrigger exit, we can just copy the exit actions, and then paste this as the array that we are looking through. Another thing we need to make sure is we need to check if the tag is the selected tag. So we can just check the other objects that are being passed by the untrigger enter method and search for it tags and we can get from the string here, select the tag, and if it's not this tag then we want to return the method, so it will not run this. Let's just copy this and let's paste this and the same goes with the trigger it. If the other game object doesn't have the selected tech, then we won't run the action. Let's save this trigger interact, and now create an object or we can just modify any object that we have. Let's just modify this cube here, and we can set the trigger B enable, and we can add the trigger interact method. And we can type the tag that we want to detect. In this case, which is player, and we can add a message action for testing and add message and we can just type player hit or player triggers the que direct this to the inter action, so it will gets added to the action and save the scene. Okay. Now if we walk through this point here, the player will avoid because it creates a hole in the F mesh. Let's just duplicate this cube game object. And then direct this to be outside of the environment and put it somewhere where we doesn't have hole in the scene here. For the cube one, we can just we can set this back to not trigger and remove the trigger action and remove the message action. Let's try this again. If we pass through here, it so Let's just check what is actually happening. Apparently, I forgot to put a rigid body on the player because the player has a collider and this cube also have a collider. But in order the void on trigger enter or void trigger exit method to be recognized or to be executed by unity, one of the objects that are cliding needs to have a rigid body component. I'm going to add the rigid co body component to our player, and we are going to disable the use gravity and enable the askinematic option. It will not act like a physics object, but it still have a rigid body component attached to it to detect cohesion. Now if we try this, it should work. Let's go to this point here. When the player passes through this box, it will trigger this message. So, this is for the trigger action, and we are going to create a custom editor to make setting up things with the trigger interrat easier. 35. 34 Trigger Interact Editor: Okay. Now, let's create a custom inspector for the trigger interact component. So let's go to the editor folder and let's create a new CHAR script, and let's call this trigger interact editor. Okay. Let's open this script, and we are going to import the using Unity editor. Also change the mono behavior to editor, always when we are creating an editor script and forget the semicolon here, and add the attribute custom editor and target the script or the class inside the type of statement here and just type the class that we want you to inspect, which is trigger interact. And then we want to create a couple of serialized property. Let's just type the class serialized property, this would be the inter actions, and I'm going to name this as underscore inter axions and for the exit action, it should be as underscore exit actions for the tag we want to name this underscore selected tag. And now we can just delete the start and update method and just create the unenable first to initialize the serialized property. Let's just type the serials property, and then using the serialized object, we are going to use the fine property method and we need to pass the field names, which is enter actions with lowercase and uppercase A. Then I'm going to copy this line here, paste this twice, and for the second one, I'm going to change this to exit actions. Also I'm going to search for the exit actions. Okay. And for the third one, it should be selected tag, and let's search for the selected tag field. Okay. Now let's create an override for the un inspector GY, and we can just delete the base method here. On the beginning of this method, we want to update the realized object if there are any changes, and at the end, we want to apply any modified properties if there are any changes also. We want to draw actions array. Let's just use the editor extensions and use the draw actions array. Then we can pass the actions array, which is the enter actions. Okay. And for the label, we can just type this trigger enter actions. And we can copy this method, this line and change the second one to the exit actions, and let's just rename this to trigger it actions. Next, we are going to create a custom tag field, and this will be a drop down and it will list all of the tag that we have on our project. Instead of typing like previous videos, we can just use this editor I layout and use the tech field method. A for a string, We can pass this is property, but this is not a string, it is ers property, so we can just pass this inside here and then get the string value. We can add a label before. I'm going to add coma here and as the first parameter, I'm going to create a label. Let's call this trigger tag. But we need to put this inside a string value. Any changes that we change in the tag field, we'll get assigned to this string variable. Let's just copy this as underscored selected string value and put in front of the editor L and then add an equal sign. We will assign any changes in the tag field to this selected tag string value. Let's this semicolon. Then now let's save this trigger interact editor. If we go back to unity and we select the cube object that has the trigger intra component, we will see that it has a custom actions array editor, and then it has a trigger tag. We can browse the tag that we have in our project, and this is quite neat trick instead of typing a tag because with typing text, it can cause an error and this will list, so it's easier. Okay. 36. 35 Camera Manager: Now we are going to create a camera manager and this camera manager will handle camera changes or camera switches whenever we approach a certain area and we want to switch camera, this camera manager will handle that. Let's go to the script folder and the manager folder and create sharp script, and let's call this camera manager. Now, once it's created, let's open this into So Studio. First, we want to create a static reference since this is a manager. I'm going to create a new public static and the type would be our own class. I'm going to call this instance with capital because this is a property. I'm going to set this to a public but a private set. The next thing we need to declare is we need to create a event a public event, and this would be a type of action. But we want to pass a argument to this event. We need to define a class or a type of here inside the angle bracket. I'm going to pass the camera. I'm going to call this on camera switch. I'm going to assign a empty delegate for now. To this event. So we don't have to check if this event has a member or not or has any subscriber or not. We can just simply run it whenever we need to run this event or trigger this event. We also need to create a list public but a private list, and this would be a type of camera. We can call this all cameras on scene, and let's initialize this and also a public properties for holding the arn camera. A is called this arnmera this will be a type of type, we'll have a public getter and a private setter. Now we are going to create a k method. In this method, we are going to initialize the instance properties to this script instance. This type instance equals this. On start, We are going to set our on camera to the currently active camera. In order to get the active camera, we can just access the camera class and then type dot main. This will return the first enabled camera tag with main camera. The camera object has to have the tag of main camera. We will also need to grab all the camera on scene. But the problem is if we try to use the fine objects of type, this will return a list of all loaded objects. The object needs to be activated and if we use the fine objects of type, this is deprecated. Let's create our custom extensions for finding object of certain type, whether it's active or not. Let's go to unity and open our extensions class. Now we have this extension class open. We are going to create a new public static and this will return a list type of generic T, so we can use any other type or classes to use with this method and we can create fine objects of type and pass the t degenerates again and close this with parent to Let's create a new type of t, and this will be the result and initialize this. Now we need to import using Unity engine scene management because we are going to access our current scene. Also, we need to import the system link because we are going to use a two list method and this is provided by link. Now we want to search in our scene, all of the object that has camera component attached to it. We can access the scene manager. And then get active scene. Then we can get root game object, and we'll return all the root game objects in our scene, and this will also return an array type of game object. Then we can convert this to list Once we convert this to list, we can look through each of the member by using the four H method and then pass the action inside this four method. Here, we are going to use a Lambda expression. Basically, we can use any name, for example, g or x or H, and this will be the representation of our game object. I'm going to use a G letter, and then I'm going to add an equal sign and then write arrow sign. Then here, We are going to access our result list. Then we want to add range because there are many multiple objects that have camera components attached in the scene, we want to make sure that for each root game object, which is G, we want to search, get component in components in children with plural here. And search the T degenerate type, and we can close this line with Smc and then once we already search and we return every object that has a type T component attached to it. Later, we can change the t with certain classes that we need to find. Now, let's just return our list result. Return result. Okay. If we go back to the camera manager, now we can use the editor extensions to search for all of the camera game object in the scene, and we want to store it into the all cameras on. Let's just type all cameras on scene and then equal editor soil editor extension, extensions class and then we want to access the fine object types of all. Then we want to pass the camera class and this will be the class that we get searched by defined object type of all and safe this. For example, we can test this out. Let's create a new empty game object in unity. I'm going to put this below the spawn manager here, so we can see it together all of the manager and change this to camera manager. Okay. And then we can add the camera manager class to this game object here. Let's just direct this and let's open the debug and we can see whenever we run this, we can see that we fill this cameras scene list. So for example, if we duplicate our camera, two times, and then we activated the second and the third camera. If we go to the camera manager, and let's save the scene, If we press play, Okay you'll see that we will populate the all cameras on scene. Even though this object is deactivated. We can easily search object, whether it's activated or not with this method and it will grab this camera. We need to activate only one camera because we want to make sure that on the start of that scene, we are viewing the scene through or that first active camera. Now we see that the extension method is working. We can continue to create our camera manager. Now we are going to create a new public method. And this will return void and we can call this switch camera, and it will ask for a camera to be switched, and we can just call this camera parameter cam Let's look through our cameras on scene list here, and we are going to disable all of the camera Let's just type the camera on scene and index of, and then we can just set act or access the game object and then set active to false. This will disable all of the camera. Once we disable the camera, we are going to activate the camera that we pass through the parameter. This way, we will make sure that we will switch to this selected camera or this pass camera to be the only camera that are going to be activated at that moment. Let's just access the game object, and then run the set active method and set this to true. Once we change the camera, we want to also change the current camera To the past camera here, the came here. We will change the current camera to the new camera that we passed as a parameter. Then we want to run the event that we've created on camera switch, and we want to pass the new camera to this event here. You may ask why do we have to create this event? If you remember, we can open our player script class here. Let's open the player script. Okay. Let's go back to the camera manager. Here, whenever we switch the camera, we are triggering the on camera switch event, and if there are any subscriber to this event, it will receive this event and it will run a certain method. In player script, we have this main camera variable, and it's store the main camera that we have in our scene. We need this camera variable to detect the click position from the screen to the world position. When we change the camera, we need to change this also. That's why we are creating this event. The player script can subscribe to that event. Okay. Let's create a new method, and let's call this camera switch. This will know when camera is switched, and we need to pass the camera here whenever these functions get executed, we want to change our main camera to the cam that we pass here. Basically, we are not passing any camera, actually, but on start, When we subscribe this event here, not camera, camera manager, instance, and then we access the on camera switch event. When we subscribe the method, which is the camera switch to this event here, as we can see here, the event is passing a camera as a parameter. So when we trigger the event, we are passing this camera, this new camera here, and the listener, which is the player script, we receive that camera and it will get passed to the argument here. So we will know when the camera is switched and we will also know the new camera and we can assign this new camera to the main camera. So when the main camera is changed, then it will also affect our click on click method here. So click will register from the correct camera. Okay. So now, I think that should do, but we need to make sure that on destroy, we remove the subscription. So there is no any error, any unwanted error. So we can just change the plus sign to a negative sign and save this. Okay, so. Yeah, that will be all for the camera manager. As of this moment, we cannot test this yet. Because we need to create a camera switch action. We are going to do that in the next video. 37. 36 Camera Switch Action: Okay. So we already created the camera manager in the previous video, and now let's create the camera switch action. Let's head to the scripts folder and then actions folder and then create a new CSA script, and we are going to call this switch camera action. Let's open the class here. First, we are going to change the inheritance from mono behavior to action, and it will ask to implement this override abstract classes. Let's just implement that we can just remove the start and update method. Let's create a serialized field, this would be a type of camera. Then we can just call this camera to switch. And we can just delete this system not implemented action exception. Now we can access the camera manager instance, and then we can run the switch camera method and we are going to pass this camera to switch as an argument to the switch camera method and save this. Okay. So yeah, This is the script. It's very short and save this. Let's go back to unity and test this out. In order to do this, we are going to use this box collider, and let's delete or just hide the mess render for this moment. And then we are going to delete the message action. Let's change the collider size to be t bigger. And let's move to around here position. We are going to delete the third camera here. But for the second camera, we want to set an angle, something like this. Let's just press the second camera and then hold control Shift F, and it will position that came to this position. And if we select the third cube here, the cube with the trigger in component, let's add the switch camera action, and we need two action because we want to switch between the first and the second camera. Let's just add a trigger axons and a trigger exit actions. Make sure the trigger tech is clear because we want to make sure that the trigger interact only correspond when a player enters the collidor. For the switch camera action, direct the first main camera, and we want to direct the second main camera to the second action. When entering this box of trigger, we want to set the second camera to be the current active camera. Direct this switch camera action to the first slot, the trigger ter actions, and dirt switch camera action to the trigger exit. Whenever we're exceeding this trigger, we want to switch back to the default, this one here. Now let's save this scene and now test this out. We can move here and if we go to this area here, it will switch the camera. As you can see, our mouse click is working because we are switching the camera and also we switch the camera reference inside the player script. Now we have a very nice switching camera action. 38. 37 Inventory UI: Okay. Now we are going to create an inventory UI system to show the item that we have in our inventory. Let's go to the D here, not the game, the D. Let's enable this. And we are going to start to create the UI system for the inventory UI. Let's just focus to the base canvas. Let's create a new empty and this will be the inventory. And I'm going to stretch this to the size of the canvas, so I'm going to hold L on the anchor preset and then choose the bottom right preset and it will fill out our canvas. Then I'm going to create a new child image. This would be the inventory UI panel. Let's make this around 900 by 600 Okay. And I'm going to change the color to black and make this also transparent around 0.5 on the alpha value. Okay. And then we want to create a new empty child, and this will be the item layout. Let's stretch this to the size of its parent, which is the inventor UI panel. Then I'm going to add a margin on each of the side here. Let's set this to round 40 on left top, right, and the tom margin, it will have margin. Let's put a grid layout group. Save the scene. Let's create a child object, which is a button, and let's duplicate this button. We can see how the button is going to be lay out under this item lay object. Now let's set up the item layout. We are going to set spacing, both to be set to 25 on x and y x. If we add so many button, it will look through this item lay out and we can select the item lay out, and let's set this to start corner left axis horizontal, the child alignment. Let's set this to middle center. It looks better. It's centers just delete all of the button here and we can keep item. But I'm going to change the item ladle center to upper center, so it will stay on the top side here, but centered. Okay. Now we are going to set up this button as a item UI. Let's just delete the text object. For the image, let's just set this to none, so it's wide let's rename the button to item UI. I'm going to create a text mesh pro object as a child and let's just set this here on the buttom anchor. And change its size to a very small one, perhaps a 150 pixels by 30. Let's just change the text to something like x01, so we can see for multiple object, we can show how many items that we have with this text and change its color to black at the moment, and just set this size to be enabled. We will see it like this. I think I'm going to change the item you cell size to round 150. We have a bigger item UI. Okay. Now we have set things up here in the scene. We are going to create a new script for handle this inventory UI. Let's create a new folder under the scripts folder and I'm going to call this inventory UI. The first thing we are going to create is the inventory item UI. Okay. Let's open this and we are going to declare a couple of variables. I'm going to paste the variable that I've already declared. Basically, we need to import using the unity engine UI. Here, I'm going to table this line first. Basically, we are creating type of item to hold the item data for this button. Then also, we are creating a variable for holding the button component because each of the item UI have a button component, and this will allow us to press on that item and to see the description. This is for showing the amount text and the type would be the text match pro G Later, we are going to enable this. Basically, this is the parent system UI that will insaniate all of this item UI layout and handle the connection between updating or redrawing the item whenever there are changes in our item inventory. This will handle that. This will the item image and the item image is the image component that lies on this button also. This will change according which item do we have currently in this item variable. Let's delete the It start and update method and we are going to create a new public void and this will be called in it. And for initialization, we are going to passing the item, and let's just call this item. Later, we are going to pass the inventory system UI, but we haven't or maybe we can just create the script. Let's just go back to unity and let's create new CHR script, and let's call this inventory system I Let's open this also. Now if we remove the comment, this should be available because we already created a class with this name here, and we are going to pass that also. To this argument and pass this. We can just call this also inventory system. Now, basically, we want to set up the button or the UI appearance from the information that we have on our item. First, let's just fill this item variable with the item that is being passed. We want to also fill the inventory system that we have here. Let's just type, this inventory system. This will revert to the inventory system that we declared in our class because we use the same name as an argument or as a parameter. We can just fill this with the inventory system from our parameter here. We will also need to initialize our button. Let's just type button, and then fill it with get component and the type will be button and it will search the button on the game object that hold the script. Also for the amount tax, we want to search for the text object. But since the text object is a child, then we are going to use the get component in children, and then just type class of the text mesh, which is the GI and then now we are going to set things up. We are going to set the item image sprite to be our item sprite. In this item class here or variable, we already passed the item that we are initializing, so we can get the items right away. We want to enable or disable this text object depend on this item, allow multiple bullion setup. For example, we can just type game object set, and then sat active for a bully and value. We can just pass this item, allow multiple. If we don't allow multiple on that item, then this value will be false, then this object will get the activated. But if this item that allow multiple is true, and this will be enabled. Then we can also set the amount tax value to be x space out space will be fine. Then we can grab this item amount, and this will show the text how many items that we have currently. This will be all for the inventory item UI at this moment, and we are going to modify this later. Now let's go to the inventory system UI. Now let's create a variable. The first one will be a type of transform, and this is for the item layout, and let's call this items parent because all of the item UI will be parented to the subject. The second one would be the prefabs of our inventory item UI. Let's just type the class here, inventory item UI. Let's just call this item UI prefs The third one will be our inventory object itself and it is a class of inventory. Let's just call this player inventory, and we will direct the scriptable object to the slot here. The last one is a private, and this will be a type of inventory item UI. All of the item UI that we instantiated during runtime. We are going to put it inside this list here to keep track, things. Let's call this item UI collection and initialize this. Let's delete the update method. On start, we want to disable this object right away because we will put the script on the inventory panel. Let's just type game object seductive to false. And let's create a new initialized method in it. And in the init method, we want you to pass the list item, and let's just call these items. And we want to look through the items that we pass here. Let's just type items.com. For every iteration, we want to create the item UI prefabs. We want to instantiate it. To make that easier, let's create a new method and let's call this at item UI. We want to pass the item data item class and let's just call this item. Basically, we want to create a temporary object inventory item UI, and let's just call this item. Let's instantiate a new item UI prep here. Let's just type item UI for the transform parent, we are going to pass the item sparent This way, we will incentiate the item UI prefs, and we will keep the inventory item UI component reference to make it easier. Once we create this, we can access the script, the inventory item UI, and then we can run the init method, the public it method that we've declared here. Let's pass the first parameter, which is an item. For the second one, we want to pass this class here, this script here, the inventory system UI. Let's just type this Okay. And then we want to add created object to our item UI collection. Let's just access the item, UI collection and then type add method and we can insert the inventor UI item that we have just created, which is the ten item. Now that we created this, we can run the method and then pass the items. And since this is a list of items, we can just type items index of. It will look through our item. Okay. Now, we already created this init function method. We can run this by typing the it and then we need to pass the list of items inside our player inventory. But we haven't exposed that yet. Let's just open our inventory script, go to unity. Then under the descriptable object, let's open the inventory class here. Now, as you can see, we have this list item is inventory, but we don't have a public getter. Let's just create a new one. Public geter this will be a type list of item. Let's call this inventory with capital I, and then we can just set together and let's just return the inventory inside this property. We cannot use this keyword because it's the same with our class. Let's call this inventory or we can just call this get inventory and save this. Let's go back to the system UI. Now we can initialize this by getting the list of items that we have inside our player inventory. Now it will look through the list of items that we have in the player inventory, and it will create new item UI based on those items. Now we need to create an event inside our inventory scriptable object and this will be useful if there are any changes inside the inventory and script can subscribe to that event. Let's just create a new public Event, and this will be type action. Action is for encapsulating a method. And list of item would be the parameter of this delegate encapsulate. With this, we can subscribe a method to this event. Whenever we invoke this event, we will need to pass a list of item as the parameter, and all of the event subscriber will get triggered and receive the list of item passed by this delegate. Let's call this on item change. And we are going to initialize this with an empty delegate. So let's just type delegate. Now whenever we add item, let's just run this on item change on item change and pass the inventory here that we have pass this and close this. I'm going to copy this line after we copy this, we want to also put it inside the modified item amount. Let's just put it here before we are returning from the four loop and then put it also here. Whenever we add the item, after adding the item, we want to on item change also. After we made changes to the inventory class, let's go back to the inventory system UI, and we are going to create a redraw method, and let's just call this void redraw. We need to pass a list of items as an argument, and let's just call these items. We want to subscribe the redraw method to the on item change event that we have on the inventory class. On start, let's just do that. Let's just access the player inventory, and we will have this on item change and we can add a plus and then equal sign and then type the method here, redraw. But without the parenthes we need to add a void on destroy. Whenever we destroy this object, we want to remove that subscription. Let's just copy this line and change the plus to a negative sign. Okay. Now we need to update our items whenever there are changes. In order to do that, we want to look through the items UI collection, and this will be all of the game object that we have inside the inventory UI panel, the child button. And we want to look through its count, and we want to delete all of those objects. Let's just run destroy item UI collection index of I and we want to access the game object. We want to destroy all of the game object of each inventory entries in the UI. After that, we want to clear the item UI collection. Let's just clear the list if there are any traces. Then we want to initialize this again. We can just run in it here, and then pass the items. It will I will incentiate a new list of items and save this. We need to test this out, but before we are going to test this, let's just create a new public method and this will be called show inventory. Let's just enable this game object here. Let's just copy this line, paste this here. Let's just invert the active status. Just type the game object act and hierarchy and then add a exclamation mark. If it's true, then we are going to set this to false and if it's fall, then we are going to set this back to true. It will create a togal effect with this method and save this. Let's go to unity and for the item UI object here. Let's under the inventory UI folder, the inventory item UI script. I'm going to direct this and dg the image component to the item image slot here. Let's set this as a pet's go to the pref folder and let's create folder, which is the inventory UI. And then drag this item UI. Okay. We can just delete this button here and this one. For the inventor UI panel, not the inventory UI anti game object, but the inventory UI panel. We want to drag the inventory system UI script. We need to set up a couple of things. Let's just set the item lay out first. For the item UI pre we are going to grab from the prefabs that we just saved before as the prefabs for the player inventory, let's just browse and choose the inventory that we created. The scriptal object is residing in the data folder. So let's save the scene and let's just create a button, a temporary button to show inventory. I'm going to set the size to be around 1005075. I'm going to align this button to the top right. And we can add a margin here, negative 25 on the x and the y. Let's just change the ex to inventory and enable the best fit option, so we can see it and save this. So now we have set this. We need to create an item in the scene here. Let's just go to the scene and let's just copy this cube that one, the green one, copy this cube here, and let's set this as an item. Okay. Instead of using the change scene action, just remove this and let's just item action, and browse the item database, and this will give us key, for example. This will give us key. Save this and let's go to the data folder and check our inventory. We don't have any items, so we can test this now. So if we press play, sorry, I haven't set up the inventory button yet. So let's go back to the base canvas. And for this button, let's just create a new click event and direct the inventory UI panel as the object. And we can run the script the show inventory method under the inventory system UI and show inventory. Save this now if we press play, and we press the inventory button, it will show nothing. It will show the inventory panel, but we don't have a think, and if we press this again, it will hide it. Now if we press this, it gives an error. Let check. Yeah, I forgot to insert action. Let's just direct the item action and save this and test this again. So now we don't have any inventory, and if we press this, It will add key. Currently, we are using check mark for the icon of the key. Now, if we expand this item layout, as you can see, it has a child object, and this child object is actually a key. If we stop and play this again, you will see that we don't have any child on the item layout. Oh, sorry. It does have because the item is get safe to the inventory. If we clear out if we delete the item from our inventory. If we clear out the inventory, if we press play, you'll see that it doesn't have a child object. For setting up item, we can just set it like this whenever we pick this up, we can show also a message. Okay. We show a message. You pick a key, and we can direct this message action to the second action. And for the third action, we are going to use the activate. Activate action and basically, we want to disable ourselves. Let's just direct the game object and make sure this is disabled for the act action, let's direct this as an action here as the third action, the item action message action and activate action. If we save this now and we press play, Now we can see our item layout doesn't have child and if we pick this up, we'll show the message and it will create item child object, and if we show the inventory, we will have this item picked up. This will be for our inventory UI system and we are going to create a description UI to show a description of the item that we have in our inventory. 39. 38 Inventory UI Description: Now we are going to create the show description in the UI inventory. Let's just re enable the two D total here and go to our inventory UI, focus on that region. Let's create a new child object, a child object, but much quicker if we create an image and set the color also with alpha value of 0.5. And we want to change its anchor or not anchor. It's pivot by holding the ship button inside the anchor resets and choose the first one here, and it will set our anchor to this position here, and we want to set the anchor back to center area. For this image, let's just change this let's just call this item description. Let's set its size to be around 400 by 200. Then let's create a new child object, which is a text mesh pro and set the test mesh pro to fit this window here. I'm going to set the auto size, but I'm going to set the maximum size to be 32. It will have sizing options 18-32 depending on the resolution. And add margin to the text object here. 2025 on each of the margin. 25 is too big, I think, 15 would be better. Now we have this setup. Let's go to the scripts folder, the inventor UI folder and then create a new invent description UI. And let's open this. We only need one variables in this class. Let's just define that and this will be a serialized field, and this is a text me PG this will be the text description text. We are going to delete the update method. Let's create a new height method, which is called height panel, and this is for hiding the description. Let's just set this game object, set active to false on start, we want to hide the panel. Let's just run that method. We want to create a public method for showing description. Let's just call this show item description. We need to pass two argument two parameters. Let's just type string, and this will be the description, and I'm going to make it shorter disc. For the second parameter, it will be type factor and this is the position. Okay. And now inside this show item description, we want to make sure that we are activating the panel. So let's just set the acts through. We want to set the description text to the description that we are passing through this parameter. And then we want to set the position by getting the component transformed. Transform and then grab the anchored position and then pass the position that we are passing here. Now we have created this script. Let's modify the previous inventory UI script. I'm going to open the item UI and also the inventory system UI. Now we need to create a reference to the inventory description UI. Let's create a new serial IS field. And this would be the inventory description UI. Let's just call this inventory desk. Make it shorter. Let's create a public getter for this field because we are going to access this from another script. Type inventory description UI and with capital desk, the same name. I'm going to set only a getter and it will return the inventory desk with lower case. Now on the item class here. We are going to create a new method. We are going to call this method tap whenever we tap this inventory item UI, we want to access the inventory system, this parent, and we get this value from initializing. Let's just call this inventory system. And then we can access the inventory description UI, which is the inventory disc that we've created a public error for it. Then we can run the show item description method, this ask for a description and a position. For the description, we can just pass this item description item description. Then for the second argument, we will need to get our rec transform component of this item UI here, and then grab the anchor position. And save this. Now we have add this tap method. We can just pass this to our button. On click Listener. Let's just type the button. On click Add Listener, and this would be the tab method. Save this and let's go back to unity and let's set up this item description object. Let's add the inventory descriptions UI and direct the text mesh pro child object to the description text field here. Under the inventory UI panel, we are going to direct this item description object, who will be the inventory description slot here, and save this. Okay. Now let's check our data and let's empty if there are any, it's already empty. I'm going to switch back to three view, and I'm going to focus to one of the character. Now save this and let's run. Okay. If we press inventory, we don't have item, and if I try to pick the key here, it will show us that we pick the key. And if we open the inventory, we have this checkmark and if we press this button, it will show a description, but the layout is all wrong. So let's just fix this Okay. As you can see that we have our pivot. It's on the top right here, but our anchor is on the middle. We need to change the anchor to top left. For the pivot, we want to add spaces. Let's move our y value here to a bigger than one, about 1.2 or 1.1. 1.2 will be okay. And we can set a negative value to the x value negative 0.2 or 0.20 0.050 0.1. I think 0.1 should do and save this, and let's try this again. Since we already have the key in the inventory because a descriptle object does not reset its value after we stop the run time. Let's just open the inventory right away and see if we click this key here, I show a description, and when we close this, it'll still showing the description, so we want to fix that. Let's go to our inventory system UI. Here, whenever we showing the inventory, we want to make sure if currently our game object is active is active in hierarchy, is active in hierarchy. This means that we want to disable this because if it's still active, then this will deactivate this. Whenever it's active, we want to set the inventory description, game object, set active to also falls. Like this. Now, whenever we run this and then we try to show the description of an item. And then if we hide this again and then we show the inventory gin, it will automatically hide the previous description that we showing before. Okay. 40. 39 Save System Extension: Now we are going to create a static class and the static class we're functioning for saving the system. Let's create a new subfolder inside the scripts folder, and let's just call this safe system. Then let's go inside to this folder, and let's create a new CS script, and let's call this safe system also. Now, let's open the safe system here in the fisico studio, we are going to modify a couple of things. First, we are you need to use the system run time, the serialization and then the formatters and then the less one binary. And we want to also using the system that IO, and this will allow us to create a binary format, class object, and this will also allow us to create a file string class. Now we need to change this safe system class type to a static class. Let's just add a static keyword in front of the class keyword, and we can safely delete the mono behavior because we won't attach this script anywhere, and then we can just delete this fit update and start. Now we are going to create a new public static method static void and this will be the safe data. Let's just call this safe and we want to pass a generic class, so we can save different classes according to our safe data classes later, let's just pass the safe data into the parameter. Let's just type the type first which is t because it's a generic and then let's just call the variable safe data. And save this. Now we want you to create a new binary formor. Let's create a new temporary field and type this binary for meter, and we can just call this binary formor and then we can initialize this by typing new binary formatter with sets of parentheses. Then we want to also create a new file stream. For the file stream, we can just call this file, would be sufficient to initialize this, we can just type new file stream and then it ask for a parameter, which is the first one is the path that we want to save the data and we can just use the application. A persistent data pass. Basically, this persistent data pass is the pass to a persistent data directory. This is the data directory that is persistent on the device. So for example, if it's on the PC, usually it's on the safe the install folder and also the same goes with Android and IOs then we can concatinate with a string and we want to add a forward slash or forward slash, and then type the safe data that we want to call or the file name. We can just call the safe and the format can be anything or anything. Then for the second parameter, we want to type the file mode to create. So we want to create a new file. And we want to create this save data file in the precisent data path. Now we have created this two object. We can just use the binary formatter, to serialize and it has a serialized method function, and I asked for a stream and we can pass the file here, since this is file stream, pass the file and it will save any object that we pass in the second parameter to the file stream in the first parameter. For the second object, we need to save the safe data here. Basically, what this function is doing is it's create a new binary for met to serialize any data that we pass here, and we can pass any type of object because we are using generic type here. When we pass this data here, and we create a new file here, the binary form will serialize after we created this file, we serialize any data that we pass here as a safe data and then it will be written as a binary to this file that we have created, which is the safe data that we have in our persistent data path. And since it's a binary, it's quite hard to modify because when a user try to open this data, it's not really readable. But of course, for any dedicated person that want to hack this data, it's possible. It's just not as easy as the player preference, the one that Unity provides for saving data. Whenever we successfully save the data here, we want to type the file and we want to run the can read, but the close method. This is basically we'll close the file from the memory. And then we want to type a debug log and call this safe success. We can also make sure that this debug log only runs on editor by typing a unity underscore editor, and then we can type with a sharp sign. We will make sure that this sign will only run in the editor and once it builds on the device or on the final build, it will not run. Because debugging a string or logging a string can also cause hit in performances, it's better to disable any kind of logging in the final bill. Save this. The next method we are going to create is the load method. Let's just type another public static. But this time we are going to return the type of t, and let's just call this load. T here. Let's just close this with a set of parent C. We want to check if we have the safe data or not. Let's just create a new method also and this will return a bull and check for safe data. Let's just return and then we can use the file class and it has a method. It has a exist method, this it's wrong, I think. Let's just retype this again, is this will ask for a string path, so we can just copy this string path here. And it will return the file is existed and it will return false if the file is not existed. So we can use this method and later, we are going to also use this method on another script. Now we can check check for safe return true, then we want to load the data. We will need to create a new binary formatter also temporary binary formatter, and then initialize this. Okay. And for the file stream, we want to load this. Let's just create a new file stream, and we can also call this file. Then we can initialize the file stream, and then we can get the path that we want to load. Okay. Also, we want to load the file, so we can just use the file mode here. We can just type file mode and then choose open. It will open the file. We'll open this file to the file stream here, and once it opens, we can make sure that we create a new generic type, let's just call this loaded data or load data. And we can use the binary formatter and derze the file stream that we have here. Let's just type file, this will rilize this file into the object that we want. But since method returns type and object, we can just typecasting this object that has been returned by the erz method to a generic type. Let's just add a set soparnsis in front of the binary formatter. Word and then insert the t keyword. It will cast this object to a generic type and then it will get assigned to this temporary lowa variable fields. We want to also close the file. Let's just type file and then close. After that, we want to, we want to return the load data. Let's return load data before returning the load data, I want to also do the bug. Let's just copy this line here and paste this here. And then change the safe to load success. We will know in the editor if it's successfully loaded our data. But here, as you can see it has an error because we only return the load data inside the statement and we will need to also return something outside the statement. Let's just return and we cannot return no since the type is generic, so it will cause an error. The right Q word that we need to use is the default and then we can put the T type inside a sets of parent C here. And we will need to add a semicolon over here. I forgot. That's why it throws an error at the bracket here and save this. One thing we can do is we can create an L statement here. And then we can also copy this line here and make sure that L statement only gets executed in the editor, and we can just safe file not found. We will know if there are no safe file and save this script. Don't forget at a semicolon at the end of this check for safe code here because I forget. Let's just save this again. Yeah, I think that will be all. We can just delete this unused namespace here, library or API. Then just save this and right now we can't test this script here, but in the next video, we are going to create a method to test the script out. Okay. 41. 40 Save Features Setup: Now we have created the save system static class to help us save data. Let's create a working safe system. Let's go to the scripts folder and under the manager. We are going to open the datanaga open the data manager class. Here, we already have a safe data that we mark as serialzable, and we need to add a new fields entry and the first one would be a string and this will be the current scene. The next one would be a public and it will be a list, but it will be a top of integer. This will be our items ID or inventory ID, or we can just call this inventory items ID because we are going to save the ID of the inventory that we are currently own instead of the item data, and we cannot save the item a, because inside the item data, we have a field and sprite field or sprite data is not serialzable. We can just grab the ID and save those ID two A list, and later when we want to load our inventory, we can just load it right through the list of integer and then grab a new item based on the ID or the integer ID that we save in our save data using the get items method from our item database. Because integer is serialzable, we can save this two A file. Let's just create a new integer. Let's create a new private integer and let's just type private integer and this will be the safe data ID, and we want to set this default to zero. Basically, we are going to save the safe data into a list, and that list is going to be sterilized into a file. Basically, whenever we load a safe data, we need to access based on its index. Currently, for testing purpose, we are going to use the first index. Now we need to create a new list of safe data, but we already have created the safe data. Let's just convert this safe data to a type of list by adding a list keyer in front of the class. Then when initializing, we want to also inize as a list. Let's just do that. Then I'm going to cut this and put this below our safe data here. And save this. Now we have this safe data or we can just add a as to mark this as plural. It's clearer for us later down in the road. And now we have this error. Be safe data, we don't have safe data anymore. We have safe data safe data is actually a list, so we need to paste this, but it will still throws an error because it's a list, so we need to access its index and we can just put as the index, our safe data ID here. Since this is zero and it will try to save and load on the first re. But later we are going to create a way to save into a different slots, and when loading, we can load from a different slots. Okay. I'm going to fix all of this error by changing all of the safe data reference to safe data index of safe data ID. Let's just add a letter and then paste this and add later and paste this safe data ID. Now we fix those issues. Now we need to create a new method to return whether we have a safe data at least one safe data or we have none. Let's just create a new public and it will return type of bolet's just call this safe data. We want to make sure that our safe data is not. Let's just access the safe and then we can make sure that it's not new. If it's not null, then we want to return I count, it's greater than one, is greater than zero. Basically, if it's greater than zero, it will return true, but if it's not, then it will return false. If safe is, then we need to create another condition here, and we need to return false. This method will always return a bulon now we need to create a safe and load function inside our data manager. Let's just create a new public void safe for safe, we want to access our safe system. Then we want to run the safe method and we want to save the data to our safe data like this. We are saving the data from our safe data, list of safe data here to a file for loading, can just create a new public void load. It should be load only on level loaded. For loading, we want to pass the data to our safe data, and then we can just assign the value from our safe system. Then we can type load and then for the type, we can just grab the list of safe data. And then we need to add a parent to. It's like get component. This is basically a method that as for a type, and it's also a generic because we can grab any types of data to this get component method and for the load method inside our safe system, we can also load any type of data by passing the data. Since we are saving the safe data, so when loading, we know that we have a list of safe data inside our safe data, we need to load using that type, so it's compatible. And we'll be able to load any previous data, if there any. Now we are going to create a method for saving an entry loading an entry data. Here below our load method, let's just create a new public void safe data entry. For saving the data entry, we want to save based on our safe data ID. Currently, this will be stays zero, the value, but later we will have different value depending on the safe slots that we are previously loading at the start of the game. In order to save the data entry, we want to first run the unsafe event. This will trigger the save entities from any object that have the safe entity component here. We want to also save the scene name. Let's just access the save data and then index of safe data ID, which is currently still zero. The ID. Then we want to insert we want to set the current string field here to our current loaded scene. So let's just use the Unit engine scene manage it has a scene manager class. Inside the scene manager, we can run the active scene method, and then we can return the name of the scene by typing names. This will return the name and it will get saved to our current scene. When we finish passing this here, we want to also save inventory. This We haven't defined it yet, so we need to create this now. For saving inventory, basically, we need to record all of the items in our inventory. It's ID, and those ID that we record, we need to save this to our list of integer inside the save data. Let's just create a new method to do that. Let's call this public void save inventory. But we will need to create a helper method in our extension static class. Let's just go to the extensions script. I'm going to search here, and this is our extension static class here and create a new method with a public static keyword void this would be the safe items to ID. We know this is for saving items to ID, and we will need to add a parameter list integer, this would be the items ID. The second one would be the list of item, and this should be the inventory that we are going to iterate from our current inventory. But here, we want to extend the list integer types, and we can add this keyword in front of it. Later, when we have the list of integer data or object in other script, we can use this method to pass through the list of item and then get the items ID and then add those values to our items ID. Save this extensions and we are going to look through the inventory count. Let's just this inventory dot count. Whenever we are saving data, we want to check first if our items ID contains a specific integer because it as for an integer and It contains our inventory index of item ID. This means that we already have this specific items, then we want to skip that. We don't want to save this because we already have this in our list of integers. Otherwise, it will create duplicates and we will have copies of items and that will be an error. So let's just type return. I will skip. Here, we want to add the items ID, add the inventory in x of item ID. So if if the items ID does not have the intended item or the current item that we are loping here, then we want to add this to the list of integer. The values of the item ID from our inventory inx of. Now we have this method. We can use this in the data manager. Let's go back to the data manager. When saving our inventory to the data manager, we can just type where is the safe data here. Let's just access our safe data and index from the save data ID, save that ID. Then for the item inventory items ID, we want to we don't want to pass, but we want to run the method that we just created. We can just type here, and then save items. As you can see here, we have a extensions method for a list of integer because we use this keyword for this parameter. This will extend the list of integer here. Whenever we have a list of integer objects, we can use that method. Safe items to ID, and we will need to pass a list of inventory. List of inventory is basically our inventory here, we can just access the inventory fields and get its inventory. This will return the list of items. And this is a properties. Let's just close this with semicolon. Now we can save the inventory and it will convert our list of items to a list of integers. Now in the save data entry, we want to save the inventory. Once we save the inventory, we want to save the data here. Let's just run the save method. Okay. Now we want to load an entry from our safety data. Let's just create a new public void, and let's just call this load data entry. For data entry, we can pass an integer. Let's just call this ID. Then for load data entry, we want to pass the ID to our safe data ID and an equal ID. Here, we want to load inventory, but we haven't defined this yet, and we also want to run the unload event. It will trigger all of the safe it object that we have on our scene and it will load the previous safe entity data. Before we can load this data, we need to run the load method. Let's just type load here. Now we need to define the load inventory method. Here below the safe inventory, let's just create a new public void, and let's just call this load inventory. Basically, we need to convert back our list of integer to a new list of items based on the item ID that we saved into that list of integer. To load inventory, let's go to the extensions class here, and we are going to create a new public method. Let's just type public static void. This would be load ID two items, and this will extend the list of items. Item and let's just call this inventory. Then we need to also access the item database, and let's just call this item database. The last one we need to pass is the list of integer. Okay. We will look through the items ID that we pass here, and this items ID will be pass from our safeta should have a couple of items in it, and we need to look through that items ID. Let's just create a loop, then we can just type items ID co It will whatever members or how many items that we have inside the items ID. Then let's create a new item, temporary item called item. We are going to copy item and we have this copy item here. And we have range of copy the item from our item database. But remember, inside our item database, we have the get item method and it asks for ID, so we can pass the items ID. Value here. Let's. Let's just type items ID, and then grab the index of I. It will look through the items ID, and when it has a value in it, it will have an integer value. This integer value will be the items ID that we previously saved when we get item based on its ID, it will return an item and it will copy the item. To a new instance of item here. Once it creates the new item, we can add this item to our inventory. Let's just type inventory, and then we want to add the item that we just created here. Pass the item, and it will add this item to this list of items, and this is an extension. We can use this in our inventory descriptable object. Let's open the inventory scriptable object. Here we are going to create a new method called update inventory. Let's just call public void update inventory. There is too many brackets that were created, so I'm going to fix that. Save this. For this update inventory, we are going to pass a list of integer, and this will be the items ID. On start of this method, we want to clear our item. Let's just grab the items, the inventory. I think this list of items here. We want to clear that. Let's just run the clear method, and clear method is actually a method from the list of items, and this will act for clearing any entries inside this inventory here. Okay. And then we want to run the extension that we just created, which is called load ID two items. This as for a item database, so we can just grab the item database because the inventory in scriptable object have a reference to the item database here as you can see. Okay. And then we want to pass the items ID, which is a list of integer, safety. Basically, this method we'll access this extensions method, then we'll create a new item, and those items will gets added to the inventory. Once it finished updating, it will update our inventory. Now we already have this update inventory method. Now we need to go to the data manager and then set up the load inventory method. Here on top, as you can see in the fields, we have a reference to the scriptable objects. Now we can just access the scriptable object and then run the update inventory method, and it will ask for a list of integer. For this list of integer, we can just type safe data index of the safe data ID. And then grab the inventory items ID here. It will grab any value that we have here from our save data. Then it will update the inventory based on the items ID that we saved previously. Save this. Now we have this load inventory method created. We need to load here in the load data entry. Let's just type load inventory. Let's save this. Now let's go back to unity and see if we have any errors, hopefully not still compiling right now. So far no errors. In order to test this, we are going to create a debut for loading and temporary loading and saving. So let's just create a new button here. Create an empty. I'm going to put this empty on the top left of our screen and going to expand this, and then I'm going to add a button. I'm going to set up this button here. Move this to the side here. Set it tax increase its size by enable the best fit and then type safe, and then create a new button for loading, push this aside. And then open this and then change the text to load. Save this. Now for testing this out. We can just grab the data manager here for saving, we want to run the save data entry method for loading, we want to enable the onclick method and then drag the data manager, and we want to snager want to run the load data entry. For the ID, we can just set this now at this moment to zero. Save this. I think this should work. Let's just go to the data folder here and for the item database, not the item sorry. For the inventory scriptable object. Let's just delete the key object here, and save this. Now let's run this pick this key here. Then let's talk to this person here. I will move out and let's go to this position and then save this. Now, there is an error on saving. Let's check that first. I found the error, and basically, whenever we save this, safe data is actually doesn't have any member yet. We need to make sure if we don't have any member yet, then we need to create a new safe data. Here in the safe data entry, let's just create a temporary code and check for safe data, and if it's equal to zero, Then we want to create new safe data. Just run the add method and then initialize a new safe data by typing new safe data like this. This will create a new safe data. And now the save system will work. One thing we need to fix or we need to add is also on the invcript object class here under the update inventory. After we clear and then we load the items from the ID. We need to run the on items change event that we already defined here, and we need to pass the inventory list of items. Let's just type the inventory object here and save this. Now with the changes, let's test this in unity. Okay. So first, I'm going to clear the inventory and once it's finished compile, let's run this. Now, let's try to pick this object here, the key and then talk to this person, so this person will move and then go to this position here. Now if we open the inventory, we will have this key object and now save this. It should print out save success and then stop this. Basically we are already stopped the session. A in the previous session will be clear from the memory and we can reset the inventory, so we don't have the key anymore. Now if we press plea and then If we try to load, it will load the inventory position, the last position for this person here and also our last position, our less player position. If we open the inventory, it will also draw the inventory item because we run this event and this will alert the inventory system UI to redraw the UI. That is for the basic safe system and we will also create a screenshot to be safe whenever we save an entry and we will create a UI to load different slots. Okay. 42. 41 Transparent FX: Okay. Now we are going to create a transparent effect. Basically, what we are going to do is we want to create some effect and this will change an object to a transparent state whenever a player is behind those objects, so we can see the player. And this will be useful for a rooms or wall, whenever player enters that rooms or wall, we can change the wall that occludes the player to a transparent material. In order to do that, I'm going to first create a new folder and I'm going to call this FX Here, I'm going to create a new C script, and I'm going to call this first then effects and create another cup script and call this transparent trigger. Trigger. Now let's open the transparent effects and also the transparent trigger. For the transparent trigger, we are going to create a couple of fields. We will need a reference to our player, and let's just create a new private transform and this will be the player. Okay. The next one should be a private ray and just call this ray.other one is the cast hit, and let's call this hit. And then the last one is the transparent class, and let's just call these effects. This will refer to the wall that are occluding the site from our camera to the player, and we will get that script and we will trigger method inside of this class here. On start, we are going to get reference to our player. Let's just type player, and then we can use the game object class and then it has a fine objects with method and search for player. Since we are referencing the player to a transform field, we need to get it transform by accessing the transform properties because fine game object with tag method, we will return a game object. Let's say the script, and then let's create the trigger inside the update method. Basically, we want to feel the ray field here. We want to create a ray from the camera to the player. In order to do that, we need to declare a new ray, and here, we need to insert the origin, and then the direction. For the origin would be the position of the camera and this will be the transform the positions because we are going to put the transparent trigger class to the camera on the scene. Then for the direction, it will be the player position, substract with the camera transform position. Okay. This would be the ray and this would mean that we are shooting a ray from the camera to the player, and we want to check if this ray hits any object, so we can just use physics cast and then we can pass the ray, we are going to use and we want to output the result to our field, so we can extract any info from this hit. Then for the distance, set two math float class and it has a infinite properties. First, we want to check if the hit is null or not. If the collider is, the hit collider is not, then it means that we are hitting something. Then we will check if hit else if hit anything else but player and the other else if hitting player. Basically, we want to make sure that if the f x object is currently null, then we want to grab it. We want to grab the f x from the object that we are hitting currently, so we can just access the re has hit and access its collider and from the collider, we can get the neighbor component by using the get component method and search for the transparent effect. This we'll try to search for this component, and then we can check if the X is not null, then we want to run the transparent effects. But we haven't created this yet, so we'll just leave a comment here, and then we want to set else hit collider and we can compare it tag is player. Then it means that we are currently hitting the player, and we need to check if the effect is not null, then we want to switch back then the transparent effects. Save this after switching back the transparent effects, we want to set the effects, so we can just type effects equal new Okay. So save this. And now, basically, the the transparent trigger script is already done. The next thing we need to create is We need to define the transparent effect script. Let's just do that. I'm going to tidy up the script a bit safe Let's go to the transparent effect. For transparent effects, we need to create a new serialized field, and this will be a type of material let's just call this transparent material. This will hold the transparent material that we are going to create in the projects. The next field that we need are an array of materials. Let's create a material array. Let's just call this original. And then we need also a mesh render array, and let's just call this mess renderers. We want to initialize this on start. On start, we are going to fill the mesh renderers with any component on the object or on the child object by using the get components in children and search for the mesh render. And get components in children will return a mes render array. It will populate our array here, and then we want to set the original material array to have the same amount member of our mesnder. We can just initialize this using the new material keyword and then insert the mesh render length as a array numbers here. It will create the same length with the mesnder then we can look through the mess render. Let's just create a four lo keyword and get the measure render length here, and then we want to assign original index of I. Okay. Equal the mesh render material. Basically, we are going to save the material of an object to the originals here. We will keep reference to the original materials and we can safely change the materials to the transparent one when we need to change it. Save the script. Now we want to create a new public method. We can just delete this update method. Let's create a public void and switch material. We can call this switch material we want to as a parameter. Just put a bullion, and let's just call this transparent. And we want to make sure if transparent equal true, then we want to change all of the material to a transparent material, we want to revert back to the original material. Now we can look through the mesh render length, and then we can set the mesh index of material to the transparent material, and if the transparent is false, then we want to set this back to the original material, so we can just get the original x of because the order of the measured will stay the same when we are initializing the original material array, we are using the same order here, as you can see, it should work. Now that we have finished creating the transparent script, let's go back to the transparent trigger and then complete the script here. Basically, this statement here is to check whether if the effect currently is new. If it's currently is new, then we try to grab on the object that are hitting our has, and if the f x is not null, then we want to switch the transparent effect to transparent material. Let's just run the switch material method that we just created before and then set the bulon to true and this will make sure that we are running this part of the code. Switch the material, all of the measurement are found on that object to a transparent material. And here, the LS statement is to check whether if the object that getting hit by our RCA has type of player, then we want to switch the material back to the original one. So let's just set this bully in to false basically, if the ya hit the player, then there are any object that are standing in front of the player or clding the player. Save this and Another thing we can do is let's go to the player script, the script where handles the player movement. We want to create a new layer mask. Let's just create a serialized field and type should be layer mask, and then we can just rename this to interact layer. For the physics recast, we can add the layer mass to the fourth parameter here. Let's just type int layer and this will make sure that we only want to cast against the object that has the layer that we set up in the inspector, a specific layer, a certain layer, and it will ignore any other layer that aren't selected. Let's just save this and go back to it. Now here, if we select the player, we will have a new in slot or fields here. We can set this to a certain layer, but we haven't created that. Let's just select our ground object, and then we want to create a new layer called ground. Then the other one should be the interact table. Now if we select the ground object, change the layer to ground and save this and go back to player and we can set the interact layer to the ground and to the interactable. Basically, we can only click on the ground or on the object that have a interactable script, and we will set all of the object that has interactable script has the layer of interactable. Now let's just select the cube here and let's duplicate this and maybe put it here. And we want to scale this. So it looks like a wall, and then push it upwards. And for this script here, let's add the transparent effects, and then add the transparent material. For the transparent material is basically a new material, just create a new materials in the materials folder, and this transparent material just set the rendering mode to transparent, and for my settings, I've set the color to a slight gray and set the value of the alpha to 0.1. This will be transparent. And if we select the cube that we just created here, we can wreck the transparent material to the transparent material slot. Don't forget to add the transparent trigger to the main camera, and this should get added also to the other camera here. Let's just add that transparent trigger. Let's save the scene and let's test this out. So now we have set the ground to the ground layer. So whenever we click behind the wall, the player will go to that point of the ground. But right now, there is an issue because when we go back to behind the wall here, the wall doesn't get changed to a transparent. In order to make the transparent wall, to work, we need to disable this cube tree here because you have this empty clider that triggers our change camera before, right now, the wall here lies behind this cube here. Whenever we run, our camera will hit this clier here. It will do nothing because it cannot found the transfering effects when the camera should hit this other cube here. Let's just disable this cube tree for a while for testing this out. Save the scene, and let's try this again. Now let's try to go back to this wall here. Once we go back, as you can see here, we have a transparent wall. If we go back to front here, it will back to the solid transparent. And this will be applicable to any other object that has different material because whenever we are changing to the transparent state, basically on start, we already save reference to the original material. Whenever we comes back in front of the camera, then we can switch the material back to the original material. Okay. 43. 42 Audio Manager: Okay, so now we are going to create the audio system and we are going to start with the audio manager. Let's create a new CSP script under the script folder and then under the manager folder. Create a new CSP script, and let's call this audio Manager. Then let's open this in Fissio Studio. First, we want to import the audio namespace. Let's just type using Unity engine, the audio, and we will have access to the Mixer class. Let's create a new S field, and this would be the Mixer group. The audio mixer group. This would be the Soffe group, and then music group. We want to separate the channel for sound effects and music, so we can create a volume controller later. With this audio menager the audio menager will create a empty game object with audio source components attached to it, and we can define the characteristic on initialized. Let's create another cerlize field, and this would be a type of integer and this would be the audio source instances. And we can set this default to five. We want to also create a Q. Q is basically like a list, but it doesn't have add or remove feature. Instead, it has a N Q and Q feature. I will show you how this works later in this video. But basically, we want to create a Q type of audio source. This would be the SFX library, lips Let's initialize this Q audio source. Then we want to create a single audio source component or fields, and this would be the music source. Or we can just call this music player. This. We are going to make sure that this audio manager act as a singleton, so it persists through scenes. Let's just create a new public properties, and this will be a type of static and should be the audio manager, and let's just call this instance. Then we want to set a public get but a private set. Okay. Now let's create the void awake method and inside this void awake. We want to sorry want to check if instance is equal then we want to reserve the instance. We are going to assign instance to this script here. And after we assign the instance to this component here, we want to set this object that holds this audio manager to have a don't destroy unload behavior. We will set the scheme object unload, so it will persist through the scene. And else if some other object already claim the instance or if instance is not null anymore, then we want to destroy this game object. The next thing we need to do is we need to create a init method. Let's just create that. Basically, for initialization, we want to create instance of audio source attached to a game object. We want to create those object as many as our audio source instance value. We want to look through this amount here. Let's just create a four loop. Then for the length, we want to use the audio audiosurce instances. For initializing, we need to create a method that will return audios. Let's create a new method that returns audio soource this will be the audio source stand, we want to pass a couple of parameter. The first one should be the audio mixer group. Let's just call this group. We want to assign which group that we are passing as the audio mixer group. We want to pass also 1 billion, then this will be the S. If it's true, then this audio source we incentiate audio source component for sound effects, and if it's false, then it's for the music channel. T one should be a string, and this is name and we can set this to a default value. Let's just set this to audio source by default. Here, we want to create a new game object. Let's create a new temporary audio source, and let's just call this audio, and then we want to create a new game object, and this is for creating a game object. But we can pass the name to this parentheses here. Let's just copy the name and pass this here, and this will create a new game object and it will also return a game object. In order to return a audio source, we want to add a component, and then we want to add an audio source. Once we set up like this, this new object component audio source that are added to the game object, we will be referred to this audio object here. The next line, we can modify any properties from this audio source. The first thing we want to set is we want to set the audio source, the group here, the output audio mixer group to be the group that we pass in our method parameter. Okay. And then for the spatial bland and spatial band is a three D specialization calculations, and if it's zero, then it makes a sound fully two dimensional and if it's one, then it will be three D sound and it will react depending on the audio listener that we have on our scene. Usually it's on camera. The further away the object from the camera, then the volume of the sound will be smaller. We want to set this depending on our SFX lean. If it's true, Then we want to set this to one, and if it's false, then we want to set this two zero. This is basically a ternary operator and the format or the syntax for this ternary operator, this is the condition. And this will be the result. If it's true then this will be the value of our special bland, and if it's false, then this will be the value of our special bland. If we set the S effect to false, then the special brand will be zero and it will be suitable for our music audio source. We want to also loop the audio based on our Sf. Let's just set the loop mode here to negative or inverted as f x value. For example, if we are setting this false, then the audio loop will be true for music, we want to set the loop to true and for sound effx we want you to set the loop to false. Then we want to also set the parent to the audio transform here. Let's just access the audio and then the transform and then we can use the set parent method. Then we can pass the transform of our audiomager here. And after that, we want to return the audio because this method returns an object type of audiosur. We need to return something here. Now we created the audiosurce insaniate method. We can use this to insentiate a new audio source upon it. So we can use this audio instantiate and then we want to pass the group. For the audio source instances, we want to set the sound effect group, for the so effect bullion, we want to set this to true. For the name, we can just pass this to the audio source, and then we can add the index the increment, it will have difference value, different names. And we can set this two string with a two digits format. It's readable. After we create this audio source instantiate, we want to instate another one, and this would be this is for the music group and set the sound effects to false let's just call this music source. And save this. Now if we go back to our fields declaration, we have this Q SFX lips and also audio source music player. We want to set this to the music player. Let's just type music player. And we want to keep the reference for our music layer here. For the sound effects, we want to put this to our Q here. Let's just type SFX lip and then Q and then put this inside the parenthese. We will shuffle this audio source inside the Q and then later we can use this from our Q here. Okay. And now we need to run the init on start. So let's just run the init method. Next, we need to create a couple of public method. The first one would be a public void play sound effects. And we want to pass an audio clip, and this is call this clip and also a transform, and this will be the source position for our audio source. It will react to a three D specialization, and we want to set this source to know by default. We don't have to always put transform whenever we execute this method. We want to create a temporary audio source, and that's just call this audio. Okay. And then we want to set if sound effects lip count equals to zero, then it means that we don't have any free audio source left, then we want to instantiate anyone. Let's just run this. Instantiate number one, and we want to put this inside our audio variable. Here, we want to set the naming by the maximum count of our sound effect slip. We can use the audio source instances. Let's just typed so instances. And we can increase this. Okay. So save this and then, if there are still free audio source available, then we want to deque from the SFX lips. Let's just set the audio to SFX lips and run the Q this will any audio source inside the q here, and we can use that. Now once we set this up here, we want to set the audio clip to the clip that we pass inside our parameter. Then we want to run the play method. We want to also set the position of our audio source. Let's just access the audio, transform that position, and then we can use the ternary operator like this one here, and we can check if the source is not new, then we want to grab the position. But if it's new, then let's just use a vector three zero. It will be incentiated or it will be positioned in the center of our role. And at the end, we want to put our audio x to the sound effects lit by running the N Q method and pass the audio that we are just previously using here. Here, I'm going to add a method to move from its hierarchy using the set as last sibling. This is basically for illustrating for illustrate the Q and Q process. Later, we can see this in the hierarchy in the editor whenever we play a sound effects. Another method is for playing the music. Let's just create a public void and play music, we only need to pass the audio clip here. Let's just call this music. We want to if the music player and music player is our audio reference for the music player here. It's clip the same as our pass music from the parameter here. Then we wouldn't want to change the music. Return the method. But if it's different, then we want to change it. Let's just access the music clip to the new clip that we are passing and then we want you to play that. Let's just run the play method from our music player. Okay. This is basically the audio manager here and safe D let's go back to unity. Now let's create a new empty game object for setting up the audio manager and reset its value here. I want to reset the transform. Reset the transform, and then rename this to audio Manager, and we want to add the audio manager component to it. I ask for the sound effects group and music group. In order to do that, we can go to the audio folder here and create a new mixer object. Let's create and here we have this audio mixer and let's just call this master mixer. If we double click it, it will open the mixer window here under the groups, we can create a new group. The first one, we want to create sound effects, and then select the master again, and then we want to create another group for the music. We will have two different mixer for outputting different audio types. The first one for sound effects. The second one for music. If we go back to the audio manager here, now we can pick those group for the sound effects group. Let's just pick the sound effects for the music, let's just pick the music. Save this. Right now we cannot test this yet because we need to create an action to trigger or to play a sound, and we will do that in the next video. 44. 43 Audio Action: Let's create the audio actions to play audio using this audio manager. In order to do that, let's go to the scripts folder under the actions folder. Let's create a new C sharp script, and let's call this audio action. Once it's created, let's open the script. Since this is a action class, we want you to derive from the actions based class. And we want you to delete the epic method, and let's implement the abstract right. Let's just implement this abstract class here, and I want you to cut this and put this below the start. First, we are going to create a new serialized field, and this would be the audio clip array. Let's just call this audioclipse. The next one would be the bullion and this would be for toggling if this audio action is for playing music arena we can create is music bullion. Then we want to create a new private audio manager reference. Let's just call this manager. For the manager, we want to grab this from our singleton, so we can just type manager equal the audio instance. The next time we need to use this audio that instance, we can access the manager. Now let's modify the a method. Basically, we want to check if it's music is false. Then we want to play a random audioclipse. Let's just access the manager, play sound effects. Then it as for a clip. We can just type this audioclipse. Then for the index, we can use a random value, random range, and then we can insert the range from zero to the length of our audioclip This will automatically choose a random eclipse from our audioclipse array. For the transform, we can just pass the transforms of this audio actions holder or owner. Let's just type transform else if we are going to play a music, then we want to use the play music method. For the clip, we can just grab the audio clips. The first one, and safety. This is the script for the audio actions. Now let's go back to unity and test this on. Right now we want to create a footstep sound. In order to do that, we can go to the player and to the graphic objects here, the one that has the animator component attached to it. Let's just direct the audio actions to that game object. For the audioclipse, I'm going to set two entries and inside the audio folder, we have a footsteps. Let's just direct the first foot step A, and then footstep B. And I want to press apply to update the prefs. After that, we are going to duplicate the animation. Let's just go to tiny people. If we go to the object here and the animator, we can check which animation are we using in the blender. Basically, we are using this. If we go to the project, this is the animation file. I want to duplicate the walk here. And it will be a separate file, and I want to rename this M M walk footsteps. I'm duplicating this by selecting the clip and then press control these, it creates a new clip file. Now if we go back to animator, we can change this to the MO footsteps. This is basically the same animation. If we press play here, you'll see if I go to speed of one, it we play the walking animation. And why do we have to duplicate the clip because now if we open the animation window, we can create a custom event with this footsteps. So if we select the graphic objects again, the idle is read only. We cannot change it. But for the footstep, we can create a new event here. Let's just Select the game object, rotate this and I'm going to focus here. Let's just crop the timeline. We're able to see the animation, I want to synchronize every time it puts steps on the ground. For example, if I move this here, I want to play sound in this frame here. I'm going to create a new event over here. Then for the other feet, I want to put the event here. Whenever the foot contexts the ground, I want to create this event here. Now, if you select the event, we can select the function because we already add the audio action and egg method is a public. For any function that wants to be triggered by the animation event has to be the public, for the second one, I'm going to also select the agg function. Let's save the scene and now let's test this. Okay. As you can see, when we are moving, it plays stepping sound. Now let's create a sound whenever we are talking to a person. Let's go to the audio mixer first. I'm going to set the forum lower for the sound effects, and let's test this again. Okay. Okay. The next thing, I'm going to select this police officer here, the NPC, and it has a message. And let's just create audio action here. And whenever we interact, we want to play the audio action. Let's just create new actions on our intractable, and then let's play a dialogue. We have this male a dialogue and drag these actions to the NPC, to the second sot of these actions interactable and save this. Now, if we press play, Okay. And let's try to. Sorry. I need to change the NPC layer to intractables. So let's just do that change the children also. Now let's try to click on the police officers again. Okay. So, we have a really nice working audio system and later, we are going to setting up how to play music. And right now for the audio systems is basically done. 45. 44 Interact Cursor: Now we are going to create a cursor script and this cursor script, we create a behavior or a hint. Whenever we are hovering and interactable, whether it's a person, it's a sign, then it will show an icon to indicate that we can interact to that object. In order to do that, first I'm going to create a new subfolder inside our scripts folder and I'm going to call this UI, then let's create a new sharp script, and let's call this cursor script. And let's open cursor script. This cursor script is basically a controller. We are going to attach this to a canvas and we are going to create a couple of serialized field. First, let's create a serialized field and this will be a type of transform, and let's call this cursor. Then the next one is also a serialized field, and this will be a type of image. But since we have import or using the UI name space, we need to do that. Let's just add a using unity engine UI on here, on top here. And then let's type image and this would be the cursor image. Then we want to also create a serials field and this would be the layer mask, so we can filter out let's just call the layer mask. Then let's create a couple of private variable. The first one would be the camera. And we are going to store the active camera to this variable. The next one should be our cast we can just call this and the other one is and call this ray the last one is the interactable Let's just call this current interact. On start, we want to grab the main camera that are currently active. Let's just grab the camera, camera class and then call the main properties. This will return the first or first enabled camera tag main camera. Then we want to also event on the camera manager instance. We have this on camera switch, but we haven't created a method subscribe to this event. Let's just do that. Here we can call this camera switch, and we need to pass a camera to this method here, and then we can just assign this camera here to the cam that we are passing here to differentiate which variable is this, and which one is this? We can add this and this will return to this class here. If I wrote it, then it will revert to this private variable. If I choose this cam here, it will highlight and it will show that this is actually the argument parameters that we are passing by this method here. Now we have created this method. We can just ascribe this to the on camera switch event. Let's just type the method name camera switch, and save this. First on update, we want to set our cursor position to be the same with our input mouse position. Then we want to create a new ray. Let's just type the variable and then use the variable here, and then use the screen 0.2 ray let's grab the input mouse position. Now we can check if this ray is hitting some object in the scene and we can filter out the ya using this layer mass. Let's just create statement, and we want to access the physics class and access the a method. Then as for ray we can just put the ray here, and then we can put the result to the variable here with this skewed out, it will send out result to this hit instead of getting the value, and then we can use the layers, type layer mask. And then we can open the bracket. Then we want to activate the cursor. Let's just access the cursor game object and then run is active method and then set this to true. We need to check if the collider is not. It means that we are hitting something, and at the same time, our current interact is still, then we want to grab the current interact if there are any. Let's just type current interact and then access the collider and then get component and we can get the interactable class from this object. If we filter these layer mess for only interact with interctables, then most of the interactable object should have this component. And we want to change the cursor sprite. But we haven't implemented this yet, so we are going to modify this later, but let's just create the Ls event here. Basically, if this physics races doesn't written true, it means that we don't hit anything that are inside this layer mass here. Then we want to hide our cursors L statement here. Then for the cursor object, we can access the game object and then set active to false and we want to also set the current interact back to null. We want to clear interactable class reference inside this current interact. Now let's modify the interactable and add a new serialized field. Inside this interactable, we are going to add a new cerlized field and this will be a type of sprite this should be the sprite cursor. Since it's a serialized field, we cannot access this. Let's just create a public getter below here with the same type, which is sprite and then let's call this sprite cursor with capital S. Then we want to only get return cursor value, whatever they are, and save this. Now if we go back to the cursor script, we can change the cursor sprite. We have this image. Let's just access the cursor sprite this should be the current in sprite cursor. For any interactables, we need to assign a sprite cursor on the inspector, so it will interact. But we can create some fail safe. If the current sprite cursor is null, is not assigned, then we want to hide the cursor object. Set two falls. Okay. Let's test this out. Let's go back to unity, and let's create a new empty for the base canvas and I'm going to stretch this to fit our canvas. Then I'm going to set to call this cursor. I'm going to also create a image and this would be the cursor image. Let's put the cursor script to this cursor game object, this empty UI game object. Then we want to change the layer mess to injectable. For the cursor, we can just drag this object here. It will grab its transform. Cursor image, we can just put the image here. Now we save this and switch back to three D view. Let's go to the NPC that are currently active. Here in the intractable, we cannot see the sprite because we haven't created that in the editor. Let's just go to the editor folder, and let's open the intractable editor. We need to create a new serialized property, and let's just call this sprite cursor as underscore sprite cursor and we want to grab the value inside enable. Let's just type sprite cursor equal serialized object, fine property and I believe this this is called I believe the serialized field is called cursor. Let's check this. Sprite cursor, and then we want to draw that. We can just draw this on top here. For the sprite here, we want to use an object field. We can just grab the object reference value here and it has a object reference value, and then we can assign this to the editor GI layout and use the object field method and we can pass the serialized property here. Let's type Sprite cursor. I think we can just grab the object reference value again here, and then we can set the type of a sprite here. We can add a false flag here. This is basically to make sure that we can only pick an object from the assets, not from the scene. It won't allow to picking a sprite from the scene, and save this. Let's try this and go back to unity. And let's see if we have, we have the slot here and we can pick Sprite, for example, let's try to pick this UI sprite here. But it doesn't show the UI here. Let's change a bit of the code here for the sprite here. We can I believe we can add a name before. Let's just call this sprite cursor. And then after the false statement here, let's just add a layout and use the hide and sets the height to around 75 and save this and see if this increase the size of the sprite slots in the inspector. Yeah. We have the sprite cursor and we can see the cursor that we are currently using. Let's save the scene first. Now let's try this, see if it's working or not. Okay. Okay. Yeah. As you can see, it shows something here. So basically, probably there is a collider here, but if we go to the police officer, it should change the. There you go. If I go to the police officer, it change but there is an issue here. Let's check the ground. Okay. Sorry, there was an issue before. And here, if I hover on the cast, as you can see, currently, it gets the value of layer mass as a float mass distance. The value of the layer mess is actually an integer, and it treats as a max distance, not as a layer mess, so we need to add a parameter for define the max distance, and right now we can just set this to 100 unit, and then the last one should be the layer mass. If I hover again, and as you can see, we are filling the argument correctly right now. And if I save this, this should fix the issue. Now if I press play, it won't show a cursor on any object that are assigned that we haven't assigned the sprite cursor. But if I go to the police officer, it will show this circle cursor. But right now we have another issue. If we press this, we cannot go to this person because the cursor image is blocking our cast target. So let's just top this and then select the cursor image and then disable the Cast target and save the scene. And since we added a new child to this base canvas, let's just update the prefs by pressing apply. So it will be included to the pre and save the scene again. Now if I try to click on the police officer, we can interact again. And then now we can go to the NPC here and we can change this to the top cursor and for the other NPC, we can also change the cursor to the top here. And for the cube here, this is for picking item, I believe. So we can just use a hand cursor, so save the scene. Now if we press play, We can talk to this officer or we have an issue here because we haven't changed the layer. Let's just select the other PC and then the other green cube here. Let's change its layer intractable. Yes, and change children and save the scene again. Now if we try to hover the player or the other NPC, as you can see it change our cursor we can pick this item, we can talk to this person, Okay. And we can talk to this police officer. And yeah, that is pretty much all about the cursor, and it's a nice visual feedback to let the player know if we can interact to an object or not. Okay. 46. 45 Look Only Interaction: Now we are going to expand the intractable script because currently we can interact to an object or NPC. But whenever whenever we try to interact with the intractables, the player will move to that position. We want to add an option where we can just create a on the option, and this will be suitable for a sign or anything that doesn't require the player to come over to the interractable position. Let's open the interactable script. Once it is open, we are going to create a new serzed field. Let's just create a serialized field here. Then type and let's just call this only. Let's create a public accessor and this should be the type of bone's call this also only with capital L. Then we can set together and return the only value. And safety. Now that we created this options here. Let's go to the player script and now we can check inside this physics cast if statement. Now for the move player, we can add an if statement. Basically we want to check if the interactable only is not true, it's false, then we want to move the player. Otherwise, we want to ignore this code here and just do the interaction and save this. With this changes, we can create some things. For example, let's just try to modify this object here. Okay. And let's just add an intable script. Okay. And then let's add a message action. But here, as you can see, we don't have the Boulan option because our editor script for the intractable doesn't render that. We need to go to the editor folder and open the intractable editor, and we also need to create a serialized property, and let's grab it inside un enabled by accessing the serialized object and then front property and access the only with lower se L. And say this. Now we can draw the inspector using the editor UI, property field and insert the Suds only property. Let's create a label using the new UI content, and then just type a string inside the parameter only this with a semicolon and then save this. Let's go back to unity. Now if we click on the cube here, we should have this only option, and Let's try this only option and Let's give the box cursor for this sprite cursor under the interactable inspector and add new message, let's just type a message. We can just add action and direct the messes action, save the scene. We will also need to change this layer to interactable. But we can create that inside script. Whenever we are adding new interctables to an object, it will set the layer to interactables by def. What we want to do is we want to create a new build in method and it reset. And then we can set the game object layer layer mass, name two layer, and we grab the layer name and just to make sure that the layer name is interactable. So let's just type that interactable and save this. Now if I let's delete this again, this interactable script. And the interruptable script again. It will change the layer automatically to intertable as you can see here. So we don't have to set every time we add an intertable component, you don't need to change the layer manually. Then we can just direct the message action again to the action slot and enable the only option and also at the cursor. And save the scene. If we now try to test this feature, as you can see, we have a really nice cursor and if we click this, it will only show a message, but our player will stay in its position. Yeah, that is the features that we need to add to create a looking at something behavior. Okay. 47. 46 Preparing City Scene: Now we created most of the components that we needed to create this game. Now let's start to create the lighting and set up the global illuminations for each of our levels or our scene. Before we bake the scene, let's create a pref for each of the manager, so we can easily add this onto the other scene, direct the audio manager, and also this pw manager and the camera manager. And we have created the C before, so I'm going to go to the scenes folder and open the city scene. Now we have the scenes opened. Let's just revert the city that we have here. First, we want to delete this directional light, the second directional light and we want to only use one light. We need to make sure that the scene is during the nighttime. Let's go to the lighting and if we go to the point click here under the material, we will have We will have the sky the night sky box over here, and we are going to use this for our skybox. Let's go to the lighting panel, and if you cannot find the lighting window, just go to the window and then under the rendering, open the lighting settings, and it will open this panel and wreck the skybox, or we can just browse in the skybox material and choose this black skybox Let's clear the big a first, so we will see the real time result of our lighting of our current lights. Now I'm going to filter out our lights here so we can modify all of the lights in our scene. Just type T for types full colon and then type the component name, which is light, and we will able to see all of the light that we have in our scene. I'm going to select all of the spot light. I'm going to change the mode to only. Then I want to set the indirect multiplier to 1.5. For the point light here. I'm going to also change this to bake. The light will only get speak and it will reduce performance overhead. We have two directional light, as you can see here. I'm going to select the second one, the one with the yellow to whitish color, and just use this one here. Let's just clear out the search bar here so we can see all of the other object now. Now we have this Let's save the scene again. Now let's try to bake the light here. I'm going to change this to enlighten. We will have a softer lighting and change the light resolution to 20 and also the light map size to 259. I'm going to enable the ambient occlusion and I'm going to increase the indirect contribution to two and change the light map parameters to default low resolution. Now, let's try to generate the lighting and I'm going to cut the video and go back when the baking is done. Now, as you can see here, we finish baking the lights and we have a very nice time lighting, and we also have a very nice ambient occlusion, as you can see here on the air conditioning unit and the line between the pipe and the wall here. We have a nice smooth shadows on the edges here. Case. Now let's save the scene again. Now let's try to play this game. If we move the player, as you can see here, the player doesn't get affected with the light from the light pole over here. Because our spot light it sets to bake only, and we want to create an effect, so it will affect any moving object such as character and BC but still at a very low performance overhead and without activating a real time light because we already have one real time light in our scene, which is the direct directional light here, and it casts the shadow for our player. But if we make all of the Spot light or the light pole the lights on the light pole here, or to be real time, then it will be to perform or too costly for performance. We will need to create a light props. Basically, light props is a way to sample the lightning information in certain areas and our player mesh can sample from that lighting information without having to do a expensive real time lighting calculations. Now let's open the City game object and let's create a new child object and under effects, under light, we have this light probe group. Let's create that light probe. And I'm going to go to the front view and disable the perspective, so we will have an ortographic view. I'm going to move this light probes by holding the control to snap by one unit. If we go to the inspector here, we can edit the light probes. I'm going to edit the light probes, and I'm going to switch to the top view here. Basically we can by editing the light probes, we can select each of the light prop we can move the light probes individually. I want to select this light prop in this area here, and then I want to press a control D. I can duplicate this light prop press Control D and then hold the control to move it to this position here and I'm going to move this one one unit on the z axis. I'm going to select this one again, and then press control to duplicate again and then hold control to snap and move the light probes and put it in this position. Also, this one, I'm going to press control duplicate and then move it by holding the control. And let's select all of this light probes. Hold the control and move it to this position. We will have a light probes or distance three units from each other, and we can duplicate again and we can start filling our scene with this light prob Press another control and then duplicate and then move it by holding the control, snapping, So I'm just pressing control the and hold control when moving repeatedly, and we will fill this scene in no time with this light probes. Let's just set this one and then expand this to the side here. Okay. Now let's select this light probe here and duplicate this. We don't need to select this here because the player cannot go to this area. Let's just select this light and then press control D again and then start positioning. Basically, we are done with our light probes, and if we go to the front view here, we don't need to duplicate or we don't need to move the upper light probes to higher position because our player or the moving objects in the scene is not very tall. As long the light probes cover the moving objects area, then it's safe. Now we have the light probe, we need to rebuild the light. Let's go to the lighting tab here and then press the generate lights again. And I'm going to stop this video and continue when baking is done. Now baking is done and we can just unselect lightbe it doesn't occlude our few here and save the scene. Now if we press play again, try to move into the area where there is a light and we will see that our character affected by the light of that area. And this is the light probes effect and it's quite performance because it doesn't add any expensive calculation, such as a real time lighting if we go to this position here, you will see that our player will get a reddish light because we have a lighting or red light on that area as you can see here. Although the light mode is set to bit. But with this light probes, it will still affect the moving objects in the scene. Whenever we change the lighting settings or lighting position, we need to update the lighting data to update the light probe. And we are going to set also for the other scenes to set the lighting for the other scenes. 48. 47 Preparing Club Hallway: Now let's continue to prepare the other scene. And in order to do that, let's create a new scene. And now we have the new scene. Let's go to the point click folder. Inside the point click folder, let's go to the prefabs subfolder and let's select the club hallway and drag this to the scene. Now we have the club hallway. Okay. And let's delete the directional light. And first, we need to save the scene. So let's just save the scene under scenes and let's just call this club Hallway. And now let's enable the lights. I think is already enabled. Let's see. Yeah. Now we need to add lights to the scene here. Now, let's create a lights for the scene here. First under the club hallway. Let's create a new empty game object and this will be the holder of the lights group. Let's just call this lights. The next thing I want to do is go to the lighting here and let's disable the autogenerate we won't have legs because sometimes with autogenerate we can have legs. Then I want to add a light and this would be the point light. Let's position this. I'm going to go to the orthographic view, and I'm going to align the first light to our light object here, let's move this here. If we go to the perspective view, let's set up our lights so we can see it better. First, I want to increase the range, let's just test this 15 or ten should be fine. I want to increase the intensity and let's set this too big, and we can add shadows. Okay. And then we can duplicate this light here and let's go to the top of you again and move it to this position here, and then duplicate both of the light here by pressing control and then move to the other area of the room here. Okay. So now, as you can see here, we have the lights. And another thing I want to make sure is that it's a bit dark here. Or we can just disable the shadow. We have a very soft light. Let's decrease the range here. Maybe set this two eight. I want to change the color to be slight yellow has yellowish orange tin. Another lights that I want to add is a area light area if you have seen area lights from the photo studios, and this is exactly like that. But it's only for big lighting and it can have a very nice bleed lights. I want to change its size here by selecting the point on the edges of the area light and then move this to the top here and increase the size. I want to change the color to a reddish. So we have some redhled on this area here. Now we have set our light Let's save the scene again and go to the lighting. And here, make sure that we have selected and lighten and set the indirect resolution to light map resolution to 20, light map padding, and we can just use a lower size light map because the scene is not that detailed, 256 would be fine. Make sure enable the MB and occlusion and we can increase the indirect contribution to. The default value should be one. Also for the big mixed lighting, make sure it sets to substrative instead of shadow mas, because the default stings was shadow mas and set this to subtractive. And we can disable the real time global elimination and disable the sky balk also. We don't need that. Let's just use a grace color or we can change to a certain color. Okay. The next thing we need to do is we need to add a light probes, and let's just add the light props under the lights group here. Under the light, we have light probes. Let's go to the front autographic view and move this one unit up. On this. Now if we go to the inspector, go to the top view. Let's duplicate or let's press the edit light props button, and now we can select the light prop press control D and then hold control to move it. Press control D and hold control to move it and press control D and control to move it, we have a snap. I want to disable the light probes and move this it fits our hallway and edit light props again, and then select the side, the top area here, press control, and then move it by using control to snap. Until we fill out all of the hallway. But this part here, I want to make sure that it's inside the club hallway inside the room, and this area, press control and then move it and then press control and then move it again. So, let's disable this and move it so it's more centered. Yeah. Once we already set up the light probes, we can go to the lighting tab and save the scene, of course, save often, and then press generate light here. And this will calculate the baked lighting. Okay. Now we have this light, as you can see here. But we cannot see the directional light at the area light that we have here. I'm going to move this to the wall here and make this bigger and also make this taller. I'm going to generate the light again. But before that, just increase the intensity to three and then press generate light again. And let's wait until let's finish. Okay. Now we have a reddish area here, but I think we need to move this slide to the back because we have this color bleed and we have this dark area here. Let's just generate lighting again. Okay. Now it is much better. And this is basically the scene here and make sure we already set up aesthetic, but we don't want to set the door esthetic, so I disabled esthetic on this door here. If we go to the navigation menu here and we can access this inside the I believe it's under the general. No, it's the Okay. AI under the AI navigation. Just press beak and it will create a path for our character to move. Now save this and we can test this. Let's go to the prefabs folder, and in order to test this, we need to put the player first. But we also need to put a base canvas all of the prefep that we use for the game. Let's just direct the audio manager, the camera manager, and also the pawn manager. For the Canvas to work or for the UI to work, we need to add a event system. Let's just add one and save this. Now if we play this, as you can see, we can move our character. The sound is working right away because we have the sound the audio manager set up. We can go inside to this room here. But later, we are going to create a mechanism on how to open the door automatically when the player is near. 49. 48 Preparing Office: Okay. So Hello, we are going to continue our lesson. And on the last video, we are lining the club hallway. So now we are going to set the light for the detective office, Wes Office. So let's create a new scene. I'm going to call this we office. Or we can just call this office, and let's open the scene. If we go to the point lick folder inside the prefabs folder, we will have this off pre just direct this to the new scene, and this is the light has been set up basically. All we need to do is to bake the light. Let's disable the to generate. Let's just clear first. Let's set this to lighten and we can decrease the light map resolution, two ten, make it faster, and we don't need a very big light map size here. Let's just decrease this I think 256 would be enough. We can just disable the real time global elimination. The other thing we need to set is we need to set the camera. We want to have this angle. Once I've set up the angle on the scene editor, select the camera and then press Control Shift F, and we will have the same view in our scene. Let's just this a bit and reposition the camera by holding the control Shift F and select the camera, we want to set the background to a solid color and change this to black. Now, let's create a light probes. I'm going to create a new empty gave object, and I'm going to call this light probes. And create new light props under light. We have this light prop group. Let's create that. If we go to the side view on the x axis here and press the circle the middle circle object here, we will switch few from the perspective to orthographic. I'm going to move this by holding control, so it will snap by one unit, and let's edit the light props. Let's select this light props and press Control D to duplicate and then hold control and we want to move on the x axis. And let's select this one here. Press control the again and then hold control, choose snap, and let's just duplicate again and then move it only one unit. If we disable the dit light props, let's just move the whole light prop group. I fits with our s here. Then from the top view, Let's move this to the site and press edit light probes again and select the one in the middle, the whole row, and then hold control D and then hold control to move the light probes to the side here. Now we set up the light probes. Let's just pick the lighting, go to the lighting type again. If it's not there, just go to the window, I think it's under the rendering. We have lighting settings. This will open this panel here. Now I'm going to enable the ambient occlusion, I'm going to set the direct contribution to 0.5 and leave the indirect contribution to one. And save the scene. Now let's generate the light. I'm going to cut the video and skip it to the part when it's done. Now, the lighting is done, but I forgot to delete the directional light. Let's just select this directional light here and delete this we shod have something like this, go to the game view and Let's just regenerate the light again. Yeah. This is our scene for the introduction, and we will set up some sort of a cut scene in the scene here. Now let's just save the scene, and I next video, we are going to continue to light our last scene, which is the part that will be off for this video. Okay. 50. 49 Preparing Park: It Now we are going to set up the last scene of our game, which is the park. In order to do that, let's create a new scene and go to the point click folder. Under Prefps we have a park prefs, and this is the whole scene, let's just direct this to our scene. And now we have this here. First thing, we need to adjust the camera position. I'm going to set the camera to be around this position and we want to disable the autogenerate it doesn't keep on generating the GI or the lighting. And let's just set the camera to disposition here. Once we are happy with our view, the set our main camera and then hold the control shift F and it will reposition. But as you can see here, if we go to the game view, we have this empty area shown here. We need to make sure that our camera is closer. Let's just change this to local, and then we can move it on the z axis and move it to the side here, rotate. I'm going to also rotate the camera and then move it again. Another thing we can change is we can go to the inspector and we can change the field of view to a lower value. So the camera is not as wide as it should be, and we can lower again to around 45. Now if we go to our scene view, we will have a how view of our park and it doesn't show the empty area over there. Okay. Another thing we need to do is we can just delete our default directional light from our scene here, and then select our camera and we want to change the background color. Let's just set the clear flax on the camera component to a solid color and then change the color to a black color. And let's set up the lighting. Open the park prefabs here and under the lights, we have three lights, first one is the directional light, and we want to make this slightly darker, darker bluish. Then we want to change the bake for the point light here, we want to also change the mo and we can just enable soft shadow. Also for the directional light. Let's just it's already been enabled, and for the light on the fire here, set this also to bait and set the shadow type to soft shadow. Okay. Or we can just disable the shadow because it doesn't look very good here, as you can see. Now we have set up all of the lighting here. Press apply for our part, and to save this back to the prefabs. Now I'm going to create a new light probes, and this is for shading the moving parts of the scene, which is the character, and let's reset the value. If we go to the ortographic view here, I'm going to move this by holding control, one units up. Okay. And let's just press edit light probes and select the bottom light probes and move it to line with the ground here. Let's duplicate the side light probes here. I'm going to first move this so it covers the area here, and this one, move it to this position, then select this one and I'm going to to press control D to duplicate and hold control to move it and press another control D and select this one and press control to duplicate and then move it by holding control. Okay. And then from the top view. We are going to move this p to the side here and this one to round this position and then press control to duplicate and select this one, press control D to duplicate. Yeah, I think this should be enough and we want to save our scene so we can bake this. Let's save this and go to scene, and then I'm going to save this as part. Now that we have created this light probe. Let's go back to the lighting panel, and I'm going to change the light map to enlighten. I'm going to decrease the light resolution to around ten, and the other should be okay. The other setting should be okay. For the light map size, I'm going to decrease this to five 12. Then we want to enable the ambient occlusion and set the direct contribution to around 0.5. Safe again, and let's generate the lighting. Now the lighting is done, and let's check this from our game camera. But as you can see, it's b bright we want to readjust this, open the park game object and under the light. We want to lower the intensity of our directional light. Let's change this to around 0.5 and then generate the lighting again. I think it should be enough and let's save this. Now if we drag the player, go to the prefex folder on the asset one and drag the player, as you can see here, we don't have any real time lights. If I select all of the lights here, you can see that all of the light is baked but the player will get lighting information from this light probe group. If I move this, it's getting more reddish, and if I move this further away, it's getting more yellow because we have a fire here. Here, it's a more darker lighting. This will eliminates the moving parts or moving objects on the scenes. Very nice. One thing we need to add is the taxi and I forgot to put that, so let's just go back to the point click folder under the models. We have a taxi. I'm going to direct this taxi to be the child of our park game object. I want to enable the static on our taxi. And let's move this on this position here, and if we check it on our game scene, we want to see more of the taxi. Let's just move it here. Now we have this. We want to make sure that later the player will arrive from this taxi position. Now let's go back to the lighting panel, save the scene and regenerate the lights. Okay. Now it's done. We have a slide shading on our taxi, and let's just delete the player and we're going to set up the scene later. Now, save this and we have set up all of the scene for our game, and in the next video, we can start designing our gameplay based on the story of our game. Okay. 51. 50 Office Cutscene: Now we are going to start to develop our games and let's start with the cut scene. I'm going to save this park scene here and go to the scenes folder and I'm going to open the office scene. First, we already have adjusted the ama, let's just start creating the asset needed for this cut scenes. The first thing we need to do is we need to create an empty and let's reset this empty. I'm going to rename this two opening timeline. And let's open the timeline window under sequencing, choose timeline. Let's direct the timeline window to the bottom panel area here. Let's create a couple of anti game object, and this will be the first dialogue. Let's just call this dialogue one, then we are going to copy this later, but right now we are going to set this and we want to create another anti game object, and this is for changing change scene Okay. And we need to put the UI prefabs that we already prepared. Let's go to the prefabs folder, the one that under assets folder, and let's drag the data manager. Put it on top here. I'm going to drag the base canvas. And we need to create an event system. Let's go to the UI here and then create a new event system. We are going to also need to put the character. I'm going to go to the pref under the assets, tiny people, T and then under the pre direct the male B to run this position here and we're going to set up this later, let's direct female and put it here. Okay. Now we want to adjust the position of the character. I'm going to go to the orthographic view and then put the female character over there and for the male, I'm going to put it here. Let's say this. Let's put the character below here below the timeline, so it's easier to access. We want to scale the scene, so let's just select the office object and scale this to be 1.2 on all access. So we have a bigger scene. And we are going to set up the timeline. Let's just select the opening timeline here, and then under the timeline, let's create a new timeline file. Let's save this under the assets and we are going to create a new folder called timeline. Let's just call this opening and say, now we have this timeline here. We can create a couple of groups first, so let's just create a new track group and this would be the character. The next one would be a script or event. And I'm going to also create a new environment track group for grouping the animation here. For the character, we want to add an animation track, and let's direct theme character here. And we can put an animation over here. So let's just add from animation clip and we can pick here and let's search for the mail set. We want to use this one here. Now if we play this, you'll see that it has animation. And we want to set this to start from the first frame, but as you can see here, the position is not, if we try to move the character, as you can see that when we go back to the opening timeline again, it will snap the position. So to fix this, we can move the offset here under the t under the mail animation clip in our timeline, and we can adjust the position. I'm going to adjust the z position. So it sits on the chair and move the y position, something around like this. So if we see in the game view, we will see it sits nicely on the chair. Okay. And now we want to animate the female. Let's just select the female, sorry the female one. And under the opening time line, let's create a new animation track. And this would be the female character. And we can add animation from clip and let's select the female walk. Now we have this walking animation, as you can see, and I'm going to put it here and I'm going to scale the walking animation to around 150 frame. We have a longer clip playing. Now we want to set the position, the starting position around this position here. Here, as you can see it holds a knife, and we want to hide that knife. Let's just select the female object and select the knife game object here and hide it. Okay. And now we have a very nice walking character. And now we want to also rotate the character. So let's rotate this 180 degrees on the y axis. So it face the detectives. And we want to create another animation track, and let's drag the female here. And we want to create a new animation. So let's just hold the record button and move to this position here. And we can move the female object to around this position. Okay. Yeah. So we will have a we need to also key the first frame, so let's just move this back. Now we have two key frames as you can see here, and if we scrub this, you will see that it's moving and we want to move the first key frame. It we can just this recording and we can double click on the track and it will open the animation track set to finish quicker. Let's just move the keyframe to this position here to 2 seconds. And then go back to the timeline here. And for the other track that have the female work clip, we want to add another animation clip, and this would be the female talk set. Now we want to move the female toxic animation clip to overwrite or to transition with the walk clip here. I'll just move this and overwrite slightly. Now if you see here, when it stop, it will start sitting and talking. We want to set the correct position. Let's just select this clip here and enable the record button on the animation and then let's move the female character. Sorry. Let's select the timeline again at this position here. Let's just enable the record button on this timeline here. Now let's reposition the character, not the opening timeline, but select the female character, and then move this to the site here on the x axis. And also move this on the y axis. It sits on the chair. Now if you play this, it will stop and it will transition to the sating animation. And also, we are correcting the position. The female character sits on top of the chair here, and we can just stop this recording, and as you can see, we have a very nice animation. If we go to the game view here and disable the base canvas for a while, let's save the scene and then select the opening timeline and we can play this. And you'll see that we have a very nice animation. Next, we are going to create the dialog for the scene. Now we are going to create the dialogues for the opening sequence and also an event to change scenes once the sequence is finished. In order to do that, we need to create a new shop script. Let's go to the scripts folder, and let's create a new interruptable script, and we are going to call this a trigger Sorry, start interrat now we can just open this script. Now we open the script. Let's start creating the variable that we need to make this component. Basically, we need to create a new serialized field, and this would be a type of actions, and it will be an array and we can just call this actions. Another option we need to have here is a bulon This is for hiding message. We want to hide message on disable, and then we can just delete the start and the update method since we are not going to use that. Basically, we need to create a new enable method, and also on disabled method. For disabled method, we are going to check if the hide message. If the hide message on disabled is true, then we want to access the dialogue system, instance, and then we want to hide the dialogue. For the nenable we want to run an action. We can use, not the editor extension, but the extensions that we've created, the static class, and we can use the run actions method and we only need to pass the list of actions, the array of actions that we have here. I'm going to pass the actions and then close this. Now we are done with this component here. We can start using it in the editor. Let's go back to the Unity editor and access the timeline by selecting the opening timeline gain object and we can see all of the previous timeline that we already set up with our character. Okay. And now we can create a new activation. So basically, activation track is for activating object and we can drag the first dialom here. Okay. And we can move this dialogue to around the position where the women sits, and then we can start the dialogue. Here, for the first dialogue, we want to add the start in. Then we want to also use the message actions and add message, and we can type a message here. And for the first message, I'm going to type. I've already prepared an opening dialogue, so I'm going to copy this line here. And paste this here. Then the next thing we can do is we can duplicate this dialogue game object, and this would be the second dialogue. Go back to the opening timeline here. We can create a new activation track, and then we can move this around maybe this position and drag the second dialogue. For the second dialogue. We want to change the message to the second message. I'm going to grab from this document here, and then delete the first message and then paste the second message and basically we did four dialogue. I'm going to move this, so it's more tidy and change the name to the third dialogue and this will be the fourth dialogue. For the third one, I'm going to just copy the fourth dialogue here. Okay. Okay. And paste this and for the fourth dialogue. Let's just copy the last dialogue that we have over here, and then go back to unity, delete this and past the last dialogue. For the change scene, we are going to also use a start in and add action, one, size, and we can use the change scene action and direct this change scene action to this position here. For all of this dialogue here, we can just select all of them. Then we want to make sure that we are hiding the message on disable. For the change scene, we are going to go to the I believe will be the C scene. Let's check this. Yeah, C. We want to start the game from that scene, type the C. And then on the timeline, we can access the opening time line again and we are going to add those game object as activation track and going to add three different activation track. Now we are going to direct the third dialogue to this here and the fourth one to this slot here, and the change scene should be on the last one. And we can trim the dialog timeline here and move this and we need to make sure that our timeline can cover all of this dialogue here, and the player can read it so it should not be too fast, but not too slow also. Once it's finished, we want to change scene, so we can just use this for changing scene in here. I'm going to save the scene. Then in order to test this, we need to play this. But another thing I want to do is I want to create an animation track Okay. And this will be the fan that we have here on top of the office. So let's just expand the office, and I'm going to direct the ceiling fan game object and direct this to the slot here. And I'm going to eimate fan, and then I want to rotate the I believe it should be the ceiling fan game object and should be the rotation. Let's just set this back to zero. Then at the end of the timeline, set this maybe around three 60 by ten. Yeah. So it rotates very fast, and we can just Now we have this, but in the first frame, we need to chase this pac to zero, I believe. So we have rotation. Let's just top this and let's just access the clip here by double clicking it and we can just adjust the value here. So the first rotation value. Let's check this Okay. Okay. The y should be zero. And then we can change this to maybe around 3,599. Okay. As you can see, we have issues, so we need to delete the key and then set a new rotation. Let's create a new key here at key and set the rotation value. It's not y, and it should be the. We are going to rotate the z axis to 30005991 angle less than 3,600. And it's currently not rotating. Let's just enable the record button again. If we zoom this, we have two keys here. We are going to delete the first key and it should rotate. As you can see, it rotates. Then we want to make sure that the animation is linear. If we zoom out again and then go to the curve, we can select all of the curves here and click. And set the left tangent or both tangents should be linear. It should be linear, and go back to the sheet to the dope sheet. If we play this animation, it will rotate linearly. We have that working and now save the scene. Let's test this by playing the scene. Okay. So it will sit and when it's activated, we forgot to activate base canvas so let's just reactivate the canvas and save the scene again. And now let's play this again. Okay, there seems to be an issue here. Okay. We don't have theta manager. Let's just drag from our prefs Okay. We do have data manager, but I found the issue. Basically, all of the child object that gets activated by the time line here are enabled on start and we need to disable that so it doesn't trigger any script actions, and let's just leave the enling of this game object by the timeline. Also, we need to set the dialogue. First dialogue, I'm going to direct the message action to the actions here. Then I'm going to add a line here and let's just call this grieving wife. Okay. And I'm going to copy this here for the third dialogue. I'm going to also add that information. For the second dialogue, we want to change this to will, for the fourth one, we also want to change this to will. This will inform the player which character is currently speaking. For the first dialogue, we already set this as an actions. For the second one, we need to direct the message action as the actions that we want to trigger on start. Same goes with the third one and also the fourth one. So now we can save the scene here and let's run this again. Now we have this dialogue, as you can see. Okay, there is an issue with the second one, and let's check for a timeline. Okay. So basically this here, so show the first dialogue, and this is the second dialog If we play this again, somehow This is the first one. Maybe it's overlapping, it's best to at a slight distance between dialogue, like this. Now let's save the scene and then run the game again. Okay. This is first dialogue. As you can see, when it's it loads the scene and then it goes to the first scene that we supposed to play to. That is basically how to create the cut scenes in this adventure game. Of course, we can always adjust the timing of the dialogue, so the player can read this better. I'm going to adjust this later. And, that's all in the next video, we are going to start building our gameplay on other scenes. 52. 51 City Gameplay: Now we are going to work on the C scene. Let's just open the C scene here under the scenes folder. Let's go to the CN view here. Now we are going to create a bouncer that will guard this door. Basically won't be able to enter the club via the front door, so we have to find a way how to get in. Another thing we need to do is we need to add the audio manager. Let's go to the prefabs and direct the audio manager. And let's test this and see if there are any other prefep that we need to put. Okay. So basically, we have this error. It asks for a cursor script. So under the base canvas here, let's just check this error. Okay, I asked for a camera manager. Let's just go to our prefabs folder and direct the camera manager. Let's just put all of the manager on top here so we can see it better. I'm going to also direct the data manager, put it on top here and save the scene. And let's press play again. Okay. Now, we don't have any error. First, we need to create a new empty group, and let's just zero out this position, and let's just call this incles we are going to put all of the interactable objects under this antigua, the bouncer on the scene here and let's create another anti game object and reset its value, and let's just call this characters. And I'm going to go to the two tiny people and let's go to the prefix folder and drag the male A, and let's put it here. Under characters, sorry. Let's create a new game object under this male object. Let's put this out here and drag the male object, and let's just call this PC underscore bouncer. And let's rotate this, set the y rotation two zero, so it's facing forward and then let's wreck the bouncer to be the child of this character game object. For the bouncer, we want to add a intertle In order to do that, we need to add a collide add a capsule. Let's just adjust the collider, so it fits with the character. Okay. And then we want to also add a action, an intractable. And let's choose a sprite cursor and let's use the pop cursor. So whenever we are over this character, our mouse will show this pop cursor. And then we can add an action. The first action that we want to add is the message action and the other one would be the audio action. Let's add a couple of action. For the message. Let's just say that. We can add a name bouncer, and then enter and then we can say you're not allowed to enter. Then we can add an audio clip and under the audio folder. We will have this dialogue, and I'm going to use the mail C dialogue no. This is for rejecting, let's track the message action to the first action slot here, and the second audio action to be the second actions, we are going to create an animation for talking. Let's just go to the animator folder, and then let's create a new animator controller, and let's call this bouncer. And under the bouncer object that have the animator, the child object. Let's direct the bouncer to the controller, and let's open the imator we can put the idle. Okay. And for the idle. Let's just use the I think we have this male d A. Let's create a new states do we have the talk only? This is t. We can just try to use this later we can search for animation that have a talk while standing, and let's create a trigger. The transition and for the transition, I'm going to create a new parameters and add a trigger and let's just call this talk. I want to trigger the talk animation whenever this triggers gets triggered. Let's just add a condition and add the top condition. And we want to make another transition from talk to back to idle and enable the exit time and for the idle to talk, we want to disable the exit time. Now we have set up the animator. Let's go to the object of our bouncer here and then add the action. And let's create an animation parameter, and we want to trigger this talk action. So let's just trigger Paul. And then under the bouncer, let's strike the child object to the lowest actions here, the third actions, and it will grab the animation actions right away. Let's save the scene and let's test this. Let's click on the bouncer and it will go to the bouncer and then the SM. Okay. It it shows this message and then it play the animation, and it also play the audio, as you can see. Then under the interactable, let's just create a new empty game object, and let's just call this front door front door interaction. Let's create a new box collider. This is the object. I'm going to put this around here and I'm going to rec the collide it fits our door. And let's just push this back, it aligns with our door. Then let's create an intractable. We want to make sure that this is look only, so the player won't approach this object, and then let's choose the icon and then for the actions, let's add an actions and add the message actions. And let's just type the front door is guarded by the bouncer. Then direct the message action to this action slot here, save the scene. Now we have set up the front door. Now we want to create the side door so we can transition to the club hallway scene. Now let's create the side door interaction. First, we want to create a new empty game object. Then let's put this game game object to be on the side door here. Something like this. We want to make sure that the z rotation is facing to the current right rotation. We need to change this to local and then let's rotate this. So now we have the zero rotation is facing here. Then let's call this side door. And we are going to create a couple of empty gamock here. The first one will be the no password. So if we haven't found out the password yet, then we want to show this message. Let's just add a box collider let's just adjust the box collider. Okay. And then let's add interactable and we want to use the top icon. And for the action, we want to add a message action and we can add a couple of messages. Direct this message action to the actions, and we can type for the first message. And for the second one, We can type door, and then we can type what is the password, and for the third one, we can type and then we can type chicken steak. Then we add a new message for the fourth message, we want to set the door to reply. Nice try. This is for the dial up when we don't have the password yet. Let's create a new empty game object under the interactable. And let's put this here in front of the wall here, and if we zoom in, you'll see that we have some sort of a writing on the wall, so we want to put it there, this empty game object here, and add a box glider. And let's just make the size smaller 0.6 on all axis. Then we want you to set this to a trigger, so it won't block the player movement. Also add the interactable and let's just use the icon, and we can add two actions. The first one will be the message action to show the password. Let's just type. Okay. You you saw a writing on the wall and add the message? The password is H L. It's help. With this password shown, we want to activate another game object using the activate actions. Let's just direct the message action to the first slot and the activate action to the second slot. Then we want to activate a certain object and the object that we want to activate is basically this here. We have this no password and then we have the other one. Let's just call this password. And for the half password, we want to reply with the correct password that we already read, which just help. And then we can just type this. Let's modify our message actions and right take on the message actions and then open the script. And we want to create a new default actions. Let's just add a chain actions. And let's open the message actions editor. Okay. Let's go back to Unity and then open from here under script editor. We have this actions actions editor. Under the inspector GI, before we are showing the dialogue here, we want to draw a default chain actions. Let's just use the editor extensions and then actions array. We need to pass a serious property array. We need to create a new actions. Let's just call this score chain actions. Let's just copy this here, and we can use the chain actions variable that we've created and search for the chain actions. Let's just copy in variable name from our message actions class and then paste this as defined property parameters. Save this. Now we want to draw the chain actions for the label, we can just type chain actions. And then close this with a semicolon. Basically, we have this default chaining actions for the message actions component, and if we go back to unity, you'll see here when we select any object that have the message actions, it will have this chain properties. Another thing we need to fix is we need to open the dialogue system component that we have the dialogue system and we need to create another show message. So basically, we need to create an alternative of our show message, and let's just call this show messages, and we are going to pass a different parameters. And basically, we want to pass the message. And then we want to pass a list of actions. And just call this chain actions and set the fault to no. Here we want to show the multiple messages. For the multiple messages, let's just add this chain actions equal as a second parameter. Here below, we can check if we are not using any dialogue. And the message we are currently at the last message. Then we want to run the actions that we have. So let's just check if chain actions is not, then we want to use the extensions method that we created and let's just use the run actions method and pass the actions here. Okay, since this is a list, we need to convert this to a array. Let's just type to array, and this will convert our list of actions to array. So it is compatible for our run actions. Save this. So let's just add an action. Here, we want to use the change scene actions, and if we go to our scene here, let's switch to the club hallway. Let's just type the scene name, which is club hallway and then drag the chain action to the chain actions under the message here and save this. We want to disable the half password first and we want to enable the no password one, and let's just call the writings on the wall. For the writings on the wall, whenever we are clicking on this interactable. We want to show the message, and then we want to add an entry for the activate actions, and we need two entries. Basically, we want to disable the no password and make sure this is unchecked and then for the half password. We want to enable this one, we need to check this checkbox. This way, it will disable the first entry and then it will enable the second one. Let's just save this and let's try this. Okay, so let's go to the position here. And right now, we don't have a switching camera mechanism, so we need to add that to make this easier for testing. So let's just create a new camera. We can duplicate from our main camera. And let's just call this side door camera. Okay. And let's change the camera to be something like this should do. Select the camera and then press Control Shift F, it will align this camera here. We want to disable this camera. Then for the camera, we want to add a trigger area that will trigger the camera here, camera changes. So let's just create a new empty game object and then add a box glider and set the size to run five by five by five. Okay. Basically, we want to set this area. Whenever the player enters this area here, we want to switch the camera. Let's just make this slightly bigger and enable the trigger options, and then we want to use the change camera. We want to use the switch camera actions, and let's just direct the camera to switch to the second camera here. Okay. So if we select this camera switch, let's just call this side area camera switch. Let's add a new switch camera actions, and this will be the main camera. So we need to set a two switch camera actions, and then we are going to use a trigger in. So let's just move the trigger to above this, both two switch camera actions. And then we want to trigger by the player. So change the trigger tech to the player. And then when we enter, we want to trigger the search camera action, the first switch camera actions. And whenever we exiting the area here, we want to trigger the second action. So let's save this, and now let's test this. Okay. So if we go to this position here, once a player enter, we should see that we are switching the camera. Now let's try to click on this password and then press. Okay. Now once we already see the password here, you'll see that the interactables will have changed the child activate status. Let's just test this one more time. Okay. Let's go to this area here, and then let's try to talk to the person on the door here, and then it will ask for the password, and we will answer it wrong, and it won't open the door. So once we saw the writings on the wall here, it will change the child object to the half password one, and if we press this, Okay. And then when we click. Okay. So we already have this, but somehow it doesn't trigger the change scene action. So we need to modify the message action square. So under the message actions, Okay. We want to use this if we are enabling the dialogue, then we want to run this one. But if it's not, then we want to run the dialogue systems, instance, show message, and then we want to pass the message and also the chain actions. Let's save this. Now let's try this again. Let's go to this area here, and then let's read the password. Okay, sorry, there is an issue here. We already showing the message, but I believe under the dialogue system, we already created a new one, but we aren't showing the message, so we need to run the routine here. Then let's just pass the Let's pass the current message the message to our current messages. And let's just set the dialogue to falls, and we want to pass the chain of actions that we have here and close this with a Semicolon. Okay. Let's test this. Okay. Okay, let's go to the position again here. And then let's see the password. We need to check this. Our password has a message and it doesn't have a chain actions. Let's fix a couple of things on the dialogue system here. The first thing we need to fix is this here. We need to test whenever we are finished showing all of the messages, so we should remove the negative one under the statement here. It will finish showing and then it will run the chain actions. For the show message, we need to basically reset the ID and then disable the button dialogue. I'll just copy two lines here. And paste this here. And we need to also enable the panel. So let's just copy this panel set active through before showing before starting the coroutine here. And let's save this. Okay, now let's test this again. Okay. And let's go to the area here and let's talk to the door and it will ask for a password, and we haven't read the password on the wall yet, so it will answer the wrong password. And then let's go to the site here, and then it will sew the writing. And once we know the correct password, we can talk again to the door. And we will answer the right one, and then it will open the door and then it will run the change sheen action. But since we haven't put the club away to the build settings, we need to do that. So let's just go to the build settings, and let's add the club hallway scene to the scenes in built here, and scene, save the project again. Now if we try this, it should work. So let's go back to the side area here and read the password and then talk to the door. And then as you can see here, it changed the scene to the club hallway, but we are going to also set up the club hallway on the next video, so the player will be starting from this door position here. Okay, so yeah, that will be for the CD gameplay, set up. And later, we are going to also add a taxi so we can go to the park from the CD scene here. 53. 52 Additonal Item Database Setup: Okay. Now in this video, we are going to set up the items that we need to set up in this game, and let's go to the data folder and under the atatabase. Let's create a couple of items that we need to create. First, if we go to the sprites folder, we will have this item sprites from our assets, and this is the item that we have. Let's just create those items accordingly. Go back to the data folder, select the item database, and let's change the first one to a portrait. Okay. Oh. Portrait, and then we can set the item description to a portrait of the missing person, and let's disable the multiple. And then we want to select those sprites, but we need to set up first so let's go to the sprite folder under the items and go to the sprite editor, and let's just drag a box on each of the item icon. And then sorry, once we finish dragging, all of them, we can select one by one and then press the trim button on top here. So it fits nicely and then press apply. Okay, let's close the sprite editor. Go back to the data folder and sack the item database. And for the portrait, let's select the sprite, which is this item seven here. And the key, we want to change this to a key here, let's add a couple of items. And this will be a money. And we can call this 50 bucks on description for the items right, let's select this money here. The third one should be a name card. Let's call this a name card with an address on it, and then select the name card for the last one, this will be a lighter. And let's just put it a small guess lighter on the description, and then change the icon to the lighter. Okay. And this will be all for setting up the item database and let's just save the project. Okay. 54. 53 Club Hallway Gameplay: Okay, so now we are going to continue setting up the club hallway. And first, we want to change the direction of the player. So let's just set the rotation of the player on the hit X to be 180 degrees. So it face forward here and move this slightly backward. And for this pawn manager, we also want to set this pawn from city to this position here. So let's just drag this. And then for the direction, let's set the x value to zero, and then sorry, set x value to one positive one. So it should face this red arrow here. Yeah, something like that. Let's save the s. Now we forget to add the data manager. Let's go to the prefabs folder and then direct the data manager to be below the main camera here. Save this. First, if we press play, then you will see that whenever we are moving to the room here, the door doesn't interact with the player, and it stays opaque, this wall here. We need to make sure to address those issues. The first thing we can do is we can select the door here and select the parent object, which is the pivot. For the pivot, we can add a rigid body, and let's disable the use gravity so it doesn't fall. And then add a hinge joint, for the hinge joint, we want to set the axis on the y axis. Let's set up the x value two zero under the axis properties and then set the y value one. Then we want to increase the spring value. Let's just use the spring value. I found that the value of 15 should do or 20 would be good enough. Then for the damper, I want you to set this to five. We will have a spring door and it will close automatically whenever we get passed through this door here. And we want to use the limits. But in order to set the value, we can just enable the added joint angular limits pattern here, and we can direct this. Basically, we want to direct this area around this position here, this angle. And for the other one, we want to set around this angle here. This would be the limit of our door, and this is the area that the door cannot rotate to. Now, let's just disable the joint angular limits. And then under the child object door, we want to add the box collider. Let's add the box collider. Basically, in unity, all of the box collider under a rigid body component, will be considered as its own collider. Unless we add another rigid body, then it will be a separate physics entity. But if we only add a collider, then this collider will be regarded as the body of this rigid body here. Why I put it on the box? Because when we put a box collider on a three D object, it will automatically resize it to that object here. You can always put the box caldor on the parent object, but you will need to set up the dimension manually. So yeah, under the child object here, the door, I want to modify the box caldor pressing the end collider, and then move the bottom area slightly to the top. So it doesn't friction with the ground object. And yeah, so basically we can save the sceam and then let's try it. Now if we try to go inside the scene here, the pair will push the door and the door will open and then we'll automatically close. Same goes when we goes out, it will open and then it will close. We want to do that also on the second door here. So we'll need to do the same at a rigid body. And then also disable the use gravity at a hinge joint. Then we want to set the xis to one on the y axis and zero on the x xis. Then enable the use spring and I'm going to set this to 20 and the dam pert five and enable the use limit options, but we want to add this joint by using this button here and set it to approximately the same value as our previous door and then disable this. We want to also add a box to the child. And let's add the collider, so the bottom area doesn't friction with the ground. Something like that. Now we have a working door. Now we need to select the main camera, and then we want to add a transparent effect. In order to trigger the transparent effect, we need to add the transparent trigger component into the camera and I've already done that. But if you haven't, you can just add a component search for the transparent trigger and then add those components to this camera here. For the wall object, we can add a box collider. To the wall object, and this will create a new box that covers the wall. But if we disable the trigger, then the pair won't be able to move through this wall here. We want to enable the trigger, and then we need to add a transparent effect. For the object that we want to able to change to a transparent material, we need to add the transparent effects, and then we can choose the transparent material. And we already create the transparent material here under the materials folder. I'm going to use that. Basically, the transmarent effects will change all of the game object and also the child object under this toilet wall here. Let's go to the other wall here and then add a box collider, and then enable the isrier and then we want to add a transparent effect and then choose the transparent material again, and let's save the seed. Now let's test this and see if it's working. If we go to this room here, you'll see that the wall will change to a transparent and we can see the player inside this wall here. If we go out, then it will switch back to the previous material. Same goes with the toilet. Okay. Yeah, this is for the transparent effect, and let's add a couple of NPC characters. Now, let's add the characters, the NPC characters, and in order to do that, let's create a new empty game object. Reset its value, and let's just call these characters. Yeah. And then let's go to the two tiny people folder and go to the preface folder. And let's direct the police officer under its character here. And let's put this somewhere around this position. And I'm going to put it here. And I'm going to make sure the police face the other way around. So in the game camera, we should be able to see the police character. So let's just move this on this position and then rotate this on the y axis slightly to this direction here. So we can see the police officer. And then let's drag the other person here. Sorry, male A again, and then put it under the characters. And let's put it inside the toilet here. And let's hide the baseball beat to activate this. And then let's put it around this position and let's rotate the character. And I want to create an empty game object parent for the character here. So I'm going to create a new empty game object. But then I'm going to direct this to be the child of the characters. And let's call this guy in the toilet and direct the male H to be the child object of antigamobject. And for the police, we can just use this and let's just rename this to security. And let's hide the gun object. So let's just select the hand gun and then disable it. So let's set up this character, these two characters. And the first police officer, let's add a capsule glider and let's adjust the size, so it fits. Okay. And then we want to add the interactable component? Let's just add that and then use the talk cursor because we want to be able to talk with this person, and this indicates that. And we can add two actions. And the first one would be the message action. We only need one actions and then direct this message action. And we can add a couple message type for the first message. We can ask this security. Have you seen this person And for the answer, we can just type security. And then we can just reply with. I haven't seen him around. And we want to add 18 actions whenever we finish talking with this. Security. We want to add a chain actions, and for the chain action, we want to add the activate actions. Let's just dd this actions as the chain actions. And whenever we're conversing with this security guy, it will trigger this action. Let's add a couple of two entries, and we are going to enable and disable some of the game object under this guy on the toilet. Let's just create the response first, and let's create an empty game object. Let's just call this normal response. Okay. And add a capsuler let's adjust the size of the capsuler. Okay. And then we want to add NPC, but the incable component, and let's use the top icons also. And for the actions, we want to add a message action, direct this message actions, and then add new message. And then we can just type guy in the toilet and we can let him say what are you looking A. Okay. So basically, the normal response is the default response if we haven't talked to the security guy yet. And then we want to duplicate this the normal response. And then let's just change this to talk to security guy. And we want to create a different message. So we can just show message that somehow the guys overheard our conversation with the security guy. So let's just say that I've heard your conversation with the security guy and then add new message. Let's just say I believe you will find the person in this address. Okay. So basically, we want to make that the toilet at the guy, you will give us or give the player name card whenever we finish talking to this guided toilet. So let's just add an item actions and direct the item database. So direct the item action to the chain actions. So whenever we finish this, it will give items. So let's just select the name card. And then we want to add a new actions showing a message that you got a name card with an address on it. And we want to show this message actions together with the item action. So when the player are receiving this name card, we want to also show this message. Okay. So we want to disable this game object here. And for the security guy. We want to switch the active status of this child object with the guy in the toilet. So for the normal response, we want to disable this. So let this game object unchecked and for the top two security guy, we want to enable this, so let's just enable this. And since the guy in the toilet have a two different response, we want to save this. So let's just add a safe entity component and it will automatically create the incense ID, and we don't need to change this because this ID will be unique. And once we talk to the security guy, we want to also create another response and receive card. And we can just type you'll find him on that address. And we want to make sure this is disabled. But when we are finished talking with the security guy, we want to add a activate actions, and then we want to disable this one. So we want to disable the game object itself, but we want to enable the receive card. Okay. Actions. And then we want to add this activate actions together with the message actions and the item actions. So it's get triggered, and then it will switch to this response. And all of the child o active status, this checkbox here, we'll get safe with this safe entity. So if we load the games again, then this will get sloaded the last state of the child object. So it will have different response depends on our progress. Save the scene here. And now let's save this and let's play this. So let's try to talk to the guy the toilet first. As you can see here, it shows the message, what are you looking at because we haven't talked to the security. So if we talk to the security guy. So if we talk with this security guy, let's talk security guy again, and it will tell us that this guy haven't seen the person that we are looking for. But if we go back to the other guy on the toilet here, It will have different response than before. So if we talk with him, it gives us a name card. As you can see, we have this name card with an address on it. And now if we talk to this person, it will respond to the last response here. It will enable the last response. Now we've already set up the gameplay on the club hallway. We want to test if the safe is working or not. So we want to make sure that whenever we save the state, we will save also the child status or the child object that are activated for the guy in the toilet. And since we have the safe entity, to the guy in the toilet, we should be able to save this. In order to enable the safe load on our base Canvas, we have the debug safe load. But both of this button doesn't have an onclick listener added to it. Since the load and save are on the data manager, when we save the base Canvas, those settings does not get saved together, since it's on a different object. In order to test this, we need to direct the data manager to the on click and then we run the function save data entry. For the load button, we want to also direct the data manager, and then we want to run the load data entry and we can just set the ID two zero for now, and this will be useful if we are setting a multiple safe entries later. Of course, for saving and loading, we are going to do this in the main menu, not in the game, but since we want to test this using the debug button, we are setting on this button here right now. Now let's save the scene, and then let's test this. Right now, if we press play, and then if we try to talk to the guy on the toilet, it will ask, what are you looking at? And if we talk to the security guy, if the security guy have seen this person on the portrait that we have on our inventory, it will response sorry, haven't seen him around, but when we talk with the security guy detailed object of the guy on the toilet change. As you can see here, it changed to talk to security guy, and we disabled the normal response. Now if we talk to the toilet guy, then it will say that I've overheard your conversation with the security guy. I believe you will find the person in this address and so forth. Once we talk this, we will receive the card, and as you can see, it enables the other child object. So if we talk to this person again, it will say different things than before. And inside the inventory, we should have the name card, let's go to this area here and then save. And we can see in the console that we successfully saved, so let's stop this, and then let's play again. And when we play this again, it should reset all of the states. As you can see here if I try to talk to this person again, it will response. What are you looking at, this is the default response or the normal response. And if we press load, it will load all of the state, including our player position, and also as you can see here, it's enable the last response on the guy in the toilet. If we talk to this person here, after we load our progress, it will say that we will find him on that address and we will have the name card. But since in the editor, descriptle objects always get safe, whether it's on run time or not. If we press play, you'll see that we have the name card from the start. In order to test this, let's go to the data folder under the inventory. Let's just delete the name card. If we press play, then we should not have the name card anymore, right now, let's just press load. And after we load if we press inventory, you see we have the name card. The inventory is also get safe right now. And you can see here under the inventory inspector, it adds the name card after we load the progress. So yeah, This is basically everything's working nicely as you can see, and in the next video, we are going to develop the other gameplay in the C. We are going to add taxi and then also a transition to the park. But before we finish up in this video, there's one thing that I forgot under the In the scene here. We basically need to create a transition to the outside or the C scene. Let's just create an empty game object interactable. Reset its value, and then let's call this interactables. Then let's create a new empty game object, and let's just call this exit door and move this exit door to this position here around this door here and let's add a box collider, and let's just resize this box collider. It fits with the door. Here. And let's make it thinner. So it fits and then add interactable script, and then we can just use the hand items. And then add an action and we can change using the change scene action, and then we want to go to the CT scene here. Let's just type the C name, C C, it should be with Capital C and then drag the change scene action to a slot here and save this. Now if we go back to the City scene, we can access the pawn manager. If we don't have the pawn manager, then we should put one into it. Let's go to the prefab folder and then drawn manager and put it somewhere inside the hierarchy. For the city, we want to set the previous scene to the club hallway. Let's just type the scene club hallway, and the scene name should be exactly the same with the file name here. For the club hallway, it's like this. Now we can adjust the club hallway position, and I want to set the player direction to facing that way. So let's just set the z value here. Let's just set this x value to a positive one. Our z direction is facing this way. Yeah, I think that should be all let's save the city here. If we go back to the club hallway and then we play this, Let's try to load the scene again. So we have the item and we have the states loaded and let's go to this door here. It's show transition to the city scene. As you can see once it's transition to the city scene, our player is standing here. Another thing we need to do is we need to add a taxi. After we leave the club hallway, we can go to the park and this taxi will act as a transition to the park scene. Let's go to the point clixFolder under the prefabs. I believe under the model, we have taxi there. Under the model, we have the taxi model. We can just direct this to the C. So I'm going to expand the CD group here and let's drag the taxi to this CD object. Okay. Now we have this taxi as the child object of the city. Let's just drag this and put the taxi around this position, and we can rotate it slightly. So the tire will contact correctly to the ground. And we can also enable the taxi to be static. And another thing we want to do is we want to add a empty game object. So first, this will be the response. This is for the normal response and the other one if we own name card. So the taxi driver will drive us to the address that are listed on the name card. And on the parent game object, the taxi game object, we want to add a box collider. So we can click on this taxi. And let's just adjust the size of this game object here. And once we already set the size for the collider, let's add an interactable game object. And for the sprite, we are going to set this to the top icon. And we want to make sure that the distance position It's one, but we need to make sure that the z values or the z position, it's facing the other way. In order to do that, we need to create an empty game object and then put this outside. Now we want to rotate this 180 degrees on the y axis and set this zero on the x axis and put it around this position here, and now we want to put the tax as a child object of this game object. And we can just call this taxi again and let's just move the interactable. Paste it here. Okay. I'm going to copy the box collator and also put it here. Drag on the offset the center value. So it fits with our taxi. Or we can just adjust the collider, so it's easier to add it. I think they should be enough, on the one that on the child object, let's just delete the box collider and also the interactable. Now that we have set up this correctly. I want to put the oxidor on top and set this to trigger. Now the next thing we are going to do, we want to put the normal in the response and the name card response to the pattern game object. This is the visual and this is the response. For the response, we are going to add a message actions. Okay. And then for the parent game object, the tax game object that has the interactable script. We want to add an item action and just add the item database, and we want to check for name card. So we said to give item and add yes or no. And another thing we want to do is we want to drag the normal response to the No, and the own name card is to the s. So if we own the name card, then we want to trigger this action, but if we don't have it, we want to trigger this one. Okay. So direct the item actions to be the actions of our intractable. And for the normal response, we can just ask where do you want to go. And we can add the name of the taxi driver. Okay. But for the own name card, we want to ask do you want to go to the address on the name card and we can set to enable dialogue and yes or no, and we can add a change action. And if you choose, then we want to trigger the change action here. Let's just change this two part and save this. Okay. Now if we go to the data folder and go to the inventory, I'm going to delete our name card and try to play this. If we try to talk with this taxi driver. You see, ask where do you want to go. But since we don't have the name card, we don't know where we want to go. So for example, if we add the name card to our inventory, then we can try to talk to the taxi driver again and it will ask if you press, then it will load the park scene here. Okay. Okay. So yeah, that should conclude the club hallway setup. Okay. 55. 54 Park Gameplay: Okay. So now we are going to start developing the park scene. And in order to do let's open the park scene under the scenes folder. So here we have this park and we have this taxi and police car and make sure both of the car objects are the child of the park and we want to enable the static. So if this is not enabled yet, make sure it's enabled and make sure it's also applied to all of the child object. So I'm going to check okay the static is also as a static object. Okay. So Now we can generate a navigation mesh. Let's just open the navigation panel. If you don't found the navigation panel here, just go to the window and I believe under the AI, there is a navigation panel. We can open this and it will open this window and now choose the big tab and press bate. This will create a area where we can walk for the player. The next thing we need to add is we need to add the prefabs that we already prepared. The first thing we need to add is the base Canvas. For this base canvas to work, we need to add an event system. Let's go to the UI panel and then create a new event system and put it this outside of our base canvas. I'm going to reset its value, the transform values. Let's add data manager, the camera manager, and the pawn manager and also the audio manager. Let's select all of this manager and put it on top of the hierarchy. We can save the scene. Now, under the prefect, we can direct the player and just put the player somewhere in the season. I'm going to move on the y axis slightly downward, and then put it here, and then I want you to rotate the y axis on the rotation to 180 degrees, so we're facing the other way and Sos. If we go to the game, now let's test this to see if we can work if we can walk on the scene or not. Somehow we cannot click it. First, we need to expand the park and then select the ground grass and make sure it sets to the ground layer, and for the tag make sure the layer is ground for both of this ground object we can set it to default, but we need to create a empty game object that will act as a cli. Let's just create a new empty and then add a box glider. And adjust the Y value on the size to be a very small one. But let's just set the sie to around 20, I believe. Then for the z axis, let's set this to 15. Basically, we need to create a box lider that covers the scene, something like this. Then we need to make sure that game object set to the ground on the layer. Rename to a ground collide and save the scene again. Now let's test this again. And now we can click and as you can see, we can see the character is moving around the scene. The next thing we need to add is we need to add an NPC. I'm going to create a new tame object and reset its value, and then I'm going to call this scene objects and put it under the part here, and then I'm going to add a new PC game object NPC group. Let's create a new and this will be the police officer. Let's add the police officer character under the tiny tiny people. Then under the TT demo folder, we have this prefpolder and let's direct the police prefab and put it under the police officer. Reset its position value to a 000 and then also reset the rotation to also 000 on all of the axis, and we want to move the parent object, which is the police officer. Let's just move the police officer or on this position here. And we can rotate this a bit. If we look in the game view, we can see the police officer and we are slightly floating. I'm going to push on the y axis to make the police officers contact the ground, its feet and then move this slightly backwards. Then another thing we want to do is we want to add a interactable. We will create a couple of interactable. The first one would be the wall, and we want to add a box collider here and move this slightly sideways. I'm going to rotate this so it's facing forward like this. Now first, let's move the box object on the y axis. We move this slightly to up position then let's scale the collider by pressing the ded collider button and I'm holding the control. I want to create a large wall that covers the scene and this one also. So if we go to the game view and then we enable the gizmo, we can see the collider is covering all of the rest of the scene here, and let's set z value to around 0.2. We have a tin wall, and let's intractable or we can just add the interactable component and it will set the layer automatically to interactable because we already set that in the script. And for the icon. I think I'm going to use the hand icon. We might need another icon for this, but it's okay. We can just use the icon, and we can add a message action. And we can no, you cannot pass says the police officer. So we need to inter and then type the name, the police officer. Okay. And save the seal, and we can trigger the animation. But in order to trigger the animation, we need to put the ate action on this game object and then we can direct the action to the wall here. The other thing we need to do is we want to create another anti game object, and this will be the interactable for talking to the police officer, let's just add a busider and then adjust its size. It fits the police officer Okay. And we can add an interactable. And we want to use the talk icon. And let's just add a message actions and type its name, police officer. Okay. Let's just say sorry, but you aren't allowed to enter the crime scene. Let's save the scene, and now let's try this. Basically, if we go to this collide here, it will go there and then, we haven't triggered the action for the wall here at the actions and directly messes action. Then for the other interactable object, we want to add actions and then put it here. And for the wall here, let's just move this position slightly on the middle, so it will stop at this position, our player when it approach this crime scene, and then we want to slightly center position a bit, so it covers our scene. Save this and test this again. So right now, we go to the wall here, the police will say that, no, you can pass. And if we talk to this police officer, it will say a different message. And here we are going to give the police officer a money to make sure that we will be able to enter the crime scene. Okay. So now let's continue and we are going to add a couple of game object here. So for this is the wall object. Okay. And when we click this, the police will respond to this message action, and this if we click on the police officer. Now we want to create a two different response, let's just create an empty game object as this child here. And let's rename this one to talk to officer. Okay. And the first one, we want to set this to give money. So this is for bribing. So if we respond, yes, when we are going to bribe the police officer, and let's add another empty game object. And let's just rename this to not enough money. So this is the response if we don't have enough money. And then we are going to add instead of a mess actions, we want to add an item action. Okay. Let's just add our database, and then choose the item that we want to give. Here, we have the money. In order to have this item, we need to go to the data folder and select the item database and create a new item. And if you haven't done that, then let's just do that. Let's go back to the talk to the officer game object here. Let's just select give item. Let's add actions, and no action. For the action, we want to direct this give money here, but we haven't add an action, so it won't work right now. Let's just create enable dialogue. Let's just sorry, but you aren't allowed to enter the crime scene area, and let's just add a unless and then add a grin here. So the police are expected to be bright for the y label, label this, give him money. And for the no response, just add ignore him. We want to add AS actions, and we don't want to add a no actions. For the action, we want to direct the item action. If we press yes, then the item action we'll try to give this money item to the police. If we enable to give item, this item will be removed from our inventory. So, we are responding with. Then we want to add another actions for another actions, we want to activate Oh, not under actions. We don't want to add actions, but here on the item action, we want to activate actions to this yes action. I succeeded giving the police officer money, then we want to activate some object and activate some object. Let's just add entry and direct the wall object and set this to the activate and also add another entry and talk to the officer, let's duplicate talk to the officer and let's just call this money gave. Or gave money. And we want to delete the item action on the gave money and also the activate action, and we want to disable the dialogue. And let's just say now you may enter the scene. Okay. For this item game object, we want to disable this on start. If we succeed giving money, then we want to enable that. Under the activate actions, add another entry and drag the gave money game object, and then enable this. We don't need the child so we can safely delete this child here. And for the talk to the officer, if we succeed giving him money, then we want to say a message. So under the give money, let's add a message actions, and also for not enough money, let's just add a message action. For the give money, just write police officer. Thanks Thanks for not enough money, Let's just say, are you serious. Okay, and go back to the touch to the officer game object and we want to put this give money message, show the S actions on the item actions. So if we succeeded giving, then it will show this message. And if we failed or if we don't have the item, the show not enough money message. Let's save the scene and go to the inventory and we don't have money. I show enough money. Let's just play this And let's try to go to the wall and yeah, the police say you cannot pass, and let's talk to the police officer. But you aren't allowed to enter the crime scene unless grin Okay, but it doesn't show the button. So let's just check for any errors. Under the talk to the officer, we enable the dialogue. Okay. Under the dialog system, there is a slide bug and with this current state of the code. If for example, under the police officer, the touch officer. If we only have one message, then it won't show the button because we are showing the button after we press space or we click on the windows digi, and it will show. But if we only have one message, then we want to show it right away. Let's just copy this cut this line here where we are showing the button and put it outside. Here. Inside the y loop but outside the statement, and then let's save this. Now if we go back, let's test this press play, and then let's talk to the police officer. If we talk to the police officer, it will show the message right away and also the button, and we can just try to give him money, but it won't say anything. If you see in the item actions, we have this yes and no actions. Basically, If we press yes, but we don't have the money, I show the not enough message here. In order to fix that, we need to go to the code here, the item actions code, and I have this open here. Basically, we are checking if we have the item, if we are giving item, but we have all of this code here. But we check if we don't have the items here, let's just put else, and then we can just copy this code here and just run the no actions. And save this. Once we modify the item action, we should be able to respond. Right now, let's just try to talk to the officer and then try to give money, and then it will say, are you serious and we cannot pass through because we haven't give the police officer a money. Let's just top this and then go to the data folder and under the inventory, select the money item and then add those items into our inventory. Let's play this again. Now, if we talk to the police officer here and we give him money. Take a notice here on the hierarchy, we will see that the talk to the officer and the wall game object will be disabled. Let's just press this. As you can see here, now it's disabled, and we have this object enabled. Once we have this enabled, if we talk to the officer, it will say another different messages, and now we can enter the crime scene. Another thing that I want to test here under the talk to the officer. Let's just add a message. Do you want to give him money? Let's test this, see if the dialogue is working with multiple dialogue, so let's just run this and then talk to the officer. And if we press. It shows the next message and it shows the button. If we only have one message action or one message only, then it will show the button right away. Now, we are going to add the corpse or the victim on this crime scene. Let's go to the uni tiny people and under the folder, go to the free and we want to add the male A character and put it under the NPC group. Here, I'm going to create an empty game object, and then I'm going to put this male A object to be the child of the game object. And let's call this corpse or victim. Let's just set up its position, we want to make sure that the of our victim is facing diagonally to this direction here. Let's just rotate this and make sure it if we select local, you'll see that our access local? You'll see that our Z access is facing this way, so we can rotate this bit here. Now we want to set the child object. But first, we want to hide the baseball bet. Just select the baseball bet and then uncheck this and go back to the TTmo male A object. Rotate this, so it's facing forward there. Now turn this down here. Okay. So we want to make sure the victim is position, something like this. Now we want to add a box glider. Let's just add a box glider. Let's move the position on the x axis slightly and also the z axis. It's there and we can addit the glider and make this slightly bigger, so it's easier to click here and let's one this next thing we want to do is we want to set this to trigger, and then we can add a intractable. And we want to activate an object here. But we haven't created those objects. So let's just create this. Safe. Now when we gave money to the police officer, the wall will be removed, gets hidden, activated. We can go through to this victim here. We can check and now we want to play a timeline or a cut scenes whenever we check the victim. Let's just create a new empty game object. I'm going to reset its value, and I'm going to call this ending cut scene. And save the scene as always, and we want to create a couple of objects here. First, I want you to create a new camera. And I want you to set the camera to be around this position here. Okay. Or something like this, something like this. I've set the view in the scene view and then select the newly created camera and then press control shift and F. We snap the camera to that position. If we go to the game view, you'll see that we have this area shown. We want to decrease the field of view, so I'm going to set this two 50. Now we have a much tighter framing and we won't see the gap on the scene. For the ending cut scene, we want to add a object, M A, male B, which is the detective or our player, and we want to add the female one. Now we already create this, push it down, right above on the ground for the player, and let's put it around here in front of this. For the female, we want to put it also down a bit. Now we are going to create a new timeline file or timeline setup. Let's open the timeline tab here. Or we can go to the window. I think it's under sequencing timeline. Then press and it will open this window and press create by press create, but make sure we are selecting the ending cut sin. Select the object here and then press create and we want to go to the access folder under the timeline. Let's just create a new ending cuts or just call this ending, should be okay. Now we have a timeline. First, I want to create a tech group. I want to create two different tech groups, and this is for the characters. And the second one is for the scripting event or activation event. Let's just delete this and call this activation. For the characters, let's just drag the male A to this group here and it will ask whether we want to create an animation activation or audio track. I want to create an animation track. Now I'm going to add right click on the timeline here and then add from animation clip, and I'm going to select idle A and make sure this starts from zero. And with selecting the clip, I want to set the animation extrapolation, the post extrapolation to looping Whenever it's finished playing, it will look the animation clip and we don't need to drag this clip. We want to also direct the female to the characters and then add an animation track. For the female, we want to set its position. But first, let's just select the game object and then select the knife here. Let's select the knife object here and hide it. Let's select the ending cut sin again so we can see the timeline. Okay. Now for the female, let's add a clip also at an animation clip, and we are going to use this female walk, this one, female walk. And stretch to be around this time line here around 120 frame. Now we have this walking animation, and I'm going to direct the female again to create another animation track, and I'm going to record this one. I want to move the female game object, the female game object here to be around this position on start outside of our camera frame, and then I'm going to push this down. Yeah. And we can we can still see the female. I object so let's just push this around this position and make sure we cannot see her again. And we want you to stop her around this frame here. Sorry, first, I want to rotate this female, it's facing to the crime scene and drag this timeline around this position, we want to move this again to be here or probably here and we can rotate this a bit. If we play this, you'll see that it will move to the scene here, and we can stop recording. Here on the first track of the female animation track, we can right click and then add another clip, and let's just use the female idle pan. We don't have any animations with crying and stuff, so we can just use this and I want to push this so it overlaps with the wall clip and it creates transition like this. This would be the transition. Now we play this, you'll see that once we stop it will transition to the panting animation. And this is close enough like crying. I should do. But if you have a custom animation, you can try it with that animation. For the male, since it's an idle animation, it doesn't have position. What we want to do is we want to select the idle clip, and then we want to create motion offset. Let's just press this button here and it will show a cursor. Let's just put it around here and then rotate it, it's facing to the body. We want to move also this again and make sure it right above our ground. Okay, something like this. Let's just table this again. Now if we play this, you'll see that we have this sequence. For the panting, the idle animation, select the clip, and we want to also set the post extrapolate too. Now you'll see that it's crying, it's crying. Now we are going to create a dialogue and also a transition to the main scene or the man scene. Now I'm going to create two different I'm going to create two new empty game object, create empty. And let's save the scene first before anything happens and change this to dialogue one, add a start we want to make sure that it's disabled on this game object, and also enable the height message on disable and we want to add a message action. First, we are going to we are going to make sure that we are showing information that our player is saying that damage I think Let's direct this action to the action slot here. Okay. And I want to duplicate this. And for the second one, I'm going to say, wait. Okay. For the third dialogue, I'm going to change this to the grieving wife and probably just crying. No, something like this. We have three dialogues. Let's just select the ending cuts for the activation, let's just rename this so it's clear. This is the second dialogue, and this should be the third dialogue. Select the ending cut since again, direct the first dialogue to the activation group and activation we want to Make this short. And for the second dialogue, we want to direct this to the activation group also add an activation tag and make sure it gets activated after the first dialogue, but make sure we have space here. Otherwise, it might get disabled by the script accidentally, for the third one, let's direct the third dialogue and add an activation tag. We want to also make sure that this message is shown after the female is stop and panting. So should do this, and we want to create another tigame object for changing scene. Add a start track and a change scene action and disable the game object. Direct the action here, and we haven't created the scene target, but right now, let's just test this out, save the scene and select the ending cut scene again. Direct the change scene and we want to add an activation track and we want to activate this after the last dial. This way, when the change scene gets activated, the script will execute this action and it will change back to our menu scene. Okay. Let's save this again. Now we want to disable the cut sin. We want to disable the cut sin. We make sure that it doesn't get played on start and it's hidden and make sure that your body is not inside the timeline. It's not the child of the ending cin, it should be the child of the NPC group under the scene object. Okay. Now for the scene object and PC group. Let's select the victim. Now let's add entry to the activate actions and whenever we are interacting with this corpse or the victims, we want to activate the ending cut scene. Let's just activate this by checking the checkbox here and add another entry, and we want to disable the player. Here we are going to disable the player, the original player, and once the cut sins is playing, we have another instance of our player that will act out as this timeline gets played. Okay. I think that all thing we need to do is we need to add the actions and direct the actions here. This position should be okay, should be around here, and we want to add a icon and save the scene again. Now let's test this out. But before we test this, we need to add a money. Otherwise, we cannot bribe the police officer, let's select the money and then add items, so we have this on our inventory. That will be all let's test this out. Okay. So let's talk to the police officer. Okay, I don't know why we are missing a dialogue, so I'm going to add a message to the police officer under the talk to the officer message here. And we are going to ask you want to give him money. Let's save the scene again and let's test this again. We have the money in our inventory. Let's press play So now we can approach the corpse. It tells you that no you can't pass. So let's just talk to the police officer, and we press. So yeah, give him a knee and it will consume our money here and now we can go anywhere we want to go to the crime scene. So let's inspect the corpse here. Once inspected, you'll see that the player is it's playing. So we have successfully played the timeline. But it's a bit fast so let's just fix that. Open the timeline object. I'm going to make this much longer. I'm going to also probably we need to edit this too. Let's just edit the animation window and make the female arrive at 4 seconds and go back to timeline, and now we can move the female idle penclip and drag the wall, so it's longer. Now we want to make the dialogue longer Okay. And the third one should be here. And activate the scene here. This should do and you'll see that we have an error because we don't have the scene name available, but we are going to do that in a later lecture. Yeah, I think this should be enough. Let's just try this again, add the money, and let's disable the ending cuts first game. Let's test this again and see if this is much slower. Let's bribe him and then once bribe him, let's Now it's better. Okay. Okay, this is basically done. Another thing that oth thisis if we play this and then we try to interact with some object. For example, the wall here, you'll see that our character is tilted slightly. We need to fix that. In order to fix that, we need to go to the player script. So let's just add it the script. Now, the player script is open. Let's fix the rotation issues. In order to fix this, first, we need to set a new vector that has the directions between our interactables and our player, and then set the y value zero. So in order to do that, let's just create a new vector three, and let's just call this vector direction. And we want to cut this out. And then paste this here. And now that we have new direction, we want to set the factor direction, y zero. This will make sure that we don't have different elevations on the direction, and we will have the directions on the same plane x z plane, so it won't modify the x rotations to the player. Once we set this value two zero, we can just simply put this inside our rotation. This is the changes that we need to do. Another thing we need to do is here on top of turning, we need to set that if currently we are turning, and then our transform that rotation is equal to the target rotation. Then we want to set turning to falls again. Turning will be set to true again whenever we trigger this set direction as you can see. This will prevent unneeded code execution inside our update. Thus, we'll make this much more optimized. Okay, now let's go back to unity. Let's go back to it and let's test this out. Now we can select the player here and press play. And let's go to the slide wall here. And as you can see, it's top and the rotation, we have a zero on the x rotation and also zero on the zero rotation. You see that we don't have that dealer anymore. So now it's working nicely. And let's just test this one more. Yeah. So now we fix that rotation and a slight tilting issues. 56. 55 Menu Scene Setup: Okay. Now let's create the menu scene this menu sin will be the starting screen. First, I'm going to create a new scene, and I'm going to call this menu. Here, for the ending cut change scenes game object, I'm going to insert the scene target menu as the target for our change scenes actions component. It should be menu. I forgot to put the menu scene inside the build setting. Let's just do that drag the menu and put it on top here to be the first scenes in build. Okay. And let's try it one more time. Okay. Now let's talk to the police officer again and then give him some money and then go to the victim. Okay, now it loads the menu, but since we haven't done anything in the menu scene, so it just shows the default let's stop the game and then open the scene here and let's create a new canvas. Okay. And let's set up this canvas here. We want to change the Canvas scalar options, the UI scale mode options to a scale screen size. I'm going to set this to a full HD resolution 10911092, and then the height should be ten 80. Let's save the scene again for the camera, I'm going to change this to a solid color and set this to black. Now we want to create a couple of button. Let's just select the Canvas and create a new button. And set the button size to around 300 by 100. Okay. And here, go to the scene view and press the button and we can adjust the button position for the child game object here, the text, I'm going to remove this and then add a new text. But I'm going to use the tech mesh pro here. Let's just add that then for this child game object here, we can hold out button and then under the cransform presets, we can click this button right preset. It fits nicely with our button for the button, I'm going to de the image. Or we can just set at source image to none, and then set the color to black. We will have a black button. Here you'll see that I'm going to add an outline component. So let's just add outline to the button, and then set the color to a white, and I'm going to set the alpha to 100, so it's opaque and let's increase the width by increasing the effect lessens value each to five. So we have a ticker button. The other thing we need to change is we need to go to the text object and set this to new game, and I'm going to enable the atoing but I'm going to decrease the max size. So I'm sorry. Let's just leave the x sie, but we want to add a margin on the left and the right side. So for the left, I'm going to feel 15 and for the right side, I'm going to also feel 15. Sorry 50. It looks better, and we can copy this button here. And let's move the first button on the y axis should be around negative 50 or negative hundred. I think 200 should do. For the second, sorry. For the second button, accept this two negative 400 or the h 250. Now we have two bon, and for the second button, we want to change its text to continue. Okay. Now that we have set up the button, let's create a couple of scripts under the scripts folder, the safe system. We want to create a safe load menu. Let's just do that safe load menu, and the other script would be the Safe entry UI. This will be this is for the UI entry when we are loading multiple safe, we can choose which one of the safe that we want to load. Now let's create the UI for loading the game progress and under the Canvas, let's create a new image. Okay. And we want to set this to a bigger size. So first, I'm going to set this to 800 for the width, and for the height, let's just set this to 500 or even more. 700 should be okay, and let's just increase this. This is our load UI, and we can change this to a dark blue. Now for this panel, let's just call this load panel. We want to add a vertical layout group. This vertical layout group will lay out the child object evenly. For example, if we create another image here and let's create another image, you'll see that it will get layout evenly here. We want to set a couple of things for our vertical layout group. Let's just set the spacing first around 15 and we want to add padding for each of the side 25. And set the alignment to middle sorry, upper center. And we want to set the control size to the width. So the width will fit. And We want to disable the child force expand on the hype options here. Uncheck the hype. We have this settings, and let's just set this to around 250 or 200 should be okay and save this. This is the data data entry, and we want to set a couple of things here for data entries. Let's just delete the second image. Let's add a couple of things. First, we want to change its color to also a dark blue. And let's add a tax mesh pro. And this will be our current scene. Let's just set the alignment to the top right. Let's just rename the scene description. We want to duplicate this, but we want to put this down here. I'm going to move the text. And this will be the dates where we safe. So let's just call this dates safe dates. Okay. And we can we need to add also a button. So let's just add a button for loading. And let's just put this on the right side here. Let's just increase its height to run 60 for the child object, I'm going to delete the text and set this as a text mesh pro for the child object. I'm going to fit this transform by holding the button and accessing the fret and press the bottom right options. For the button, I'm going to set the source image to non, it will be solid, and then I'm going to pick the same color as our badgron But I'm going to add an outline. I'm going to set this outline color to it, just like the one we create on the menu, and let's increase the Alpha and also the y value. We should have something like this, and for the text, just type this load let's increase its size 36. Okay. So for the other two texts, we want to enable the out of sizing. And for the description, let's just increase this text here, but let's just put the anchor to the middle and let's decrease the width to around 800. Okay. And let's move the y position, so we have margin on the top here. This is the data entry, and we want to save this later as prefabs. But now let's access the script first. Let's just open the safe entry UI. Here, since we are using the text mesh. Now we are going to import or we are going to use the text mesh pro namespace, and then here, we want to declare a couple of variables. The first one will be the text mesh object. Text mesh pro, UDI, and we can call it the scene description. The second one should be the date Okay. And then we want you also access the button. So let's just import UI namespace Unit engine UI. I then let's just type button for the class, and let's just call this load button. And we want to add a private integer, and let's just call this ID, and this will hold the data entry index. And with this ID, we will load the correct safe data from the list of safe data that we have on our data manager. Let's just delete all of this built in method. And first, we want to create a public void, and this is for initializing the initialized load entry. Okay. And we need a couple of things here. First, we need a string parameter, and this should be the C name and also a string or we can just import a dates. System and we can just import the time. And also, we want to pass the ID. So let's just create an integer ID, and save this. So when we are initializing this entry, we want to update the text object. So let's just access the scene description and access it text properties and assign the s name to its properties. And the next thing we want to update is the date text. Since we are having the same name, we need to change this to this. The date and this will revert to the date that we declare on the class here, and then type text. And we want to assign a string here. So let's just change this to string and we don't need the system using system, but we are going to use the dead time when we initialize this load entry. So we are going to do that in the safe load menu, and right now we can just pass the date. For the ID, we can just type this ID equal ID. We want to also create a load function or load method. Let's just call this load data. And here we are going to implement loading later. Now, we want to assign the load button on click Add Listener, and we want to pass this load data method as the listener of the onclick event for this load button. So when we load the button, it will load the correct data according to its ID here. Now, we can save this and we can create the safe load menu. For the safe load menu, first we want to add a safe entry pref. Let's just type the class here, safe entry UI, and this is the entry prefep entry or the second variable that we need to have is a transform, this should be the p Let's just call this parent. Let's delete the pate method since we are not going to use it, and let's created in it, and let's just call this panel. And we want to create a temporary integer, and let's just call this safe count. And let's access the data manager. Instance, safe. Do we have the safe? Okay, let's go to the data manager first and we have this list of safe datas, right? So let's just create a public accessor. And let's call this safe data with as we want to we want to only have properties, and then we want to return the safe data. These properties able to return the safe data that we have, but we cannot write it. It's protected and we can only write it inside the data manager here. Let's just access the saves count we want to look through this count here. Let's just change the length here to save count. By the way, if you are wondering how I did the four loop, just type four and double tap and it will automatically create the four loops code and just change the max length. Now we want to instantiate the entry prefep Let's just instantiate a new entry prefps save entry UI, temporary three, and then instantiate an entry prefps we want to set the p as the parent, let's now we want to initialize this temporary entry. Let's just type the t entry and then call the it entry, and it as f and it as for string name, string date and integer ID. Let's just go to the data manager, and under the safe data, let's add a public system. We want to access the system and then let's access the date here or public system, and we can access the date time class here, and let's just call it safe date. And now that we have this, we can access this by creating a couple of strings. This should be the scene name. Let's describe this from data manager instance. I instantiate, but it should be instance and access the safe data index of I and let's grab the current scene. For the date, We can just create a new string called safe date and then access also the data manager. Instance, save data, the capital S one, the public accessor that we just created before, and access the safe date, but we want to form at this. We can just type two string. And we can set a format here. For the format for the format, we want to set the first entry is date, we fill D character four time and add a comma and then two D and this will represent the date, the number number date. This will be the day name and this will be the day number, and for the month, we want to set this to four time and space and for the year. We want to also set this four time. We want to also add hour full column and then minutes, change the minutes to a lower case one. Let's just save this. Now that we have this, we can pass the sname to the first parameter of the edit load entry method, and the date put it to the second parameter, second argument. For the ID, we can just pass the I as the ID, and this should do the trick. Okay. Now that we have this setup, let's just call the init panel method on the start method, and save this. Now we need to update the data manager. Whenever we save data entry, we want to also save the date. Let's just type the lower case one, and then access the save data ID, and for the safe date, we want to use the system the day time now. And this is a property, I think, this is the property, so just type like this. And this will return the current date time when we are executing this method. When we are saving and this will get safe, And for loading, I think we don't need to do anything. We can just access the load in here in safe data entry. Now we can implement this. Access the data manager instance load data entry, and pass the ID that we've received from when we are initializing this load entry. Just pass the integer value, and this will load test. Let's just set up this in unity first. Let's select the data entry, and it's still compiling right now. I'm going to direct the safe entry UI to the data entry that we've created, and as for a couple of objects here. For the s description, let's description object. It will automatically the text mesh UI and also the safe dates. I think I'm going to rename this without the safe date for the button just direct the button here. Like so, and now we can go to the prefap folder and just drag this data entry as a prefps. Once we have set as a pref we can safely delete this from the scene and for the load panel. Let's go back to the script and save system and select the load panel again and drag the safead menu. For the parent, we can just drag itself its object because it has this vertical layout group. And we want to drag the preface from the prefix folder. So let's set the prefix folder and direct data pref that we have just created. One thing though we want to do is I want to change this. I want to duplicate this load panel, and I want to remove the image and also all of the other component. I want to set this as an empty game object. I want to set the load panel as of this empty game object. And let's put the safe load menu, copy this component here and put it on the parent game object. So the way it works here, as you can see, we are putting the safe load menu here and we can safely delete this one, and this will refer to the parent game object. So we can hide this. Still the script will gets executed because the parent game object is not the activated. So it will instantiate all of this safe entry on start. But it's disabled, so it won't show, and it will only be shown when we click the Continue button. Okay, let's save the scene, and now menu. We want to create a couple method. So we can just create a new public method and call this new game for new game, we want to go to the Data Manager and also create a new public method for setting a new game. Let's just type void new game. For the new game, we want to add a new safe data to our safe data add and call this new save data. We are creating a new instance of safe data and we add this right to the end of our safe data at the last member. Then for the safe data ID, We want to set this to the data the current save datas count but we need to substract this by one. So we will get the correct ID for the last member here. Since ID is always an index base of zero, so it starts from zero. So we need to make sure that we substract this with one and save this. Also, in a new game, I want to access the level manager, and then we can just sad the office. I think it's the intro. Okay. And for the safe data, I don't think we need this anymore, but just comment comment this out for the time being, and if there are any issues, then we can modify this later. Now that we have the save data, we can go to the safe load menu and access the data manager instance, and we can run the new game method. Okay. For loading, we want to also create a public method void can call this show load menu, and we can just type per game object Sebcte Also we want to create a closed button if we are plan on canceling. Let's create a new button and Okay. We can just since we are using the vertical layout group, so we need to find another way to do this or we can just duplicate this. And put this as a child, and let's just call this D vertical layout and remove the image. For the load panel, just remove the vertical layout. We have this vertical layout sits nicely. Now we need to change this. For the parent game object, make sure it's the vertical layout. The data entry will be loaded evently or nicely using this vertical layout group. Here, under the load panel, we want to create a button. That will act as a close button. Let's just set this to 50 by 50. That should be okay and put it on the top right. I'm holding the alt and click here. I sits on the top right and sets the value on the x and the white two zero. Sorry two zero. It sits on the middle here, and we can just set this to and also set this to a dark blue. Remove the text game object and add the text mesh pro since it's much better. Using the text mesh b is very sharp and very light weight. I'm going to set this to x for the character and to size this. We have this x pattern for closing when we are closing the button, we want to hide this panel here, the patent panel. Let's just select the load panel and then set game object set act to false. And we need to add another entry on the safe load menu. Let's go to the scripts here, the safe lock menu and create a new cerrized field, and this would be a game object, and this would be the load panel. So we want to hide and show this. So let's just change this para game object to the load panel, sect to true. So let's head back to unity. And once it's updated, we will have a new entry on the inspector. Then we want to direct the load panel. Okay, so save this. Now let's test this. But since this panel is shown, we want to automatically hide this. So let's just hide on start. So let's just dip the load panel set active two false and save this. Now if we press play, it should hide the panel automatically, and we can start a new game. But there is an error here, so let's just check what is the error. Okay, there is So, the manager. Do we, we haven't put data manager here on the menu. Let's just go to the prefix folder and direct the data manager. So we have one instance in it. Now if we press play, this should be done, the error message. If we press new game, One thing that I forgot, we forgot to assign the button here under the load panel, let's just create a new button, but we need to import the unity I namespace. Let's just access that. Here, let's create two new entry button first for the new game and the second one for the load continue. Sorry, continue game. Okay. And on start, we can assign this button on click Listener to the new game method that we've created in this class here. Let's just copy this line here, paste this and change this to the continued game. For the continued game, let's just use the show load menu method, save this. Now if we go back to Unity, let's update the entries here, for the first button, it's going to be the new game button, so direct this button and put it on the new game entry, and the second button, put it on the continued. Hopefully, this works. Press play run and then press new game. You see that, there is an error because we haven't put all of the scenes on the build settings. Let's just do that now, go to the scenes folder and then press the build settings. Okay, now we have the sample scene. I'm going to remove the sample scene, but I'm going to add the office and also the part. This is all of the scene that should be included in the build. And save this, save the scene and save the project because we change the bill settings. Now if we press play, it should work. Press new game. There you go. It's loading, and now it's playing the game. So this should be all for the menu, and we need to continue working on the load. But first, we need to change a couple of things on the game play scene. So it works right now if we press continue. It doesn't show anything, and we are going to address this issue on the next video. Okay. 57. 56 Menu Continued: Okay, now let's continue our safe and load system, the first thing we want to do is we want to go to the data manager script here and we have this load method, but we never load any data. We want to load this method on start. Let's just create a start method and then access the load method that we have created. Basically, this load data will only load the safe data from the binary format or the safe data that we save on the storage, and if the load, but it won't do anything. Just load and fill this safe data list with the previous data that we have on our storage. In order to load this, we need to run this load data entry. Also under this load method, we need to check the safe system or if we have a data that we have saved before. Otherwise, it will throw an error when we try to load this. Now, you see that if we press plea, and then if I press continue, It will show the save data that we have, and we have a save data in the sample scene because we are testing on the sample scene before. But since we don't have the date time object before, it shows the default value here, as you can see, Monday, the date, the month, the year, and the time or the hour minutes. Now let's fix a couple of things here. Under the load entry when we are loading the data, we want to load the scene. Let's just access the level manager. At manager is the child object of the data manager that we've created, and this handle for scene loading and just access the scene load, and then we can access the sorry, the save data, and let's just access the save data ID index ID, and let's just get the current scene. So Whenever we try to load this data, and this method is going to be called by this safe entry UI. Whenever we press the load butthn here, since it has a listener, then this load data will run the load data entry based on the ID. Here, when we run this method, we don't need this load method anymore, so we can safely delete this because the load method it's already being called on start and we only need to call the load method once. And after that, we need to only load the inventory and call the unload method and load the currencne that we have on the save data and save this. Now if we press play, you'll see that we will be able to press continue and press load, and we will load the sample scene. But there is an issue because I've removed the sample scene from the bill setting. In order to test this, we need to put the sample scene back to the bill setting and test this again, press continue and then load and it should load the test. As you can see it loads, but it doesn't load the position. Let's just check Let's just go the sample scene here. I believe for the NPC, we have the entity, we should have the safe entity. The third PC. We have the safe entity here and we can check this on start, we want to create a new class for initializing the entity, and we want to also modify the data manager. Here on the data manager, we are going to create a new method and this will be in entities for the entities here, we can just call the unload method. And we don't need this, but we can just leave this. It's okay. We can just run that. We need to create a initializer. Let's create a new subscript, and let's call this its initial And this will be a very simple script, but we need to delay the script by 100 milliseconds. So let's just set this. On start, we want to run the entities initialized. Let's just access the data manager that instance, I think it is init entities. Let's just run this method and this will trigger Here, on the sample scene, we can just create a new empty game object. And let's just call this entity initializer. And we want to add the script that we have discrete it entities initializer. If we select this script here, we can go to the inspector. If you select the script from the project manager, go to the inspector and then press the execution order, and we want to add the entities initializer by 100 milliseconds. Press apply, and this will apply the changes. The script will gets executed after all of the other script already present on the screen so we can initialize the entity by calling this unload method unload event in the deaminator. Now let's go back to the menu sin here, save, and then press play. Now let's try to continue the game and then press load. There you go. Now you see the NPC is already moved to this position here, and I believe we have inventory, let's just test this out. Go to the data folder, we can go to the inventory and we can delete the name and delete the key. I'm not sure, but let's just test this. And then press continue and then load. There you go. As you can see, the inventory is also gets loaded. Another thing we need to do is we need to create a small script for saving on the game play. But we are going to do that in the next video. 58. 57 Add Save Menu In Game: Okay. So now I've loaded the C scene here and I'm going to adjust the UI for saving and we are not going to be able to load in the game, but we want to able to save. So here, under the debug safe load, I'm going to direct the safe button and put it under the inventory, and we want to hide the safe load. So let's just go to the scene view. With the TDs press, we can adjust the UI. Let's just set the anchor to the top right here and move the position to be below the inventory. We want to make the button to be the same size of the inventory button. It's 160 by 60. It's just set that value 160 by 60 and put it below. And let's just delete all of the text game object here and add a new text mess P, I game object as a child, and for both of the game object, let's just set this to the stretch to the parent game object. You'll see that each will fit nicely with the button. For the button, we want to set this to a value of and we set this to black's just add an outline. For the outline change its color to white and set the value to the alpha value to 100 and we want to increase the thickness by changing the effect distance value. I'm going to copy this component here and go to the state button and also set this to none for the color, change it to black and we can paste this component that we have just copied before. Paste component is new and it will paste the the outline and call this inventory and enable the to size, but I'm going to add a slight padding ten by ten on the left and the right side. For the save, I'm going to call the save and also enable the toe and add a top button padding. Now we have a very nice button similar to our other button. Now, let's open the inventory system UI. Okay. And I want to add a button. So in order to do that, we are going to or we can just create a public method. Okay. I can just call the public method and save progress and this will access the data manager, instance, save data entry. Okay, so this will save our current progress. And maybe some of you may ask, since we are going to use this button, this method from the inventory system UI. So here under the inventory button, you'll see that we have the unclick event, and this is showing an inventory. And for the safe button, I'm going to do the same direct the inventory panel. And I'm going to access inventory system UI and call the safe progress. Maybe some of you may ask why don't we just tract the data manager to this click event and then access the safe data entry right away, I cannot do that because we cannot do that because when we are transitioning to other scene, our data manager on that new scene will get destroyed. If we do that, the button will refer to the data manager from each of its scenes. If we have the Singleton persist to the other scene, then it will destroy the other data manager. And when the data manager gets destroyed, The safe button on that new scene that we have just loaded, will miss or we'll find the data manager missing. So we cannot safe progress, and that will be an issue. By doing this, we are making sure that the safe button will always have access to the safe progress method and safe progress method will have access to the data manager via script by calling its static reference the instance here. Let's just save this and I'm going to apply the base Canvas. Since this is a pref and save the scene. If we go to the other scene, let's check to see if the prefps is updated and as you can see, it's updated. Here, if we check the reference of the flix event, this still refers to the data manager. Let's just drag the inventory panel again, and this should call the safe progress. Let's just first apply. Now, this should be safe and let's check on the other scene. This is the C Hallway city and the other scene that we have is the part and save the scene and check its base canvas here under the safe button, as you can see, it's accessing the inventory panel. I will never miss this object here, the safe progress method. Since it's the same preps now if we go to the menu here, We can try to save the progress. So let's just press play, and then press new game, and let's just watch the cut sins. And once we already on the scene, I want to go to this area here, and I want to look at the password, and now I want to save the progress. Let's save this and you'll see that we have successfully saved and let's just stop this. Now if we press, if I press continue, you'll see that we have two entries, the sample scene and the city for the city, we have the correct date if we press, it will load the city But there is an issue with the city because we haven't put the entities initializer. Let's just do that quickly, create an empty game object, reset its value. And I'm going to call this entities initializer, and I'm going to add the z component. Now we have created the entities initializer, we need to do this on every scene, so I just copy this game object here. Save the scene and go to the club hallway and then paste the game object. So I have this entities initializer, and also for the part, save the scene and paste the entities initializer. So if we 59. 58 Saving Thumbnail: Okay, in this video, we are going to continue on the safe pictures, and right now we have a loading and saving system. And if we go to the prefix folder, I want to drag in the inventory UI, but the Data entry, I think. Yeah. And Let's just open the canvas here and under the load panel. We have this vertical layout. I'm going to put this data entry to the vertical layout, and we can see here. Let's just adjust this and basically, we want to create a screenshot of it of our progress. We are going to adjust the composition of our UI here. For the scene descriptions, let's just decrease the size here. And for the date, of course, we can make this even smaller. And push this to the middle this position here, and make it also smaller on the horizontal size sizing here the tax, but it should be the object. And for the load button, we are going to change this this position by holding out, you can move it to this position here and I'm going to add a space to the edges, so it doesn't to cram. And now we have this new space here. Let's just create a new UI, and this would be a raw image. It's not going to be an image, but it's a raw image. And for raw image, it as for texture. So we are going to provide this texture from our screenshot. So now I'm going to set this to the site here, and I'm going to set a certain value, so probably around 240 by 170. Yeah, this should do and add space. And this is basically our pixel size for our screenshot. So save the scene, and I'm going to apply this data entry. Okay. So now we need to modify a couple of scripts. So let's just do that. I'm going to go to the manager folder under the data manager. And the first thing we need to do is we need to create a new custom class that will hold the color data, the pixel data or the image data. And basically, the image data, it will be a series of pixels, and it's going to be safe in a color array. But we are not going to use the color class because the color class from unity cannot be safe. It can be serialized. I'm going to create a new class that it can be serializable. Therefore, I'm going to add a system serializable tag, and then I'm going to create a new class and I'm going to call this custom color. This custom color, we have a public float, and this is for the color data, which is the red, the green, the blue, and the Alpha. But I don't think we need the Alpha, so we can just save the RGB and this will be more smaller in terms of safe file size. Basically, we want to create a new function to return a color from this custom color data. We are going to create a new public that will return a color, and let's just call this get color. Let's just type return new color, and we can add the value, which is the r, the G, B, the blue, red, green, blue. For the alpha, we're going to simply put one, so it's opaque and safeas. Now that we have saved the custom color, we are going to add this new class as a field on our safe data. Let's call this custom color array, and let's just call this thumbnail. Now the next thing we need to do is we need to create a helper class that will save the screenshot. In order to do that, I'm going to go to the safe system folder and I'm going to create a new shop script, and I'm going to call this screen shot saver let's open this new created class. Okay, now we need to create a new private integer. Okay. And this would be the width. Okay. Should be around 270, I think for the height, it should be 170. But I'm going to check this. So let's go head back to unity and under the dree I'm going to access the raw image object and see it size. Oh, it's 240. So let's just modify this and make sure this is the value that we have on our raw image. The next thing I'm going to create is a custom color array, and let's call this thumbnail. The next one is a color array Let's just call this pixels. And the last thing we need to create is a new core routine, and this is a route object that can hold a coroutine that are currently running. So let's just call this screen capture weight, and this will be a property and we can get it publicly, but we can only set it privately. So I'm going to add a public getter, but a private setter. Save this. I'm going to delete the update method. Since we are not going to use that, We are not going to use the start method also. Let's just delete this. I'm going to change this to a public method. Type public void and change the name to get snap shot. Basically, this will run a routine. Let's just create the routine first. I enumerator and call this take or we can just call this process snapshot. Now that we have this, we can run the coroutine, but we can put it inside the screen capture object. Let's just type screen capture weight and then equal start coroutine and let's just run the process pshutin Now that we have this process nash, we need to create a new render texture. Let's just type render texture, and we can just call this RD, and then we can construct this rendered texture. I believe we can set the size here. We are going to use this one. Basically, we are going to pass the width, and then the height that we created on top on the variable decdationF the depth, I'm going to set this 2204. We don't need the Alpha, so let's just set this 2204. Then we are going to access the camera manager in Conmra Carmra is the active camera, and we can access the target texture, and we want to set the target texture to the RT or the render game objective we have just created before. Once we set this target texture, we want to make sure that we are processing the screenshot at the end of the frame. So we are going to delay the code, yield, return new weight for end of frame. And this is basically going to wait until the frame is almost finished, and then after that, it's going to start execute the code below here. And this is to make sure that all of the object on the screen is already been drawn, including the three D object, the UI, and stuff, and it will get saved. Now here, we need to access the render texture class here, and it has a active and As you can see here, it tells us that currently active no texture. We need to set the active to the RT that we've just created and we assigned to the camera manager. One thing that I forgot, we need to also create a new texture to the game object, and let's just call this screenshot SS Let's just construct this new texture, and for the width, we are going to set the, the, and for the format. This should be a texture format, and I'm going to choose this A RGB 32, and this is for the MMP options and we are going to set this two falls, it doesn't have a map. We don't need that. Let's save the script. Now that we have created the texture to the object, we need to read the pixels from our screen. Let's just use the read pixels method. Basically, this is as for a rectangular source, the source size and the destination initial position. We can create a new rectangular and first is 0.0 And then for the width, I'm going to get the render the textures with and also render textures height. So we have a new rectangular size of our render textures, and for the destination x and decision y we are going to set this two zero. It starts from the bottom left of the screen, and it will read all of the pixels up to the top right pixels. And once we read the pixels, we need to apply them. So let's just SS apply. And then we want to save the pixels that we just read to the color array. So I just type pixels equal to the SSG pixels. And this basically will save whatever pixel array data that we have on our texture to D, and it will get saved to the color array. And now we need to convert the custom, but the color array to custom color array. In order to do that, we need to create a new function. Let's just go below here and I'm going to add a fit texture to array we need to pass the color array, and let's just color this color pixels. Okay. And inside this color pixels, we are going to declare our thumbnail object here. In order to do that, we can just type thumbnail equal new custom color, and for the length, we can just grab the color pixel that length. It will have the same length as our pixel that we grab from our no texture. Then we are going to look that length here. And now we are going to copy each of the data to our tonal. For the tonal index of the R channel or the red color, we are going to grab the color pixels, i dot r. The same value, float value here. It's going to be safe. I'm going to copy this a couple of times, but I'm going to set this to g the last one should be B, in blue and same goes with the color pixel. And this one also. So now that we have saved the color pixel that we grab from the nto texture, this will temporarily be saved in the tmnail object, and later we can grab this since it's a public field. Now that we have created this method, let's just run. The texture to array and pass the pixels that we just grabbed before. Once we grab the pixels, we don't need the random ture anymore. So we can just safely access our camera manager, that instance, current camera. And for the target texture, target display, the target texture, we are going to set this to know. And then we are going to destroy our RT game object. This one here. We are going to destroy to clear it from memory. After that, we are going to stop all coroutine that are running inside this class, the screenshot saver. But it's only this process snapshots actually. For the screen capate we are going to satisfacon no. So now we've finished the co routine. Now we need to create two more method in this class here, and the other one is a public method that returned a custom color array. And let's just call this get thumb nail. And this is basically we'll return the thumbnail object that we just created here. And next method is a new method that will return a texture. Okay. And this is for loading the custom color back to texture to object. So let's just call this array to texture, and we need to pass the custom color array object. And let's call this safe Tumbnail. For this, we are going to create a new integer called length, and let's just create the safe t length. This object that we are going to pass when we are running this method here. We are grabbing those length. Then for the pixels object, we are going to clear this and set this as a new array of color with a number of member of the length. It will have the same member or the same index with our safe object here. Now we are going to look through the length. Yeah, Delay. Here? And with color, we can just set this to a new color. So basically, we can set the col index of I to be the safe tuna index of I, and then we have created a gate color function. So let's just run that get color, and this will return a color so we can put it to a pixel color array. Once we finish looping through the safe tuna colors to the pixel here, we are going to sorry, but before that, we are going to create a texture to the object. And call this S S and we are going to construct this just like we construct it in the orotin here so it just copy this. It should be the same and paste this here, makes things easier. Then after that, we are going to use the as pixels. It's not get pixels, it's set pixels, and basically it as for a array of color. So we can just pass the pixels. And then after that, we can just apply this. So it gets applied to the Texture two D. And after that, we are going to return the aces object. So we are returning this object to the return type. And whenever we run this function, it will return a texture two D that we can show on our safe entries UI. So let's just save this script, and I think this should be all for this screenshot saver. And in the next video, we are going to continue how to set up this onto the saving system and loading system and also the safe entry UI. 60. 59 Add Thumbnail to Load UI: Now we are going to continue setting up the Tmnil system for the save data, and let's open the data manager. Now that we have this data manager open, I'm going to create a new private screenshot saver object, and let's just call this as saver. Here, below the component level manager, we are going to grab the screenshot saver and we are going to use the get component screenshot saver Okay. And we are going to put the screenshot script to the data manager game object. Now, basically, we need to create a new coroutine inside the data manager to save a screenshot whenever we save a data. Here, below the save data entry, I'm going to create a enumerator, and I'm going to call this save screenshot. And for saving the screenshot, I'm going to access the saver, and then I'm going to run the snapshot function. And after that, I'm going to wait return. I'm going to return for the screen capture weight to be done here. This is basically we'll wait for this process, and if it's new and it will continue to execute the code below here. Once we've finished grabbing the screenshot, we can save the screenshot to the safe data object index of safe data ID or our current safe data ID. And we have the tumnil object that we've created in the last video here, as you can see, and we are going to save the newly generated Tmnila which is using the gun method, and return a custom color, Tumnail is a custom color, so we are going to use this method and this basically will save to the safe ta object. Once we already fill this out, we are going to run the safe method. Now, safe method are being handled by this orotine. We need to remove this. Now instead of using the safe in the safe data entry, we are going to run the start coroutine safe screenshot. Yeah. So it's like this. Whenever we save things, we are going to save all of the entity in the scene, and then we save the s name, and then we save the scene date, we save the inventory, and then we save the screenshot. And when the screenshot is finished, it will run the save function, we will save the data to the binary formatter or the storage on the disc. Now we need to create a method that will output a texture from our custom color in the data manager. We already have these function in the screenshot saver here. But this is basically is a function to convert the custom color to a texture. And in the data manager, we need to make sure that we have a function that we grab a certain ID from our safe data and then convert the thumbnail into a new texture. So I'm going to create a new method here, a public method, and I'm going to call this or we can just call this thumbnail. Based on ID, and we are going to pass the integer data ID, and we are going to create a new texture two D. But this is going to be an output variable, not an input. An argument is usually an input. In order to create an output variable, we can create a new out keyword in front of the class here. We have this. Now, we are going to run the method. This ray texture method into this object. Let's just type. Here, going to type S S equal the SS saver, and then we can use the ray texture function and we need to pass the custom color. This will be the safe index of the data ID that we pass here and grab its thumbnail. We are going to pass the thumbnail custom color object, and this will convert this to the texture, and then the texture will be saved to the SS object, and this will be outputted by this method. And this method gets called by I think it's a safe entry UI or the safe load menu. I'm not sure, but we are going to check that. Okay. Save this. And now we need to modify the safe entry UI. So where is it. Let's just go to Unit, and I'm going to go to the safe system folder and I'm going to open the safe entry UI. Basically, the script that's on this data entry object safe entry UI, let's modify a bit. We are going to add a new serialized field, and this will be a type of row image and let's just call this screen capture or screen capture. Basically, we are going to add a argument here, which is the texture, D, and let's just call this SS. Basically, we are going to sell the raw image, row image. The screen capture texture to the texture that we pass on the method here. Now that we set this, let's go to the safe load menu. I'm going to open the safe load menu here and put it near on our data manager. Here, the saved menu. Now, as you can see, we have an error in the in the load entry because now it asked for a texture two D. In order to load the texture two D, we can access the time manager, Instance, and then we can run d. I think it's load tunail based on ID, and this ask for the ID and we have the ID, which is the I here. Let's just pass the. We are going to output this texture to a new texture object. Let's just create a new texture object, Texture two D. Sorry, Texture two D and call this SS. For outputting, we need to put out keyword. This will make sure that instead of inputting the texture, we are outputting the result to this variable here. Now, once we finish outputting, we can pass this S to the init load entry. Basically, the screenshot will get loaded whenever we are populating the safe entry UI to the load menu here. We can see it on the UI later. Let's just save this. I believe we are done. Let's go back to unity and start setting things up in the editor. Okay. Now we are going to direct our raw image as the screen capture field here, and then press apply again and we can delete this. And on the data manager, we are going to add a screenshot saver object. Perhaps we can just hide this. Let's just go back to the screenshot saver. Okay. And we can make sure it's private. We don't need this to be public. Since the data, it stays inside this class, and this is for holding the color array temporarily, and this is also for holding the custom color temporarily, and we are returning the thumbnail using this function here. Safe now that we have set this up, I think it's going to probably throw an error if we press play now because our previous safe data doesn't have a color as you can see here. So if I continue, There is an error. Okay. So as you can see, we have an error whenever we start the game because when we are populating the load entries, it tries to grab a texture, and we don't have this on our previous safe. So we need to make sure to create a fail safe. If the save tumnil is null, then we want to return a null texture. Other thing that we need to fix here in the data manager. I made a mistake here. The custom color, it should be a strut not a class. And struck is basically like a class, but a much simpler data, and it has a less memory footprint on the memory. But it's more suitable for a data that is color, which is plenty monogamous data, which is a float class is more suitable for data that stores much different data here, custom color, string, day time. Now I've changed this to struck here. Let's give it a try again. Let's press play and let's run a new game, and we can just watch the intro again. Okay. And now, let's try to save this game here. Safe. As you can see, it holds, and then it throws a safe success. So if I stop this and then press play again, if I try to continue, you'll see I save data that have a screenshot here. And this is the previous data that I've tried before when I cut an error. And if we load this, it will start from this scene here, and let's just go to the hallway we have the password. We can go in. Okay. Now we are in. Let's save this again. This is successfully safe, and if we stop this and then press play again, G continue. As you can see, we are in the club hallway here and it grabs the screenshot. Yeah, that is basically how the screenshot system works. Since color is not serializable, that's why we need to create a new custom color strap to save the color a disc fire binary ftter the other thing that we need to do is we need to make sure that the players pan position gets executed after they script, save sytem. The initializer. And if we open the execution order, you see that the entity's initializer gets delayed by 100 milliseconds. So we need to make sure that the players pan position. Let's just search for the player span position here, and this gets delayed even more than entities initializer. Whenever we enter a new scene, entities initializer, we load all of the data object state including the position of the player, and then it gets override if we are transitioning from a different different previous scene. So it will transition the player to the door or to the player spans position that we already set up. Press apply. Now, this will make sure that we are responding to a correct position. For example, here, if I press play, and then I try to load the club hallway. If I go to the door here, You'll see that we are spawning here. Otherwise, it might spawn on the same position, X Y and Z world space from the club hallway to the C and it might put the player on some odd position. H that is basically how to create a screenshot for the save data. And I'm aware that this is a very advanced topic, but it's a nice to know topic with this method, basically you can save any screenshot anything and do different methods or not different methods, but you can use this screenshot for anything for safe data or for sharing screenshot and stuff. Okay. 61. 60 Finish and Build: This is going to be our last video in this course, and basically, we are going to finish things up and one thing that I noticed in the menu seen here, our canvas, the load panel canvas doesn't have a scroll bar. So for example, if we have lots of game safe, we cannot scroll the UI, for example, if I just open this up and then I duplicate this a couple of times. You'll see that we have no way to scroll and we will have this ugly UI. We need to fix that. In order to fix that first, we can go to the load panel here, the child load panel, and then we can create a new UI, and let's create a scroll view. And this will create a new object, which is a scroll view. And for the scroll view, we are going to set its size to round this parent object. So let's just hold out and then click this button here under the anchor presets, we can add a margins about 20 pixels on each of the edges area. Okay. Now that we have set up this scroll view here, we want to go to the view port here, and under the content, we want to delete this child object, and we want to direct this vertical out as a child of this field part object. The other thing that we want to do is we want to drag the vertical out as a content. As you can see, when we delete the content object. Now the content is missing a rectangular transform. So we need to drag a new one and this will be the content that will show the save progress and we will be able to scrawl it. I want to also add a content size for the vertical, let's just set this two preferred size. Now let's save the scene and let's press play. Okay. So now if we press continue, you see we have a scroll bar on the side, and if I try to duplicate the entry, Okay. You see, we have a scroll scroll bar on the side here. So we can scroll down and then we can select the progress that we want to load for setting things up here, we can probably under the view port here, we can disable the image. So we don't use that, we need that because it's for making for the scroll view, I think, here we can disable the agon image. So we have a better, and we have a better UI for the scroll bar horizontal, we can height this because we don't use it. We cannot hide it. But I think we can disable this. Let's just go to the scroll view here. Let's just set this out of p or we can just remove it, I think. Yeah, set this to. So we don't have a horizontal scroll bar and we can disable this. Once we remove it from the scroll view, no, set this to n, we can disable it. Now if we press save, we will have a consistent UI. Yeah and we only have a vertical you. Okay. Yeah, it's still working. So it's very nice and this will automatically the radical outt will automatically fit the child sizes. So the scroll view will always get longer if we have more content. Another thing we want to do is we want to create a message whenever we successfully save currently, we only can see the message in the console. Let's just go to one of the scene here, couple way, for example, and let's open the data manager script. Here, now we have the data manager opened. Under the safe method, It's this here, I think, not safe entities. Yeah. Under the safe screenshot here, whenever we successfully save here, we want to We want to show the message here. I think it would be best if we put it here under the safe method. Let's just access the dialogue system that instance and use the show message. Here, we can create a new list of strings or we can create new list of strings outside list of string. And then let's call it safe message. And let's initialize this. And then add a new message. Save successfully. Okay. Now that we have this, we can pass this list of string as the message, and then we can set I think it's this one, the bull dialogue, and we can set this two false. It's not a dialogue. It's just a message and close this. Now if we press play and test this out, and whenever we try to save, there's an error here. Okay. Okay, we have a load, so let's just go to the menu scene and then play it from here. And let's open one of our progress. The save is somehow deleted, so I'm going to press new game. And once the cut since is over, let's try to save. Okay, now we are in the scene here. Let's try to press save. There you go. We have this message. So you sir, we'll know whenever we successfully save. Now if we try to play this, let's try to continue again. There you go, our progress. The next thing we need to do is we need to set a couple of things in the build settings. So let's just go to the build settings and go to the player settings. Now we have this player settings. And first, we need to modify the company name. So for example, I'm going to call this Milch because that is my company. And let's just the private e or whatever. I'm not good with naming things. The other thing we want to do is we want to set the Mc store options if we are going to release this on the mac. So basically, for the bundle identifier, we need to set this to the company name, and then the product name. I'm not going to change this. And we also need to set a version, version is basically what is shown to the user and build is the build version that's going to be recognized by the store. Whenever we update an apps, the build version have to be greater number than the previous one. Otherwise, we cannot update it. So make sure that we keep track of this build for each, every updates or path releases. I think that would be all. You can change also the color space to linear. If you are using a HDRP high definition radar pipeline and with the PBR material and stuff, it will look better with linear. But since this is more a tune style, I'm going to leave this to gamma because it's more performance on a lower end devices. The last thing we need to do is we need to set the default icon. So we haven't had any icon so far. I'm going to go to the sprites folder, and I've already prepared an icon, and this is included on this module. So let's just direct and put it inside the sprite folder under the player settings, it asks for a texture two D. I'm going to direct this game icon texture Now once we already set up the player settings, let's just save the project, and now we can try to build it. And if you want to have a wider audience, make sure it's set to 32 bit or x 86, and that is 32 bit compatible with the underscore 64 64 version, and this has a because 32 bit can run on a 64 machine, but a 64 B cannot run in a 32 bit machine. So for greater audience, wider audience, just set this to 32 bit. And then once we finish updating or importing the assets for the target platform, we can build this. Now let's just press built and I'm going to create a new build folder. Then I'm going to add a new folder and this will be the version and the build number. It's easier to keep track, and then I'm going to select this folder and once we select it, it will build the game to that folder. So I'm going to stop the building process and continue after we finish it. Now as you can see here, the build is done, and we have this file. This is basically the build is done and for distributing the game, you only need to include the data folder, the it folder and the unity player folder. And this is for debugging, just zip it and you can distribute it or create an installer. Now let's run this game. So if you press play, It has the settings, and we can set the resolution. I'm going to set a smaller resolution with window options enabled and then press play. So now we have the games. We can continue, but we don't have the safe because this is a different one from the editor, so let's just run a new game. Okay. There you go. We have this game built. I hopefully you find this course enjoyable and useful and it can help you expand your skills with unity, and I hope to see you in another course in the future. Thanks for enrolling. See you next time. 62. 61 PlayerScript Bug Fix: Hey, one of the student found an issue, and thanks a lot to Bruno Bayer for pointing this issue out. Basically, we have a bug where if we try to play and then let's see the bugs here. So if we try to top to one of the NPCs, and before we arrived, we go to the other NPC. I will j see it will show and it will execute the actions from the first NPC, which is this one here. Where it says that can you move out of the way and then it moves the NPC using the move actions, and it should be playing these actions, which is the pole NPC actions. We are going to fix that and text again to Bruno Bayer for pointing this out and also showing me the fix. Basically, to fix this, let's open the player script component. Player script CSR file. Then let's go to the onclick event here or the onclick method, and we need to save the interactable object here to a local variable in our class and keep track if those variable is now or not. Let's just declare one first. I'm going to create a new private and let's just call this interactable and I'm going to call this previous interactable. And let's go I'm going to zoom this a bit, the editor. Okay. Now let's go back to the click method. And inside here, after we finish running the intractable, we can just try to check if, if the previous intractable is not new, then we want to stop the coroutine. Let's just access the object and then run the stop all co routines method. And this will stop all of the coroutine from our previous intractable. After we stop the tin, we want to override the previous intractable to our current newly pick intractable. Let's just assign the intractable back to this previous intractable. This way, basically, when we click on an intractable object, it will try to run the movement, the move player, and then it will intract that intractable. And if there are any previous if the previous interval is not new, then we want to stop the previous coroutines. Then after that, we want to replace the previous intervale to our current intractable. As you can see here, if I opened the intractable script, you see that we have this coroutine wait for player arriving. Basically, the stop stop all courtin method will stop this coroutine here. It will stop any coroutine that are currently running on our previous interratle it will cancel out all of these actions and set directions and stop. So this will fix that and save this. And we also need to put here if we click on a area on the ground. But we have a previous interractable. We want to also cancel that. So let's just copy this statement here and put it here. But we want to create a bracket and then put the top cortins inside this statement. And after we stop the art, we want to set the interractable to. This will clear out any previous interracable. Okay. And next time we move to any other position, we won't trigger the less intractable by accidents, and if we click on intractable, it will just loop the code here and then try to check if we have any previous intractable or not. Okay, this should fix the issue. Let's just give it a try. So it's still compiling right now. Okay. Now, let's try to talk to this person here and then go to the police officer. And we cancel out the actions from our NPC, and he doesn't move. And it shows the actions from the police NPC, as you can see here. Good day, and then we can respond and we can show the button. And if we press awesome, it will reply. But there is another issues where if we try to talk to the police go jump on fee then before clicking the button here, one of the button, we go to the other position and it will disable the message. But if we go to talk to this other NPC, it will show the button. So we need to fix that. So now we need to go to the dialogue system. Okay. And here inside the dialogue system, we have the hype dialogue method. So instead of the activating the panel, we should be using this method, so I'm going to change this using the hype dialogue method. Okay. Also, the one that we declare on the no button Let's just remove this and replace this with height dialogue. This is basically we'll do the same hiding the panel. For button, we want to set a height dialogue and also for the button to be the default listener. Then back to our height dialogue, we want to disable a lot of things here. First, we want to stop all routines whenever we hiding dialogue. It will stop any previous routine. The next time we are showing new message, it will start a new fresh routines with a new argument values or parameter values. And this will fix the button that keep showing if we didn't finish our previous dialogue. And then we want to set the message ID to zero. Yeah, I think it should do the trick. So let's just give it a try. Go back to unity and let it compiled for a second. Once it's finished, let's give it a try again. Now if we press play and we try to talk to the police officer. And then we don't finish the dialogue. We go somewhere else, and then if we talk to this NPC, it should hide the button, as you can see. Okay. So yeah, that is basically the fix for our player script and our dialogue system. Thanks again to Bruno Bayer for pointing this out. Okay. 63. 62 Entities Resets on Scene Changes Bug Fix: Okay. So in this video, we are going to fix another small bugs, and thanks to Bruno buyer for pointing that out. Basically, the issue is with the entities. Currently, if we change scene, all of the entities that are changed in the previous scenes are not stored in the safe data. So we need to fix that. And I'm going to show you the issues here. Let's just run the game, and then let's go to the here to the door here and try to talk to the door, the bouncer, and it will tell us that we have the wrong password. If we go to this wall here and we will see the writing, and once we know the password, we can go inside this room. But if we go back to the outside of the club here, if we try to talk, then it will show the wrong password again. And we need to fix that since the player already know the password. Those states where we answer the correct password should be saved. In order to fix that. First, we need to open the change scenes action and also the data manager. I'm going to open the data manager here. And here inside the data manager, we need to add a new method to save all of the entities on our scene, and we can just trigger the event here, the actions event. Instead, but we are going to trigger the unsafe event. So let's just type public void, and I'm going to call this store entities state. And then I'm going to trigger the unsafe event and save the data manager. Once we've created this unsafe event here, the public method, store entity state, we can go to the change scene action, and after we setting the previous scene, based on our current active scene before we are transitioning to another scene. Let's just access the newly created method in the data manager. Let's just store the entity state. And basically what this is doing is whenever we transition to another scene before we finish transitioning, we are going to make sure that all of the entities that are changed its child active status will stored into the dictionary in the data manager that we have here. I think it's in the safe data. Let's just check this. Yeah. All of the entities will store its data to entity data here, and including the child status because we are using the different child to trigger different messages. So yeah, let's save this and go back to unity, and now we can test this out. Okay, I'm going to play this again and let's go to this area here and let's just talk to the bouncer first and go to see the correct password. And then let's go back to the door here. And once we enter the scene here, let's try to go back outside and let's talk to the bouncer again. And now we will remember the change state hence it will show like the player remember the password. So yeah, that is the small issues that we have before and now it's fixed. Thanks again, Bruno Beer, for pointing this out. And if you have found any issues or any bugs, just let me know and I'll try to fix it, and then I post another video to how to fix it. Thanks. Okay.