GameMaker FREE RPG Crash Course: NPC, PATHFINDING, DIALOGUES

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi there welcome to the first part of making our rpg we are going to start with importing tiles and filling our world using game maker's auto tiling feature for this we are going to start with a fresh new project first of all in the asset browser we have a lot of groups we are not going to need most of them at least for this section so i'll select them using shifts and my mouse and delete them same for these i'll leave the room scroll there because it already has a room which we are going to need now i'll create a new group four sprites so this will contain any sprites that we create before we do that i'll go up here in the filter menu and change the order from a to z to custom order this way we can place our assets in any order we want and they won't be alphabetically sorted it just gives us more control over the asset browser now in the sprites group i'll create a new group called tiles this will contain the sprites for our tile sets i'll create a new sprite here and name this as styleset ground in the sprite editor i click on import and go to the resources for this course here i have a tileset image for the ground so i'll import that so you can tell that this style set is for the ground now in the same group i'll create another sprite and name this as style set collision the style set will be four things that can collide with the player so they will stop the player i'll import an image for this as well we need to create the actual tile set assets now which let us use these sprites as styles i'll make a new group in the asset browser called tile sets here i'll create a new tileset assets and call this tes ground ts here simply means styleset you can assign a sprite to it by simply dropping it from the asset browser so i'll take my ground tile set sprite and assign it to my new tile set if you want you can also assign a sprite through this button now here you can change the size of each style and 16 by 16 actually works out for our tile set so i'm gonna leave it as it is of course if you're using a different tile set you can change this now we are going to set up auto tiling for their style sets this way you don't have to worry about manually placing each corner tile and game maker will handle that for you let's click on this auto tiling button here and set it up in this new window you can make two kinds of auto tile sets one that uses 47 tiles and another that uses 16 we're gonna go with the 16 one so click on it and it will create a new auto tile set here you can assign tiles according to the white and gray areas let's just say that the white part is the grass and the gray part is the dirt so click on this and one by one start selecting the tiles that fit you can click on this button to see an overlay and make sure that you are selecting the correct tiles if you mess up you can always change the tile and now i'll go ahead and fill in all of these and now our auto tiling is complete let's set up another tile set in the tile sets group i'll create a new tileset asset and name this ts collision i'll assign the collision tileset sprite to it now we don't need any auto tiling for this it's just a few obstacles that we can place around the room but we can do something interesting i'm gonna open the brush builder window on the left here we see our tile sets and on the right we have an empty canvas where we can create different brushes or groups of tiles for example i'll create different shapes of bushes i'll also make some for rocks and now these are all different brushes that we can use in the room let's go into the rooms group now i'll right click on the room here and rename it you can also press f2 i'll change its name to rm world because this will be our game's world i'll open the room now down here at the bottom in the room settings i'll set the size of the room to 640x640 i know that seems small but we are making a pixel art game which uses low resolution sprites so this is going to be big enough but of course you can make it as large or as small as you like let's start placing our tiles and for that we first need a tile layer in the layers panel i'll click on this button to create a new tile layer i'll rename this to tiles ground i'll also make sure to place it below the instances layer because we want it to appear below instances such as the player down here we have the tile layer properties and it currently doesn't have a tile set assigned to it i'll click on this and select the ts ground tile set and we can now start placing tiles in this layer on the right side of the ide you'll see a new panel and this is used for selecting tiles from your tile sets you can select each individual tile and place it in the tile map i'll select the basic graph style then up here i'll choose the fill tool and fill the room with that tile now we're gonna go under libraries and here we have auto tiles select this and now you can place tiles using the auto tile feature left clicking will not do anything right now because the room already has grass so you can instead right click to place dirt you can then left click again to place grass let's use it to create parts and design our world the ground tile layer is done so now let's place the collision tiles go into the layers panel and here create a new tile layer let's name this styles collision and make sure that it's placed above the tiles ground layer but below the instances layer now in the properties below click here and select the collision tile sets you'll see those styles here so you can start placing them and you can also go on the brushes and see your brushes down here you can select any of them and place them in the room and this makes level creation much faster so i'll place some around and build my world now after you've placed all of your bushes and rocks you can use the eraser tool to cut out a path and just make use of these tools to design your world in your way so we now have our world set up with all sorts of trials if you run the game however you're gonna see the whole room in the window that's not how games work he wants to have a camera in the game that only shows a part of it and follows the player so we are going to work on that camera and set up the game's resolution in the next lecture hi there in this lecture we are going to set up our camera and the game's resolution we are going to do this in a script a script is usually used to create a function but you can also create other stuff like different kinds of variables everything you create in a script is globally available throughout the projects and the code within the script runs as soon as the game starts so this is a good place to initialize global data and to set up the window size and so on one kind of variable that we're gonna create in this lecture is called a struct you know how a variable can store a value and you can create multiple variables to store different values a struct is simply a collection of variables so you can create a struct using curly brackets within those brackets you can create variables with values but instead of using the equal sign here you use the colon sign this is simply how you create variables inside a struct you can then add a comma and create more variables and so on and this is simply what a struct is now to get a value from struct you simply write the name of the struct followed by a dot and then the name of the variable that you want to access so creating and using a struct is just that simple in the asset browser i'll create a group called scripts which is going to store our script assets make sure that the scripts group is selected then go up here and create a new script assets i'll name this scr resolution where scr stands for scripts you'll see the script window open up in the workspace and inside the script we already have a function we'll learn about this in a later lecture but right now we don't want to create a function so i'll remove this we just want to create a struct and call some functions to change the game's resolution let's create a struct to store the game's resolution information i'll add this here we are creating a new global variable called res short for resolution we are setting this equal to a new struct created using curly brackets let's add our first variable inside this struct this variable is called width and it has a value of 320 notice how we are using a column sign here instead of the equal sign because we are now inside a strut now let's add some more variables make sure to add a comma before creating a new variable and now let's see what these are first we have the width and the height of the game's camera this means our game's internal resolution is 320 by 180 that works out for our pixel art game but that means that the window will be very small and that is why we have a scale value here this means that our game window will be 4 times larger than the camera size so we can easily see the game let's change the game's resolution now for that i'll add this first of all here we are creating a local variable called width which stores the final width of the game window so here we are getting the camera's width from our struts by entering the struct's name then a dot then the name of the variable that we want to access and then here we are getting the scale we are multiplying them together which is then stored in the width variable then we are doing the same for the height multiplying the height with the scale and now we know what the final size of the window should be now here we are running a function called surface resize we are using this to change the resolution of the game now a surface is simply a canvas where something can be drawn and the application surface is where the game is drawn sorry sizing it changes the resolution we are setting its width and height to our game windows width and height so that's the resolution but we also need to resize the window itself so i'll add this we are running a function called window set size and this changes the size of the game window we are setting it to the width and height in our local variables after that we are running a function called display set gui size which changes the size of the gui layer that is drawn above the game this is used to draw the hud and other gui elements and will make it the same size as the window itself if you run the game now you'll see that the window has a different size we still need to make a camera but you'll notice something odd the window is not in the center of the screen we want it to be created at the center so let's add some more code to our script to handle that i'm going to add this here this function gets the width of the display which means the whole screen and not just the game window we'll store that in this variable then we'll get the height of the screen so now we know what the resolution of the user screen is which we can use to center our window on that display now here i'm running a function called window set position which is used to change the position of the game window on the display it takes two arguments the x position and the y position for the window now i know this looks odd but i've simply placed each argument on a new line to make it easier to understand and now let's see what each argument is for the x position i am dividing the display width by 2 to get its center point then i'm dividing the window width by 2 so i get its center point then i'm subtracting that from the display center so that the window is placed in the center on the x-axis and then i'm doing the same on the y-axis dividing the display height by two then dividing the window height by two and then performing a subtraction if you run the game you'll see that the window is centered now but we are still seeing all of the room so now we are going to set up a camera we will do that in a new object so in the asset browser i'll create a new group and name this objects in this group i'll create a new object and name this or room manager so this will manage things related to the room which includes the camera now let's open the room make sure that the instances layer is selected and place the room manager anywhere you like now let's go into the room manager objects and here at the create events in this event we are going to create the camera so first i'll add this here we are simply getting the camera's width and height from our global struct and storing them in these local variables we are only doing this so that they are easier to write since these local variables have shown the names and now we are going to call a function to create our camera here i'm calling a function called camera create view and this is used to create a camera that camera will be stored in this variable but first we need to pass some arguments to this function so let's do that these are the initial x and y coordinates of the camera so we can just set that to 0 and 0. then we have the width and height of the camera so we are passing in the width and height that we got from our structs and now there are some optional arguments that we are going to pass in to supply some extra info to the function this is the angle or rotation of the camera and since we don't want it to rotate we are setting it to 0 then we have the object that it should follow later we are going to set this to the player but right now we don't have an object for that so i'll set this to no one which simply means no object or instance then we have the speed limits of the camera on both axis and since we don't want a limit we'll set these to -1 that simply means no limit and finally we have the x and y borders of the camera this is simply how much margin the player has within the camera space to move around until the camera also starts moving we want the camera to always move with the player so we'll set the x margin to half the width and the y margin to half the height now we need to enable views since the camera system makes use of the view system so i'll add this first of all here we are enabling the view system this variable is green because it's a built-in variable so whenever you see a green variable it means that it's a special variable that has a certain functionality in gamemaker so for example this variable can be used to enable or disable views then we are making the first view visible since we only have one camera we have zero here so that means we are enabling the first view these brackets are used with arrays so this is an array but we don't need to worry about that right now as we learn about them in the future now here we are calling a function called view set camera which is used to assign a camera to a view we are assigning our camera to the first view which is view zero so our camera will now be used and it will be visible in the window everything is done now but only one thing is left we need to make sure that this camera is destroyed when the room ends so in the events window i'll add the clean up event this event runs whenever the instance is destroyed or the room ends and can be used to clean up any resources that we have created and don't want anymore since the camera is created whenever a room starts it should be destroyed when that room ends so here i'll add this this function will simply destroy the camera that is stored in this variable let's run the game now and in the game window you now only see a part of the room so the view is not distorted anymore this means that we can easily add a player object and when the player moves around the camera will also move so now let's start working on our player character in the next lecture hi there in this lecture we are gonna set up our player object making our player character with movement will be a lot of work so i am dividing this into separate lectures in this lecture we are gonna import the player sprites create a character parent and set up the player object now let's first talk about what parenting is a parent object is used as a base for an object so let's say we create a character parent object this will have all the code that's required for a character to move and animate now since this is a parent it means that other objects can be its children so that they behave in the same way for example you can have the player as a child of the character parents so the player will now move around and animate according to its unique properties you can then create npcs and enemies which also move around because of the character's appearance this means you have the movement code in the parent only you're not copying the code so the code that you wrote in the character parent is being used by multiple objects and that is the purpose of a parent object let's go into our project now and import sprites for our player in the sprites group i'll create a new group called player we're going to import the player sprites here and their names will have a specific format we want to import price for two states idle and work each state has four directions so we name a sprite in this way as player then underscore then the state name then another underscore and then the direction for example we could have s player idle down as player walk down as player walk right and so on now in the player group i'll create a new sprite and name this as player idle down i'll import an image for it from the resources that matches the file name i'll change its origin to middle center so we now have the player's idle animation facing down by the way all the player images will need to have their origins set to middle sensor so instead of having to do that every time you import a sprite you can make that the default option go into the file menu then open preferences here select sprite editor and in this option set the default sprite origin to middle center press ok and now all the news price that you create will automatically have a middle center origin now in the same way i'm going to import more sprites as player either left s player idle right and s player idle up you can import these in any order you like now we need to import the vox sprites by the way to neatly organize our state sprites we can create new groups so in the player group i'll create a group called idle and i'll place my idle sprites here then i'll create another group called work and this is where we'll have our box sprites now here i'll create a new sprite and name this as player walk down [Music] i'll import an image for it if you play it you'll see that it's too fast so i'll change the fps here from 30 to 12 and now the animation looks more natural now in the same way i'll import s player walk left s player walk right and as player walk up make sure to change their animation speeds as well so that's the player's price done let's add up our character parent and player object now in the objects group i'll create a new object and name this or character parent then i'll create another object and name this or player so this will be our main player object i need to assign a player sprite to it so i'll select the idle down sprites what sprite you select right now doesn't really matter because we are going to animate it later now we need to assign its parents let's open the parent menu from here and this is where you can see the parent that is assigned and the children that are assigned to this object we want to assign a parent so i'll click here and under objects i'll select all character parent this is now a child of that object if you go into the character parent object and open the parent menu you'll see the player in the children list let's go into the room now and place the player object here now the grid is too large for me right now so i'll go here to change it our game uses 16 by 16 tiles so i'll just set the grid to that and now i can place my player more accurately now before we set up our character we need a new script with some data i'll go into scripts and create a new script i'll name this scr data now in the script i'll remove the function and add this here i'm creating a macro a macro is like a variable but it's global and you can't change it i'm making a macro called tile size which has a value of 16 so this will stay 16 throughout the game as a constant value and this works out for us because we know that the tile size isn't just going to change in the game and as per my style i write macros in all capital letters so this macro will now be globally available to be used by any object let's work on the character parent now i'll open the character parent object and in the events window add the create event here we'll initialize some variables that we'll use for input and movement so i'll add this these variables show the input that the character is getting on the x and y axis these will be different based on the child object so while the player will get input from the keyboard and then pc will calculate its own input so that's basically the purpose of these variables let's add some more variables now this is the speed at which our character will move so that's one pixel per frame then we have a variable called moving which is set to false this shows whether the player is currently moving or not so when this is true it means our player is currently moving to another tile and if it's false it means that the player has stopped then we have move direction which is a direction that the player is facing in this will be used to figure out which sprite the instance should throw then we have target x and target y these variables store the coordinates of where the player needs to move by default they are just set to the current x and y of the instance but whenever the player gives their input these variables will be changed to tell the player where it needs to move so all of this gives us a basic overview of how our movement system is going to work now let's add another event this time we'll go on the step and select begin step this is just another step events that runs before the main step events will be using this to set the input variables but not in this object this event will be used by a child object to set its own input so for example the player can read input from the keyboard and an npc can calculate its own input now we are going to go in the events window again and this time add the step event which is where our movement will take place we will code our actual movement here later but for now just to get some basic temporary movement let's add this here we are multiplying the x input with the move speed and adding that to the x so it moves on the x axis and then we are doing the same for the y axis now let's see how these input x and input y variables will be set which will happen in the player object so i'll open that first of all in the events window you can see all of the events that we added in the character parent because this is a child of that object you can now inherit an event so that the parent's code runs but you can also add your own code to the event let's right click on begin step and select in hide event this adds that event into this object now in the event you will see an event inherited function which is going to run the parents code in this event if you remove this then the parent's code for this event will not run now let's add some code here for the player to get movement input from the keyboard specifically the wasd keys let's first see what we want from the input x and input y variables if the player wants to move right this should be one if the player wants to move left this should be -1 now for input y if the player wants to move down they should be 1 and if the player wants to move up then this should be -1 if there is no input then both of these variables will just be 0. here we are getting input from the d key then here we are getting input from the a key let's say the d key is pressed then this will return 1 and the a key is not pressed so that will return zero one minus zero is one so input x will get that value and the instance will move right now let's say d is not pressed but a is pressed zero minus one is minus one so input x will get that value that way the instance will move left this is how our input code is essentially working then here we are doing the same thing for input y where it will be 1 if the s key is pressed and -1 if the w key is pressed so pressing s will move it down and pressing w will move it up now the final task in this lecture is to update the camera so it follows the player let's open the room manager object in the create event we have code to create the camera here in the camera create view function we have this argument to tell which object the camera should follow right now it's set to no one so let's change it to all player and the camera will now follow the player if you run the game now you'll see that the player is able to move around using the wasd keys and the camera is also following the player but of course this is not our final movements as we'll make great bass movement where the player moves from one tile to the next so let's continue working towards that in the next lecture hi there in this lecture we are going to implement grid based movement for our player currently for moving our instances we have been working with room coordinates however to move our player from one tile to the next we'll be working with dial coordinates as well so let's look at the difference between room coordinates and tile coordinates let's say this is our room in a room coordinates are based on pixels so starting at 0 this is 16 pixels on the x-axis this is 32 pixels on the x-axis this is 48 this is 64 and so on these are room coordinates now since the size of each style in our gain is 16 by 16. we'll divide these room coordinates by that amount which will give us 0 1 2 3 and so on and these are tile coordinates we'll be working with tile coordinates to make it easier and more accurate to do great base movement let's say the player is at 16 pixels i can just convert that to tile coordinates which will give us one then i can say move plus one tile so the player will move to the next style which is two so this really makes it easier to do grid based movement now to actually move the player from one tile to the next we will be using room coordinates but we'll use style coordinates to do our calculations and to check for obstacles on the new tile we'll be creating two new functions to convert a coordinate value to tile coordinates or to room coordinates the function to tile will convert the given room coordinates into a tile coordinate and the function to room will convert the given tile coordinate into a room coordinate let's open our project and start working on it in the asset browser i'll go into the group for scripts in this group i'll create a new script asset and name this math functions because we're going to put math related functions in the script now in the script let's rename the function to true tile this will take one argument called val short for value we are assuming this value as a room coordinate so this function should convert that into a tile coordinate and return that value for that i'll add this into the function here we are dividing the given value by the tile size this dev operator makes sure that the result is an integer so the value will be divided by the tile size and the result will be rounded down to return an integer value then that value will be returned by the function because of the return keyword here also when you use return the function ends there so if you add any code after this it will not run because the function ends when you use return now let's add another function in the same script i'll call this to room and it will also take an argument called val this argument will be a child coordinates and this function should convert that into a room coordinate so in the function i'll add this here we are multiplying the given value with the tile size and the function is returning that this way the tile coordinate is converted into a room coordinate so overall in these functions all we are really doing is we are dividing a value by the tile size to get the tile coordinates and multiplying it with the tile size so we get the room coordinates the calculations are very simple but we have created functions to make it simpler to repeat the calculations let's work on the actual movement code now i'll go into the orchestra parent objects and here open the step event i'll click here to maximize the window so we can see the code more easily now there will be two parts to this event the first part will read input from the player and set the target position where the player needs to move then the second part will actually move the player to that target position and stop it when the player has reached there first of all we'll remove this code as it was only temporary and now we'll work on the first actual part of this event i'll add this here here i have a condition that checks if input x is not zero this means we have input on the x axis then we have another condition checking if input y is not zero meaning we have input on the y axis we have joined them together using the or operator so the whole condition will be true if we have input on either axis let's add another condition in this block now this condition checks if the moving variable is false we are doing this to make sure that the player is not already moving so we can tell it to move within this block let's add this if the player is giving input on both axes the player will move diagonally but we don't want that we only want it to move in one direction at a time so here we are checking if input x is not zero meaning we have horizontal inputs so in that case we are setting input y to zero so in case the player is giving inputs on both axes at the same time our system will prefer the x input over the y input now let's calculate the position of the tile where the player needs to move by adding this let's look on the right hand side of the first line here we are taking the x position of the player and converting it into tile coordinates this will give us the player's current tile position on the x-axis then we are adding the input x value to that so if input x is 1 or -1 that will be added to the player style position giving us the tile position where the player needs to move that will be stored in the new tile x variable here then we are doing the same but on the y axis converting the player's y position to tile coordinates adding input y to that and storing the results in new tile by so we now have the tile coordinates of where the player needs to move based on its input we are now going to check if the player can move there and set the target position if it can for that let's add this first of all we have a variable this will store whether the player has found a collision at the new tile or not currently we don't have any collision checking so as a placeholder we'll just set this to false this means that the player can move there we'll add actual collision checking here but in a later lecture now here in this condition we are checking if that collision variable is false which means that the player can move in that case we want to set the target x and target y to the position where the player should move but those variables need to be in room coordinates so here we are calling the two room function to convert our new tile coordinates into room coordinates but you'll notice that we are also adding 0.5 to those values that's because by default you will get the top left coordinates of a tile but the player needs to be in the center of a tile that's why we are adding 0.5 to the tile coordinates so the position is offset by half a child and the player is positioned in the center now the converted room coordinates will be stored in the target x and target by variables which we'll use later to move the player to that position after that we are setting the moving variable to true so we know that the player is now moving now let's add code to actually make the player move we'll do this at the bottom of this event after all of our previous code i'll add this here here we have a condition that checks if the player is moving if it is we want to determine how far it is from its target position so for that we are using the point distance function which gives us the distance between two points the first point here is the player's position so it's x and y and the second point is the target position so the target x and target y this will get the distance in pixels between these two points and store it in this local variable now if the player has not reached its target position yet we'll move it there so for that i'll add this here in this condition we are checking if the distance to the target position is greater than the player's movement speed it means that the player has not reached that position yet in that case we want it to move there and here you can see that we are adding something to the x and y so let's see what that is starting with the x we are subtracting the current x position from the target x position so we know how much the player has to move on the x-axis to reach the target that value is then passed into the sine function this function basically simplifies a value so if it's positive it becomes 1 if it's negative it becomes -1 otherwise it remains zero so depending on the distance between the x values will get either one or minus one that will then be multiplied with the move speed and then add it to the x this way the player will move towards the target with a constant speed then we are doing the same thing but on the y axis getting the difference between the current y and the target y getting its sign multiplying it with the move speed and adding that to the y so this handles moving the player to its target position but what happens once it reaches there well this condition checks if we have not reached the target yet so we can add an else block which will run when the player has reached its target so i'll add this this s block will run if the player has reached near its target position in that case we simply set the x and y equal to the target x and target y so the player is exactly on the spot where it's supposed to be and then we are setting moving to false so we now know that the player has stopped moving and with this our grid based movement is complete in the first part we are reading player input and telling the player where it should move then in the second part we are actually moving the player to that target position until it reaches there if you run the game now you will see that the player moves style by tile based on the player inputs which we assigned to the wasd keys you can also hold the key to move the player constantly without interruption until you release the key and the player stops on a tile now the next step in our rpg is to animate our player because currently it only shows one sprite it should make use of all the sprites that we have imported so we'll do that in the next lecture hi there in this lecture we are going to work on state based animation we are going to set up two different states for the player idle and walk each state has 4 sprites left right up and down so depending on the state of the player whether it's idle or walking and depending on the direction that it's moving in we'll select a sprite now the sprites for each state and the states themselves will be stored in structs so we'll be able to access a sprite from a struct like this first we have the state struct that contains all the states then the struct for the state that we want to access so in this case it's idle and then the direction of the sprite which in this example is left so that should give us the sprite for that state and direction and that's how we're going to set up this struct let's go into the project i'll open the all player object we want to set up the states in the create event which we already got from the parents so here i'll inherit that event now in the event i'll add a struct for the states now in this struct we're gonna create another struct to store the sprites for the idle state so i'll add this now in our main struct we have a new struct called idle note that we are using a column here because now we are inside a struct so now we don't use the equal sign but the column sign now let's fill this idle struct with sprites for each direction so now in this struct we have variables called left right up and down and they store the correct sprites for each direction which are for the idle states note that we have commas at the end of each variable assignments because we are in a structure now let's set up the work state in the same way after the idle struct let's add another struct this is our work state which has sprites for each direction the sprites are for the walk states now make sure you have a comma after the idle structs here because after this we are initializing the work struct so our states are set up now but we need a variable to tell which state the player is in so i'll add that here this state variable tells us which state the player is using and by default it's set to states dot idle now we need a function to figure out which sprite the player should be using depending on the state and the direction so let's go into our character parent objects and here open the create events we'll create a new function here at the end so i'll add this this gets pride function should return the sprite that the player needs to use it takes the movement direction as its arguments so in the function let's add this if the direction is 0 that means that the player is moving right this variable stores the state that the player is currently using so we get the right sprite from that state and return it then we have more conditions for the other directions if the direction is 90 then the player is moving up so we return that sprite from the state if the direction is 180 the player is moving left and if it's 270 then the player is moving down now whenever the function returns something it ends at that moment so the code in the function after that line doesn't run so if none of these return statements run it means that the direction was invalid for any reason so to stay safe at the end here we are returning the player's current sprite which is stored in the sprite index variable let's now figure out what direction the player is moving in for that i'll go into the step event and go into this part where the player is moved towards the target here i'll set the move direction variable using the point direction function we are getting the direction between two points the first point is the player's current position and the second point is the target position so it returns the direction towards the target and applies that to the move direction variable we are doing this only in this block so the move direction is only changed when the player is moving we can now use this variable to set a sprite for the player so at the end of the step event i'll add this here we are running our get sprite function and passing in the move direction variable as the direction the function will then return the sprite that the player should use based on the direction which we will apply to the sprite index variable this variable stores the sprite that the instance is using so changing its value changes the sprite of the instance let's run the game now you will see that the player turns when we move so that part works however it only shows the idle animation and that's happening because we are not actually changing the state yet so let's work on that let's go back in the create events and here we'll create a new function which will be used to change the character state so i'll add this here we are creating a function called set state this function takes one argument called new state which is the new state that we want to switch to here we have a condition checking if the player state is already equal to that new state and if that is true we use return to end the function we are doing this because if the player is already using their states then we don't need to change it but if the player does not have that state then the function will continue and here we are setting the state variable to that new state so that the state changes then we are setting the image index variable to zero this variable stores the frame that the sprite is on now when we change the state we want the character's animation to reset so it starts from the beginning and doesn't play from the middle and that's why here we are setting the image index to zero let's now use this function in the step event or scroll down to the block where the player moves after checking if moving is true in this block i'll call the set state function and set the state to states dot walk so here we are telling the instance that the player is now working now to change the state to the idle state when the player is not moving i'll add an else block after this condition this else block will run if the player is not moving and in that case we are setting its state to idle so this way we are now controlling the player's animations using states let's run the game now and you can see that the states are working correctly it shows the idle animation when we are not moving and the walk animation when we are moving our game is looking pretty solid already now there is a small issue that should be pretty easy to fix when the game starts the player moves diagonally to fit into the grid because its initial position is not in the center of a tile you might not get this issue so in that case you can continue to the next lecture but if you do here's how we are going to fix it to fix this we'll go into the room editor make sure that the instances layer is selected and that the grid is turned on i'll set the grid size to 8 by 8 which is half of our tile size then i'll move the player right by one tile and then down by one tile so now my player instance is centered on the 16 by 16 tile and when i run the game i don't get that issue anymore now to make our rpg world feel real we need to have collisions when the player comes across this bush it should stop so let's work on that in the next lecture hi there in this lecture we are going to work on tile collisions in our room we created two tile layers one for the ground and one for the collisions we'll make it so that the player can collide with any tiles that are in this layer now each style layer has a tile map which draws its styles we'll need to get the tile map for this layer in our code and then use it to check for collisions let's open our project and go into the room manager object i'll open the create events and here we'll get the tile map id for our collision layer so i'll add this the layer tile map get id function gets the tile map id for a layer this is the name of the tile layer that we want to use make sure that this name matches the name that you gave the layer in the room editor otherwise collisions will not work now the id of this style map will be stored in this variable called call tile map now we need to create a function to check for collisions we'll do that in a new script let's go into the scripts group in the asset browser and here create a new script asset i'll call this collision functions in the script i'll change the name of the function to collision this will take two arguments tilex and tile y these are the tile coordinates where we are checking for collisions and if it finds a collision add that tile then the function returns true if it doesn't find a collision then it returns false and that means that the player can move to that tile now in the function i'll add this first of all we are getting the tile map for our collision layer from the room manager objects we are storing it in a local variable just to make the code cleaner then we have a condition where we are calling the tilemap get function this function gets the tile at the given tile coordinates in the given tile map and it actually returns a tile number but we only want to use this as a condition now in the arguments we are first passing in the tile map that we want to check and then the tile coordinates which we are taking from the arguments if it finds a tile then it will return true and the function will end there however if a tile is not found then the function will continue and at the end here it will simply return false we can now use this function in our movement code let's go into the character parent object and open the step event here we have the collision variable that we set to false we can now replace this with a call to our new collision function so i'll add this this will now check for a collision on the tile where the player wants to move and store the results in this variable if the variable is false then the player will start its movement otherwise it will not do anything let's run the game now and if i move towards a collision tile you can see that the player stops so our tile collisions are working perfectly now there is one improvement we can make if you are on a trial and you try to turn and there is a collision where you are trying to move the player does nothing however it should at least turn in that direction so the player feels like their input has done something to implement this we're gonna go back into the step event of the character parent and here we have the block that starts the player's movement and does so if a collision is not found we can add an else block to this condition which will run when there is a collision so i'll add this this else block will run if the collision variable is true which means that the player found a collision in that case here we are getting the direction of the player's input so this function is getting the direction from 0 by 0 to the input x and input y values that direction is then applied to the move direction variable this means that when a collision is found and the player can't move the direction will still change based on the input you can see that in the game now when you try to go somewhere the player can't move it still turns to face in that direction now we have tile collisions working but what about objects we want to add trees and they will be objects so we also need to work on object collisions let's do that in the next lecture hi there in this lecture we are gonna work on object collisions by adding trees i'm gonna go straight into the projects and set up the sprites for our trees in the sprites group i'll create a new group and name this environment in this group i'll create a new sprite and name this as 31 so this will be our first tree i'll import an image for it and here change the origin to be at the foot of the tree now every sprite has a mask which is used for collisions with other objects we need to change the mask for this sprites so here i'll open the collision mask menu and change the mode from automatic to manual you can now move and resize the mask in the sprite preview here so i'll make it very small and place it around the origin here this makes sure that when the tree is placed on a tile that it only covers that tile and not any neighboring tiles now in the same way i'm going to create another sprite called s32 import an image for it set the origin and also change the mask now we're gonna work on the objects so here in the objects group i'll create a new group and name this environment in this group i'll create a new object and name this or collision this will be a parent object for all the objects that can collide with the player now i'll create another object and name this o31 i'll go into the object and assign the s3 one sprite to this then i'll create another object this will be o32 and i'll assign the s32 sprite to this now these two objects need to be children of all collision so i'll go into that object and open the pad menu we will assign the children in this children section here so i'll go in the asset browser select those two objects by holding ctrl while selecting them and then drag them into the children section here now let's go into our room and start placing these objects first of all make sure that the grid size is set to 16 by 16 and then we can start placing our trees now the problem is that by default they are placed in the corners of the tiles but they need to be in the center so you can hold ctrl and move it independently on the grid or you can go in the grid settings here and disable snapping this way you can now place your trees wherever you want so make sure to always place them in the center of a tile so that they only fill up the current tile and not any neighboring tiles in the same way let's go ahead and place some other trees now to add some extra variation you can double click on an instance to open its properties and then take the flip x option to flip it on the horizontal axis that's where you can get more variations in your trees i'll also move the player now let's add up our object collisions for this i'll go into the collision function script and we'll add some more code to this collision function after the line where we return true but before the line where we return false i'll add this let's look here first we are getting the center tile coordinates of the given tile and converting that to room coordinates we're gonna use these room coordinates to check for collisions where the for that here we are using the position meeting function in a condition this function checks if there is an instance at any given point in the room so these are the coordinates where we'll check for a collision and this is the object that we are trying to find which is all collision now because this is a parent object this collision check will also include its children which are o31 and o32 so if this function finds a collision with these instances then it will return true in that case our collision function will also return true to tell the player that a collision was found if there wasn't a collision then the function will continue and return false at the end so you can run the game now and see that the player collides with the trees now depending on how you place the trees you might see graphical issues such as this tree appearing above this tree to fix this we need depth sorting and we'll work on that in the next lecture hey there in this lecture we're gonna work on depth sorting as we saw in the previous lecture you can face graphical issues in your game such as this where this tree appears above this tree when it should be behind it this is happening because we haven't implemented depth sorting yet which is very important in top down rpg games to work on this we're gonna go into the all room manager objects and in this object we're gonna add a new event which will be end step this event runs after the step event and we are using this to make sure that all of the other instances have moved before we do our depth sorting so now in this event i'll add this here we are using the width statement this is used to run some code in some other instance or instances of a specific object here we are using all so it means that whatever code we have in this block will run for all instances in the room you can also put any specific object name here to run code in the instances of that object but for our purposes here we are using all so the depth sorting is applied to all instances now inside the width block here we are changing the depth variable of the instance thus running the code the depth is the distance of the instance from the camera so if the depth is low it means that the instance is closer to the camera which means it will draw in front of other instances we are setting the depth to negative v box bottom the b box bottom is just the y position of the instance but on the bottom edge of its mask we are using this point for our depth sorting because that's where the feet of our characters are now we are making this value negative so if that y position is larger then the depth is lower which means that if an instance is below another instance it will be drawn above it if you run the game now you'll see that the graphical issue with the trees is solved because of depth sorting another example is how the player is drawn behind the tree but if you move down it's drawn above it so our depth sorting makes our world feel more realistic as instances move behind or in front of each other now in this section we worked on our world by adding trees and collisions and we also worked on our player by making grid based movement and state-based animation in the next section we are going to work on npcs that move around in the world and after that work on a dialogue system so i'll see you in the next lecture hi there in this lecture we are gonna set up our npc and ai objects let's go into our projects here in the sprites i have a folder for an npc called bob and i've imported all the sprites for it you have four idle sprites and four walk sprites same as the player when you're importing these make sure that their origins are all set to middle center and also make sure to set the speed of the working animations to 12 fps let's create the objects now in the objects group i'll create a new group and name this ai in this group i'll create an object and name this oai parent this will be a parent object for all the characters that are ai controlled which includes the npcs and any enemies now i'll create another group within the ai group and name this npc's in this group we'll also create an object and name this o and pc parents so this is a parent object for all npcs and it'll be a child of the ai parent let's open the ai parent object in the parent menu i'll set its parent to or character parents so these will be ai characters and in the children list i'll add onpc parent so it'll be a child of the ai parent this means our hierarchy right now is character then ai then npc on the character we have our player under npcs we'll have two npcs bob and jazz and later in the course we'll create an enemy parent which will be under ai and contain all the enemies now let's create our first npc in the npc's group i'll create an object called onpc bob i'll assign its idle down sprite to it and in the pad menu i'll set its parent to onpc parents because this is an npc let's set up its price now for the idle and walk states for this i'll inherit the create events in the event we'll set up the sprites using structs the same way we did in the player so i'll add this here we are setting up the sprites for the idle and walk state of the npc the sprites are correctly assigned based on the state and the direction this is exactly the same code we had in the player but the sprite names are different so you can copy this code from the players create events and just change the sprite names then at the end here we are setting the state to the new idle state now i'll open the room and place a couple npcs here make sure to set the grid size to 16 by 16 and then place them in the center of a tile just like the player i'll add another npc now if you're on the game they are simply there and don't do anything but because these are children of all character parents they are fully capable characters just like the player and we are gonna program them throughout this section right now we're gonna add two features we'll make it so that we can change where an npc is facing and we're also gonna make it so the player and npcs can collide with each other let's work on the first one i'll go into the oak acts apparent object and open the create events here we have the move direction variable which stores the direction that the character is facing in i'll remove it from here and we're gonna initialize it in a different place i'll open the variable definitions window from here this allows you to initialize variables for this objects and the reason why we are using this now is that it allows you to easily change a variable for each instance in the room editor i'll create a new variable and name this move direction just the one we removed from the create event we'll allow ourselves to select a value for this from 4 options 0 90 180 and 270 so i'll open the type menu and change the type for this variable to list this means we can now select one value for this variable from a list of values to set up that list i'll click on this cog icon in this list i'll add four items and set them up to be 0 90 180 and 270. i'll close it now you can now select any of these values for the variable so i'll change the default value to 270 this means that by default all characters will be facing down let's go into the room editor now if you double click on an instance you will see a variables button clicking on this will open the variables window for this instance and you can change the variables here just for this individual instance to edit a variable you need to click on this pencil icon first and then change its value i'll set the direction for this npc to 0 which means it'll face right then i'll do the same for the other npc but change its direction to 180 which means that this will face left if you run the game you will see that the npcs are facing in the directions that we set for them so this is great as you can set where an npc is facing without having to change the sprite yourself just change the direction value and our system handles the rest now let's set up collisions between all characters i'll go into the collision function script in this collision function before the return false line i'll add this collision check here we are using position meaning to check whether there is an instance at the given point for the point we are using the rune coordinates the same ones we used for the o collision check above this new collision check is checking for or character parents so it's checking for all characters whether it's the player an ai or an npc if it finds a collision it returns true this means that objects can now also collide with characters so the player can collide with the npc and the npc can collide with the player when we add movement to it if you run the game you will see that the player can now collide with the npcs so they really feel like part of the world now of course they don't move so in the next lecture we are gonna work on ai path finding which means that the npc will be able to move around and also create a path to go around all the obstacles so let's work on that in the next lecture hi there in this lecture we are gonna work on ai pathfinding this will allow us to make npcs that move around and can find their way around obstacles on their own so for example if i tell this npc to move here it should be able to find a path to reach there for this we are going to use mp grids an mp grid is used for path finding on an mp grid you can set the cells that are occupied by tiles or collision objects then an npc can ask the mp grid hey i want to go there please create a path for me so i can go around the obstacles so the mp grid then creates a path and the npc can then move through it let's go into our project i'll go into all room manager and open the create event here we'll first create an mp grid and set up the cells that are occupied so this will happen when a room starts this way our system will know where the obstacles are in that room so i'll add this here this is the width of the grid in cells not in pixels to calculate that we are simply taking the width of the room and converting that to tile coordinates then we have the grid height calculated in the same way now here we are creating our mp grid in a global variable we are calling this variable ai grid because it's used by our ai objects the mp grid create function will create our mp grid this is the position of the grid in the room and since we wanted to cover the whole room we are creating it at 0 by 0. then we have the width and the height of the grid in cells so we are passing in the values we just calculated after that we have the width and height of each cell in this grid and since the cells in this grid will be the same size as our tiles i'll simply pass in tile size for both now here we are calling mp grid at instances to tell the mp grid where our collision instances are this is the grid that we are using this is the object that we are registering and this controls whether we want to use precise collisions or not we are using rectangular masks for our sprites so we don't need this which is why it's set to false so now as a result of this function dmp grid will now know where our collision instances are such as the trees and they'll be registered as obstacles now we need to tell the grid where our collision tiles are since we got the collision layer style map up here we can just go through each style in that tile map and register any tiles we find in the empty grid for that i'll add this here here we are using a for loop this basically takes us through each value in a given range using a variable in the first loop our variable is called x and it starts at zero it then runs this block of code after running it the loop variable x goes up by 1 because of this statement then it comes to this condition and checks if the x value is smaller than the grid width if it is then the block of code runs again if it's not then the loop stops so this means that the loop will take us through each x value from 0 to grid width minus 1 and run the block of code repeatedly at each iteration the last value is grid width -1 because the loop variable will not be equal to grid width as we are using a smaller than condition here the moment it becomes equal to it this condition will become false and the loop will break now inside the loop we have another loop this one takes us through each y value from zero to grid height minus one so basically using these two loops we are going through each style in the tile map now inside the second loop we are getting the tile at the current x and y position using tile map get we are getting it from the tile map stored in the call tilemap variable then here we have a condition that checks if a tile was found there if it was then we run mp grid add cell which adds an obstacle cell to the empty grid this is our mp grid and this is the tile position where we found the obstacle so essentially this whole block is going through the collision tile map checking where we have a tile and registering that tile as an obstacle in the mp grid let's also open the cleanup events and here destroy the mp grid when it's no longer needed now we can also preview this grid by drawing it in the room for this i'll add the draw and event which runs after the main draw event and we are using this to make sure that the grid is drawn above everything else in the event i'll add this this is simply drawing our ai grid in the room so we can see where we have our obstacles before drawing the grid we are changing the alpha to 0.5 so it's half transparent and after drawing it we are resetting the alpha to 1 as that's the default value if you run the game now you will see the mp grid the red tiles are the obstacles and the green tiles are empty so the mp grid now knows where the collection tiles and the trees are and can use that information to create a path for our npcs before we move on to that i'll remove the draw and event because we don't need to see our mp grid in the game anymore now let's open the ai parent object and program the ai path finding i'll inherit the create event and in the event i'll add this here we are creating a new path for this ai character to use whenever we want the character to move somewhere the path will be created and stored in this variable then we have a path next point variable when you create a path that part has multiple points in it and this variable stores the id of the point that the character is following then we have path point x and path point y these store the coordinates of the points in the part that the character is moving towards now let's create a function to start the movements of the character towards a target position for that i'll add this let me maximize this window so we can see our new function we are creating a function called move two points it takes two arguments these are the target coordinates where we want this character to move these need to be room coordinates because the mp grid requires room coordinates now in the function here we are calling the mp grid path function which tries to find a path to the given target position this is the mp grid that we are using this is the path variable where the path will be stored this is the starting position so it's the current position of the character and this is the target position where we want it to move so that's taken from the arguments the last argument tells whether the path should allow diagonal movements our characters can't move diagonally they can only move in one direction at a time so we are going to set this to false so the path doesn't include any diagonal movements now if the mp grid was able to create a path then this function will return true which will be stored in this variable if it can't find the path to the target position for example if it's completely blocked then in that case it'll return false if it return true then here we are running a block of code this sets the path next point variable to 1 so the character can start moving towards the next point in the path point 0 would be the current position of the character which is why we want it to move towards point one then here we are resetting the values of the path point variables to zero so any previous values are removed now because we have created a path here we need to destroy it when it's no longer needed so i'll add the cleanup events and in this events i'll add this this will simply delete the path when the instance is destroyed let's now set up how the character will move through the path point by points we'll handle this in the begin step event so i'll inherit it in the event i'll add this here we are checking if the path next point variable is greater than zero meaning that we are moving towards a point in the path so here we are getting the x and y coordinates of that point from the path so this is the path that we are reading and this is the point number that we want to get these functions will return the x and y coordinates of that point on the path which will be stored in the path point x and path point y variables now here we are getting the difference between the path point x and the x of the instance we are then passing that into the sine function so we get either one or minus one based on that difference that value is then applied to the input x variable so that the character moves in that direction on the x-axis then we are doing the same on the y-axis now here we have an else block and this runs if we are not following a path in that case it sets the input variables to 0 so the character stops moving now if you remember in the player's begin step event we were calculating input based on the keyboard input now in the ai character we are calculating input based on the path that is following so we are calculating the inputs in different ways for different characters but they all use the same step event code from the character parent for moving this is a really efficient object oriented system finally we want to handle what happens once the npc reaches the point where it's moving for that i'll go ahead and add the end step events we are using this to make sure that the character has moved back in the step events so i'll add this here here we are checking if the character is moving towards a point then we are checking if the current x and y of the character are equal to the x and y of the point where it's moving this means that the character has reached that position in that case we wanted to move to the next point in the path so here we are increasing the value of the path next point variable of course the path isn't infinite it's going to end so here we are checking if the path has ended this gets the total number of points in the path and then we are checking if the next point value is equal to or greater than that value if it is it means that the npc has completed the path and in that case we are resetting the path next point variable to 0. this means that the npc is not following a path anymore the ai parent now has path finding but it doesn't have anything moving it we'll implement that in the next lecture but for now let's make it so we can move it with the mouse and just so we can test the path finding feature in this object i'll add in new events go on to mouse then global and add the global left pressed events this event runs when you click the left mouse button anywhere in the room and we'll use this to set the target position of the character and tell it to move there for that i'll add this here this is only some temporary code we are taking the x and y coordinates of the mouse and converting them to tile coordinates we adding 0.5 to them so we get the center of those tiles and then converting them back to room coordinates we are doing this so that no matter where the mouse is in the tile it always points to the center of that tile these new coordinates are then stored in these local variables after that we are calling our move to point function and passing in these coordinates so the ai moves there before we test this let's make it so the path is also drawn i'll add the draw event and here add this first of all this draws the instance itself so the character is visible then it draws the path that the character is following these are the x and y coordinates where it will be drawn and this tells whether the path should be drawn in the room or if it should be drawn relative to the instance we want it to draw in the room so i'll set this to 1 which means true now in the room i'll remove one and pc so we only have one npc to move i run the game now if i click anywhere in the room you will see that the npc moves there you can also see the path that it's following it successfully finds its way through any obstacles and reaches the target position that we set this means our ai path finding is working perfectly let's go back into the ai parent object and remove both the draw and the global left breast events as these were only for testing we'll now make it so that the ai character can randomly decide to move to a random tile so that they can move on their own will implement this in the next lecture hi there in this lecture we are going to implement a movement loop for our ai this means our npcs will be able to move around randomly on their own we'll define a range for an npc to move in so it'll only move within that rectangular area it'll have a timer so every few seconds it'll select a new tile to move to and it'll go there let's go into our project now and open the oei parent object i'll open the create event and here i'll add this here we are setting alarm 0 to 1 alarms are events so this means that the alarm 0 event will run after one frame that event will handle the random movement of the character now before we program that event let's add some variables in the variable definitions window again we are initializing variables here so that they can easily be changed for any npc instance i'll add a variable and name this moves i'll set the type to boolean and the default value to true this shows whether the character should move or not so if you want a character that only stays in one place and doesn't move you can set this to false for that character instance now i'll create a variable called min move time i'll change the type to integer and the value to 150 i'll also create a variable called max move time make this an integer and set its value to 250. now these are the minimum and maximum interval values between the npc's movement if we were using a fixed value like 200 the npc would move to a new tile every 200 frames but we don't want it to be fixed to make it more realistic we'll make it random and so our npc's interval value will always be random between 150 and 250 frames now i'll create another variable name it move range and change the type to integer this is how far the character can move from its starting position in pixels we want to create a slider for this so it's easier to change so i'll click on this clock icon and here enable use range i'll set the minimum to 16 and the maximum to 128 back in the variables window you'll now see a slider for this value which makes it easier to modify for each instance and also sets a minimum and maximum limit i'll set the default move range to 64 pixels let's close this window now and set up the movement loop we'll do that in the alarm zero event so i'll add that event this event will first run one frame after the create event as we told it too and after that we can tell it to run again and again so it keeps running and keeps moving the character to new trials let's now add this in the event first of all we have a condition that checks whether the character can move or not if it can then we are calculating the target x and by where it needs to move we are doing this by using the i random range function which returns a random integer between a minimum and a maximum value the minimum value here is the move range subtracted from the x start value the x dot is the x position where the instance was created so this is 64 pixels to the left of that starting position then the maximum is x start plus move range so that's 64 pixels to the right of the starting position a random value will be returned between these two values and applied to target x after that we are doing the same thing but on the y axis using the y start position then here we are converting the target position to tile coordinates we are adding 0.5 to them so we get the center of the tile after that we are calling our move to point function we are passing in our target coordinates but also converting them to room coordinates before passing them in this is because the function needs room coordinates but then why didn't we just pass these coordinates directly into the function since these are room coordinates the problem is that these coordinates can be anywhere in its aisle but we need it to be in the center of the tile that's why we first converted it into tile coordinates and then converted those back into room coordinates now after running this function here we are resetting alarm 0 we again using the i random range function so it will select a random value between the main move time and the max move time values and apply that to alarm zero this means that the alarm will run again after a few seconds and then again and again so this will result in a continuous loop i'll go into the room now and here add another npc i'll open its variables and make it so that this one doesn't move i'll run the game now you can see that the npc on the left is moving on its own going to a random tile then stopping then going to another tile and so on this makes our world feel alive the npc we have on the right is not moving because we disabled its moves variable so this can be a seller or someone who's waiting for someone else and doesn't need to work in the next lecture we are going to add a new npc to our game and after that we are going to work on a dialog system so i'll see you in the next one hi there in this quick lecture we are going to add a new npc to our game in this price group i've imported sprites for an npc called jess we have all the 8 sprites 4 for each date let's create the object now for this i'll simply duplicate the npc bob object and name this onpc jazz in the object i'll assign the correct sprite to it and now i'll open the create event here we have the sprites for the states and currently they are the bob sprites so we'll replace these with the jet sprites luckily we don't have to do that manually we can just use the search and replace feature so i'll press ctrl f and in the panel that opens here enter my search value which is bob then i'll click here to open the replace field and here you need to enter the new value that will replace the search value so i'll enter yes then i'll click here to replace all the occurrences of bob with jess and now in the code you can see that we are now using the jazz sprites instead of the bob sprites now if you don't see any of these sprites in a red color it means that the correct sprite is not being referenced so you need to check its name in the asset browser and then android here manually you can now go in the room editor and place the new npc make sure to put it in the center of the tile this has all the npc properties such as whether it moves its movement range and the other variables if you run the game the new npc will be there alive and moving so this is how easy it is to create a new npc using our system our npcs feel alive now but not completely they also need to be able to talk with the player so we'll work on a dialog system in the next section hey there in this section we'll be working on our dialog system that makes use of sequences for its text box design and layout in this lecture we'll be creating our text box in a sequence and animating it so let's get started let's jump into our project and under sprites in the text box group i've already imported the sprites that we are going to use throughout this section so let's go through them one by one first we have as next arrow that shows up on the text box when we need to move to the next message then we have s message that shows up on an npc when we can interact with it then we have s text box back which is a texture that appears inside the text box as text box frame is the text boxes frame that appears around it as text box mask is the mask that ensures that the texture that i showed earlier only appears inside the textbox frame and then as textbox name box is a small box that will show the name of the character that is talking the origins for all of the sprites that i showed need to be set to middle center finally we have s box which will be used for objects that we place in the sequence to tell the system where the name should appear where the message should appear how large that area should be and where the character's image would appear so we only see this box sprite in the sequence editor to lay out our text box and it won't be visible in the game make sure that the origin for this bride is set to top left now let's go ahead and start creating our text block sequence in the asset browser i'll create a new group and name this sequences so this will contain all of our sequence assets i'll create a new sequence asset in this group and name this seq text box where of course seq stands for sequence this will now open the sequence editor where you can place any sprites objects and sounds and simply animate them at the bottom you see the details of all of the tracks that you've added where each asset is its own track and up here in the canvas is where you see what's happening in the current frame where everything is placed and this is where you can also preview your final animation now inside the canvas here we have a rectangular frame that doesn't do anything but it simply helps us make sure that we are placing things in the correct place so we are going to change the size of this frame by going into the canvas frame settings up here i'll change the width and the height to 320 by 180 which is the resolution of my game so the frame has now been resized and we're also going to change the origin which is by default in the center of the sequence we want it to be in the top left corner so in the canvas settings i'll set the origin x to negative 160 which is simply half of the total width of the sequence and the origin y to negative 90 which is half of the sequence's height so now the origin is in the top left corner which will make it easier to place the sequence in the game now with the sequence setup we'll start creating our text box so i'll open the sprites group in the asset browser select the s text box frame sprite and drag it into the sequence editor onto the track panel we now see it in the canvas up here and also down here in the dope sheet it only lasts for a couple frames so if you move the playhead around you'll see that it's not visible on the other frames we want it to be visible throughout the whole sequence so you can either manually resize the asset key so it lasts longer or you can simply right click on it and select stretch asset key so it's automatically stretched throughout the whole sequence you can also hit play to preview your animation but of course right now there's nothing moving around before we do any of that we're going to set up the layout of our text box so make sure that your playhead remains on the first frame because this is where we're going to move and scale everything then go into the canvas and start scaling and moving the textbox frame once you've got it where you want it you can start placing the other elements so from the asset browser i'll take the s text box in the inbox sprite and drag it into the track panel we now have another track and asset key for this which again only lasts for a couple frames so we are going to right click on this as well and stretch the asset key now again making sure that your playhead is on the first frame you can go into the canvas and start moving and scaling your name box to place it where you want it now we've got the basic layouts of the text box setup so we're going to add the back texture to the text box from the asset browser i'll drag the as textbox backsprite into the sequence editor and you can see that it's a very large sprite that's covering our whole sequence we only want it to appear inside the text box and we're going to do that by using a clipping mask a clipping mask has a mask and a subject where the mask controls where the subject appears so the subject essentially only appears where the mask has pixels so to add that let's go into the track panel and click on this button to add a clipping mask this will add a new track into the track panel and when you open it up you'll see that it has two folders one for the mask and one for the subject so by placing tracks into these folders we can essentially set up our clipping mask let's select the s text box backtrack and drag it into the subject folder under the clipping mask and you'll see in the canvas that the back texture disappears because currently we don't have a mask so from the asset browser let's take the s text box mask price and drag it into the sequence editor under the mask folder for the clipping mask and in the canvas you will now see that the back texture appears it only appears where the mask itself has visible pixels so let's adjust this now in the track panel select the mask track and then in the canvas move it and scale it so it only appears inside the text box you can also move it more precisely by using the arrow keys on your keyboard so we've got the mask set up properly and the back texture only appears inside the text box but the asset keys for the clipping mask tracks are still very small so i'm going gonna right click on them and stretch them one by one so right now our whole sequence should have the same things visible on all frames now the text box sequence is essentially complete but we are now going to animate the text box throughout the rest of this video if you don't want to do that and want to skip to implementing dialogues with npcs you can skip to the next lecture and it will work fine or you can continue watching this one if you want to animate the text box so first of all we're going to animate the back texture to give it an infinite scrolling animation in the track panel i'll expand the back textures track and here we can see its position parameter which we can use to animate its position inside a parameter track you can have multiple keyframes which would be used for animation currently we can see that on the first frame we already have a keyframe so i'm going to take the playhead all the way to the last frame and then come back to the track panel click here to create a keyframe on this frame so we now have two keyframes for the position parameter track if we now change the position of the sprites on any of these keyframes it will create an animation between these two keyframes so i'll move my playhead to the end of the animation where i have my second keyframe and in the canvas i'll select the back texture track you can hover over something for a second and it will show this menu where you can select the track that you want to move so i'll just move it down and to the right a bit to create a scrolling animation and once you've done that you can move your playhead between those two keyframes and you'll see that the back texture is moving you can also hit play to see your animation in action but it only plays once so you can click here to change the playback mode and turn on looping so if you play it now you'll see that the animation simply restarts after it ends now you can see a bit of a jump there the animation isn't really seamless so now you can just take your playhead to the last frame and just make adjustments to the position until the scrolling looks seamless and infinite so now i've got the two keyframes set up perfectly so that when the animation ends the dots are in the same place as they were when the animation started and so the loop looks seamless and infinite so animation for the back texture is now done and now we're going to animate the name box and the message box so they move up and down throughout the animation we'll first apply that animation to the name box so i'll expand that track and select the position track in this parameter track we already have a keyframe on the first frame so i'm going to take the playhead to the middle of the sequence animation and then click here to create a keyframe here then i'll create another keyframe at the end of the animation on the last frame so now we have these three keyframes for doing our animation i'll take the playhead to the middle of the animation where i have my second keyframe select the name box track and in the canvas move it down a bit so if you play the animation now you'll see that the name box is bobbing up and down we'll now apply a similar animation to the message box but currently we can't easily do that because the message box is made up of two separate tracks which is this frame track and the clipping mask track so we need to group them together and then animate that group so in the track panel i'll click here to create a new group and name this message box then i'll select the frame track and the clipping mask track and then drag them into the message box group so we now have them both in this one group and we can simply animate the group to animate both of those tracks together now in my case the name box is appearing behind the message box so to fix this in the track panel i can simply drag the name box track above the message box so it also appears above it so let's animate the message box now i click on this plus button to add a new parameter track and click on position because we want to animate the position of this group let's create a keyframe on the first frame then in the middle of the sequence and then at the very end now i'll take my play head to the middle of the sequence select this keyframe and then select the message box track so we can move it in the canvas we want to use the gizmos to move the track so up here make sure that the translate gizmo is selected which is used to move a track and then use the red arrow to move it up a bit now our message box also has an animation of moving up and down now the final thing we are going to do in this lecture is to use animation curves for animating the message box currently you can see we have three keyframes in the position track for the message box and it's animated between these three keyframes so the animation is pretty linear and kind of robotic because it doesn't use smooth curves to animate it so we're going to implement curves into this i'll select the position track for the message box and then click here to enable curve mode where you can preview and manage your curves currently this track doesn't have a curve assigned to it it uses basic keyframes so we can click on convert to curve here to convert it from a keyframe track into a curve we see its curve here but we don't want to make any changes to it because our animation is ok as it is we only want to make it smoother so i am going to click here to open the curve library you can see here that this curve is currently set to linear i'll change that to use base a and now the curve looks much smoother if you play the animation it will also look a lot nicer but you can make it even nicer by adjusting the handles on each point in a curve so you can move these handles around to make the curve more rounded and this in turn will make the animation more bouncier if you happen to modify the wrong curve like i just did there you can hit ctrl z to undo that and then make that other curve invisible so you only modify the curve that is being animated which in my case is the y-curve so after this little modification the animation is much juicier and you can now go ahead and apply curves in a similar manner to the name box track as well now personally i do think that this animation is a bit too fast so we can easily modify that by lowering the fps value here so at 20 fps it's a bit slow but it's much better because otherwise the textbox would be too distracting for the player to read any text on it our text box is now visually complete and in the next lecture we'll be working on displaying this sequence inside our game so i'll see you there hi there in this lecture we are going to draw our text block sequence inside the game and make it appear on top of everything we'll also make it so that all the characters stop whenever the text box is visible so let's jump into our project and start by creating a new object that'll manage everything about the text box when it's visible on screen so under objects i'll create a new group and i'll name this gui and under this group i'll create an object and this will be all text box now we'll come back to this object later we first need to set up a script with some new functions so i'll go into the scripts group and here create a new script and i'll name this text box functions as this will contain all the functions we need for our text box so let's remove the default function that gamemaker has created for us and instead add this this is a global variable that will store the id of the text block sequence when it's visible in the game this will simply be used to destroy the sequence when we close the text box then we have two functions one to create the text box let's say when the player starts talking with an npc and the other to close the text box when a conversation is over let's look inside the create text box function it's first of all creating a new instance of the old text box object in a layer called text box and then storing the id of that instance in a local variable then this part is simply creating the text box sequence in the game now since sequences are created inside the room we need to create it at the camera's position to ensure that the player actually sees it so here we are simply getting the x and y position of the camera and here creating the sequence at that position the sequence is also created in the text box layer which doesn't exist yet but we'll create it later in this lecture then after the sequence is created we are storing its id in this global variable so the create text box function is simply creating the text box manager which handles the code and the text box sequence which displays the text box the closed text box function is then doing the opposite where it destroys the sequence and the text box manager so with these easy to use functions we can very simply start using the text box from anywhere and we don't have to worry about its specifics we simply have to call one function to create a text box and one function to close it we'll now test these functions by calling them in the player object so here i'll go into the events window and create a new event i'll go under key press and add the space event so this will run whenever the space key is hit and inside this event i'll add this this code is simple if the text box already exists then it will be closed otherwise it will be created i'm only doing this to test the text box system and will later remove this code let's now create the layer where the text box will be visible and for this we'll go into the old room energy object instead of creating the layer manually in each room we'll just ensure that this object creates it automatically whenever a room starts so here i'll add a new event go under other and select room start which runs whenever a new room starts in this event i'm going to call the layer create function to create a new layer this layer will have a -10 000 depth and its name will be text box the depth is set to a really low number so it appears above every other instance so now let's run the game i'll hit space and the text box appears on the screen if i hit space again it disappears so our textbox functions are working at least but the problem is that the characters don't stop and even the player can move anywhere they want so we simply need to stop the movement of all characters including the player and all npcs whenever the text box is variable for this we first need a variable which will create in the create events of the oral manager object so in this events i'll add a new global variable and this will be called pause by default this will be false we'll set this to true when we want to pause all characters which will happen when the text box appears so to make that happen let's go into the text box function script and edit the create text box function after the line where we create the sequence i'll simply add a statement to set the global paused variable to true this will pause the game when the text box is created and then inside the closed textbox function i'll add a statement to set the global post variable to false so that the game resumes when the text box is closed so we've now got the post variable turning on and off and now we'll control what actually happens when this variable is true we simply want all the characters to stop moving so for that i'll go into the oak hacks apparent object this object if you remember is the parents of the player and all the npcs let's open the step events where we have all the movement logic for the character and at the very top of the event let's add this this block runs when the global pause variable is true which means the text box is active and at the end of this block we are exiting the event so when the game is paused the step event of the character will not run and it will not move at all now while this is happening we want the character to display its idle animation so here we are changing its state to the idle state then we are calling the get sprite function to get the correct sprite for the character based on its state and direction and then applying that sprite to the sprite index variable of the instance let's run the game now and when i press space to create the text box you'll see that all the npcs stop they display their idle animations and the player also cannot move then when i close the text box the npcs start moving again and the player can also move now displaying our text box is working perfectly we now need to display some text on it which we'll do in the next lecture hi there in this lecture we'll work on displaying text on our text box usually when creating text boxes you have to enter numeric values manually into your code to position the message the image and the name which makes it a bit harder to make changes and to visualize your text box layouts thanks to sequences though it's becoming much easier and better we'll be placing simple boxes inside the sequence to tell the text box where it should draw the name the message and the image so you can very easily move them around and see exactly where everything will appear making changes in a system like this is also way easier let's jump into our project and start by creating new objects for those boxes that we'll be placing in the sequence so in the gui group i'll create an object and this will be all box parents as there will be different kinds of boxes this will be the parent object for all those different box objects now let's create another object this will be or box name which is where the name of the speaker will appear in the object let's set its sprite to the s-box sprite that we imported earlier and in the asset browser let's duplicate this to create a box message where the message itself will appear and then duplicate that to create all box image where the image of the speaker will appear let's now go into the obox parent object and open its parent menu we want to assign the other box objects as children of this object so in the asset browser i select those three objects by holding shift and clicking then drag them and drop them into the children section of this object so now any events we add to this object will automatically be applied to the other box objects as well now we're gonna go into the text box sequence and start placing these boxes first in the dope sheet make sure that your playhead is on the first frame then in the asset browser select the obox name object drag it and drop it into the track panel inside the name box track we've now got it as a child of the name box image and in the dop sheet i'm gonna stretch its asset key now keeping your playhead on the first frame you can go into the canvas and move the name box where it needs to be you can also resize it to make it fit perfectly the name box is now ready and if you go through the animation you'll see that it moves with the actual name box because it's a child of the name box track that we have already animated now make sure your playhead is on the first frame and we'll now place the messagebox object which could be a child of this frame track so from the asset browser take the old box message object and drop it into the frame track so it's now a child of that track and will be animated along with it let's stretch the asset key for this as well then go into the canvas and place it where we want it so now this means that the text will start here and it will not go past this point finally let's place the image box we'll take the or box image object drag it and drop it into the frame track the same place where we dropped the message box now for this track i'll also stretch the asset key then go into the canvas and place the image box to the left of the message box i'll scale it so it has the same height as the message box and now the layout of our text box is completely ready if you play the animation you will see that the boxes are also being animated so any text you have on the text box will also move with the boxes now the thing is we don't want the player to see these boxes they are just for us so we are going to make them invisible in the game now usually to make an object invisible you just disable the visible option here but because the boxes are being used in a sequence in this case their visibility depends on the visibility of their tracks in the sequence so we need a way to make these objects invisible in the game without having to make them invisible in the sequence editor so to do that i'm going to add the draw event in this object and then leave it empty when you add the draw event you have to draw the object yourself by calling draw self but if you don't do that then the object will not appear at all so this way the boxes will not be visible in the game now we want to write the code to display the text on the text box but before doing that we gonna create a new font so in the asset browser i'm gonna create a new group for fonts and in this group i'll create a new font asset i'll name this ft text box then in the font editor that opens you can select any font you want so i'm going to select the bitmap font if you want to use the same font you can google this name and download the font file then here i'll set the font size to 12 and because this is a pixel art game we gonna disable and try elsing now to write code for drawing the text we're to go into the old text box object that we created earlier in this object i'm going to add the draw end event this event runs after the regular draw event so that ensures that anything you draw here is drawn above your game because by this point your game is already drawn first of all let's make this code window full screen as we're gonna add a lot of code and now let's add this first of all this function checks if the name box instance exists if that box exists it means that the other boxes also exist because they are created together in the sequence so if the box does not exist this will exit the event so nothing is drawn we are doing this because the sequence only creates its instances after one frame of being created which is why we need to make sure that the instances have been created otherwise we gonna get an error in that one frame when the instances have not been created then here we are changing our phone to the new font that we just created then we are creating some placeholder variables which will appear on the text box so we've got a name a message and an image for the speaker the actual dialogue data will be set up in the next lecture so for now we are using these temporary values let's add some more code now here we are drawing some text the text that we are drawing is simply the name and the position where we are drawing it is the position of the name box so the name text simply draws wherever the name box is then similarly we are drawing the message here at the position of the or box message instance however for this we are using the special draw text ext function this function is used to ensure that whenever the text is longer than a certain width it wraps over to the next line so we need a width value to pass into this function and we have that right here for this width variable we are simply taking the sprite width from the message box so the maximum width for our text will be the same as the width of the message box instance now for the draw text ext function we are passing in two extra arguments the first one is the separation which is basically the distance between each line and here -1 means that it will use the default value for that font so we don't have to specify a custom line height but we can do that if we want then the second value here is the maximum width for the text so we are passing in the local variable that we just created now what's remaining is to draw the image of the speaker so for that let's add this now this looks like a lot of code and we are doing all of this to ensure that a the image is drawn in the center of the image box and b that it scales up or down to fit the size of that image box now we are first of all getting the center coordinates of the box image by dividing the width and height of the box image by 2 and adding them to the x and y of the box image we are getting the center coordinates because in this example the sprites that we are using for the speakers use a middle sensor origin so they need to be drawn in the center position of the box then after that we are calculating the scale that the image will be drawn at so it fits the box to calculate that we are getting the width and the height of the image box and then dividing those values by the width and the height of the original image this will give us the x and y scale that we need to draw the image at so it perfectly fits the box that we placed in the sequence now that we have all of these different details we'll call the drawsprite ext function to draw our image this function is used to draw a sprite with custom scale values and other options like rotation blend color and alpha so looking at the arguments we are drawing the speaker's image we are drawing its first frame we are drawing it at the center x and y of the image box we are using our custom scale values and for the rest of the properties which are rotation color and alpha we are passing in the default values so there is no change there so all of this should now fill our text box and we can run the game to see how it looks in the game i'll press space the text box appears and here we can see the name of the speaker their image and the message itself you can also see how the message is being drawn on multiple lines and this is because of the draw text exp function now of course to make any changes to this you can very easily go into the sequence and move the boxes scale them up or down depending on how you want it to look now currently we are using placeholder values for the name image and message so in the next lecture we'll focus on setting up all of our speakers and dialogues so we can start writing up those actual interactions and build up sort of a story for our game so i'll see you in the next one hi there in this lecture we'll set up the dialogue data for our game and make it so the player can interact with npcs we'll start with the dialogue data one dialog on its own is simply a list of messages that are shown to the player each message will have a speaker attached to it so the player can know who is talking in our code each dialog will be an array and that array will store each message as a struct so our final dialog structure will look something like this this is simply an array that contains trucks for messages each truck contains a speaker reference so that's the speaker of this message and then the message itself you then have more messages after that in the array and this whole array is essentially one dialog instance let's jump into our project now for the dialog data i'll create a new script and name this dialog data i'll make the script full screen remove the default function and in its place add this first of all here we are creating a local variable called speakers which holds a struct this truck holds all the possible speakers that our game can have each speaker in this truck is its own struct containing a name and an image for that speaker currently we have two speakers the player and bob we are making the speaker struct a local variable here because we will not be referencing this variable directly outside of the script will only be able to get a speaker through a message so let's create our dialog messages now by adding this here we are creating a global variable called dialog which holds an empty struct this struct will contain all of the dialogues that we'll use throughout the game we are initializing our first dialog here as a variable inside the global dialog struct it's called bob underscore meet because it plays when the player meets bob this variable is an array which stores all the messages for that dialog each message is its own struct containing the speaker and the message you can see that for the speaker we are simply referencing data from the speaker struct above like we've got underscore speakers dot player here this way we are not writing the speaker's name and image over and over again we only have that once up here and then we just reference that same struct whenever the player speaks after this message we have a message from bob then the player again and so on and we have now set up our first conversation let's now set up how the player can interact with an npc to show some dialogue i'll open the onpc parent object and then open its variables window we'll create a variable to tell the npc which dialogue it plays so i'll add a variable and name this default dialog this variable stores the default dialog array for this npc which is basically what it says whenever you talk to it its type will be expression because we need to reference a structs here and for the default value i'll enter global.dialog dot bob underscore meets so this is the dialog that an npc will play by default we are now going to make it so that an npc shows a message icon above it when the player can interact with it so for that first of all let's go ahead and inherit the create event in this object here we'll create a variable called show message icon which will be false by default when this is true the npc will show the s message sprite on top of it to draw that sprite let's go ahead and add the draw and event we are using draw end so the icon draws above everything else now in this event let's add this this checks if the show message icon variable is true if it is we call draw sprite to draw a sprite the sprite is s message we are drawing its first frame and we are simply drawing it at the position of the npc instance then we are setting show message icon to false this means that you need to set this variable to true for every frame that it needs to be visible but the plus point here is that you don't have to worry about setting it back to false now we need to allow the player to walk up to an npc and then display this message icon so the player knows that they can now talk to this npc so first let's go into the all player objects and in the events window i'm gonna delete the key press space event because i only added this to test the text box now for the npc interaction logic i'm gonna add the end step event we are using end step for this because the player and the npcs will already have moved in the regular step events so they are now in their final positions for this frame now in this events we want to do two things first we'll calculate the position of the cell that the player is facing towards that will depend on the direction of the player but it'll always be in front of it also keep in mind that we'll be calculating this position as room coordinates not tile coordinates second we want to check whether an npc is in that position if an npc is found we'll enable its show message icon variable let's now add the code we need to accomplish these goals in this line we are setting up two local variables the first one is how far we want to look and since we only want to look one tile ahead this will be equal to the tile size then this is the direction we want to lock in so that's simply the move direction of the player then here we are calculating the x position of the cell that the player is looking at we first pass in our length and direction variables into the lengthier x function which gives us an x value based on the length and direction that we specified when we add that to the player's x position we get the final x position in this direction being this much far away then we are doing the same but on y both of these variables will now allow us to point exactly at the center of the tile that the player is looking at now we want to check for an npc at that position so i'll add this here we are calling the instance position function which basically tries to find an instance at a given point and if an instance is found it returns its instance id so this is the point that we are checking as which is basically the central points of the trial that the player is looking at and we are trying to find an instance of an npc if an npc is found this variable will contain its instance id but if it's not found this will simply contain no one so here in this condition we are checking whether an instance was found by checking if the variable is not equal to no one so if an npc was found we are setting its show message icon variable to true so that it shows the message icon on top of it this veda player will know that they can interact with this npc let's now run the game and walk up to an npc when i do so you'll see that the message icon appears and at other times it doesn't appear so we now have our dialogue data set up and also a way to interact with npcs so we simply need to show the npc's dialog when the player presses a key but we also have a lot more work to do on the textbox side so that it displays each dialog message using a typewriter effect where it appears letter by letter so we are going to work on that in the next lecture hi there this lecture is the culmination of all the work we have put into our project over this section and we'll finally get the text blocks working for all dialogues using a typewriter effect where letters appear one by one let's jump into our project now most of the code that we'll be adding in this lecture will be in the o text box object which manages the text box while it's visible this object will need three events a create event a step event and the draw and events that we already have i'll make this window full screen so we can see the code more easily and let's start by adding some code in the create event we are simply creating some variables here text speed is how many characters appear every frame so it's currently set to half a character per frame or one character every two frames start it tells whether the text box has started yet or not when it falls which it is by default no text will be displayed dialog stores a reference to the dialog array that this text box will go through by default it's set to -1 so there's no array here currently message index is the message number that is currently being displayed and it starts at 0. so from 0 it goes to 1 then 2 then 3 until there are no more messages in the dialog array characters tells how many characters are currently visible for the current message now we'll create some methods or functions that we'll call later on so i'll add this first we have a start method which will be called when the text box is created it takes the dialog array as an argument and it then applies that to the dialog variable so the text box now has a dialog data it needs it then sets started to true so it can start displaying text then the next message method is used to move the text box to the next message in the dialog array it simply increases the message index variable by 1 so it shows the next message in the dialog array and also resets characters to zero so the message starts from the beginning so that's all of our variables and methods done we'll now program the typewriter feature in the step event here i'll add this first of all at the top of the event we are checking if the text box has not started yet in that case we'll exit the event so the rest of the code doesn't run this stops the text box from doing anything until it has been started now here we are getting the data for the current message from the dialog array it's using the message index variable to pull a message from the array so what we get in this variable is the message struct that contains the speaker and the message string itself so in this variable we are getting the message string from that struct now here we have a condition that checks if the current character count is smaller than the length of the complete message this simply means that the message is not complete yet so in that case we run this statement it simply adds the text speed value to the character's variable this way as the game goes on more and more characters will become visible now when all of the characters in the message have been shown and the characters become equal to or greater than the string length of the message this condition will become false and the s block will run instead here it checks if the player has pressed the space key which is used to continue to the next message when the player presses that we check if there is another message in the array after the current one to know that we check if message index plus 1 which would be the next message index is smaller than the length of the dialog array this means that that particular index is inside the range of the array and not outside of it meaning there is another message for the text box to show so in that case it runs the next message method which simply increases the index by one and resets the cracked account so the next message can be shown but in case there isn't another message and this was the last one it caused the close text box function which would of course close the text box so this event now handles showing each message with a typewriter effect and allowing the player to move to the next message by pressing space let's now open the draw and event and here ensure that the correct values are drawn but before doing that i'll add a new condition here using or and this will simply check if started is false so if the text box has not been started yet this will exit the event now under values or remove these three placeholder variables and instead add this first of all here we are getting the current message struct from the dialogue array then from that struct we are getting the speaker's name and then the message string itself and finally the speaker's image if you're unsure how this works this first line is giving us the message struct that contains the speaker reference and the message string so in these parts we are accessing the speaker structs to get the name and the image and here getting the message string itself now the message that we get here is the complete message but we need to show it letter by letter using the characters variable which simply shows how many characters should be visible so we are handling that in this line we are calling string copy to copy a specific part of the message string and then saving that back into the message variable this function takes the string itself then the starting position in the string to start copying from and finally the number of characters to copy so let's say characters is currently equal to 4. in that case this function will simply copy the first 4 characters from the message string and apply it back to the message variable this way when the text is drawn down here it only displays a limited amount of characters based on the characters variable so this is how our string will be drawn letter by letter we don't need to make any more changes to this event because we are using the same variable names as before so our existing code will continue to draw the name the message and the image we've now finished coding our text box manager but we need to make sure that this start method is called when the text box is created so we'll do that in the text box function script inside this create text box function first we'll add an argument to this function so it now requires a dialog array to be passed in that's simply the dialog array that we want to display then after this line where the o text box instance is created we'll call the start method on it we'll pass in the dialog array that we got from the arguments into the arguments for this method so what we need to do now is to call the create textbox function with a dialog array we'll do that in the player object when it interacts with an npc so in the end step event we'll go to this part where it finds an npc and enables its show message icon variable inside the same block after setting that variable to true i'll add this this checks if the player has pressed space so you can press that to talk with an npc and then calls the create text box function and passes in the default dialog variable from the npc that contains a reference of the dialog array that the npc should display to this condition up here i'll add another condition and this will check if the text box instance doesn't already exist before trying to create it so when the text box doesn't exist you can press space to create it but when it already does exist of course you can't create it let's go ahead and run the game i'll go to this npc and hit space and our dialog has now started you'll see each message appearing line by line and you can press space to move to the next message once a message is over now there is a bug when a dialogue is over and you press space to close it it immediately starts again this happens because we use the space key to start and close a dialog and so on the frame that we close a dialog it reads the space key inputs and starts the same dialogue again because we are still facing the same npc so the solution here is that when we press space to close the text box we reset the input for the space key so it can't read it again until you release space and press it again so to fix this i'll go into the text box function script and here inside the close text box function i'll add this this will tell game maker to clear the input for the space key so if it's held already game maker will not see it as being held and you will have to release the key and press it again for game maker to detect it again this means that when you press space to close a dialog it won't immediately start the dialog again it'll only do it if you actually release the space key and then press it again if you run the game that's exactly what you'll get when you close a dialog it successfully closes and you can then press space again to start it again our text box is now essentially complete and in the next lecture we'll be working on some minor improvements such as making sure that an npc faces the player while talking showing a next arrow on finishing a message and more so i'll see you in the next one hi there in this lecture we are making some final improvements to our dialogue system first of all we'll make it so that an npc faces the player when they start talking then we'll make the text more exciting by slowing it down on dots and commas we'll also display an animated arrow when the correct message is done displaying and finally we'll add more dialogues for more npcs so let's get started to make an npc face the player when they start talking let's go into all player and open the end step event and go to this part where we create the text box when we interact with an npc now within the same block after the create text box statement i'll add this this is changing the move direction variable of the npc so this affects the direction that the npc is facing in it is set to the direction that we get from the npc's position to the player's position now in the game if you start talking to an npc that's facing somewhere else they'll immediately turn to face the player now currently our text box is a bit boring because all of the text appears exactly at the same speed we'll make it so that the speed at which the text appears will be slower when there's a dot a full stop or a comma and the speed will be normal when anything else like a letter is being drawn this way our textbox will have a bit more personality and achieving this is also very simple go to the o text box object and open the step event where the text box behavior is handled we're gonna add some code inside this block where we increase the characters variable we'll add our code before this line i'll create a local variable for storing the modified text speed for this frame the variable starts with an underscore like all of our other local variables and in this statement down here i'll add the underscore so we're actually using the new local variable instead of our instance variable now between these two lines i'll add some code to actually modify this text speed the string charade function gives you only one character out of a string and we are using it to get the last character that the player can see using the characters variable so we get that character and store it in a local variable then down here in a condition we are checking if that character is a dot an exclamation sign a comma or a question mark these are things that usually end a sentence and this is where we temporarily want to slow down the message so when we find a character like that we simply divide the text speed by 6. keep in mind here we are only modifying the local text speed not the instance variable and that means that the actual text speed that we have created in the create event is never modified this only happens per frame so now run the game and talk to an npc you see that messages play out a bit better now because they slow down whenever they encounter a comma a full stop an exclamation sign or a question mark now when a message ends we should tell the player that the message has ended and they can continue to the next one by drawing an arrow at the bottom of the text box so inside the gui group under objects i'll create a new object for that arrow and name this or next message i'll find and assign the s next arrow sprite to it let's now go into the text box sequence so we can place the arrow at the correct position i'll zoom in a bit and make sure that the playhead is at the first frame and from the asset browser i'll drag and place the o next message object into the sequence canvas you can move it and place it wherever you like it we also need to stretch the asset key so it lasts for the whole sequence now i want to animate the arrow getting bigger and smaller so i'll add a scale parameter track to it i'll add a keyframe at the first frame and then a keyframe at the tenth frame i want the scale to change on this keyframe so i'll first click here to link the x and y scale values and then change the x scale to 75 which will automatically change the y scale to 75 as well in the canvas you will now see the arrow getting smaller now to create our final animation we'll simply duplicate these two keyframes throughout the whole sequence so the arrow simply keeps animating between 100 scale and 75 scale so hold ctrl or command and click on these two keyframes to select them together and then hit ctrl c or command c to copy them now take your playhead to frame 20 and hit ctrl v or command v to paste the two keyframes now go to frame 40 and paste the keyframes here as well and now the last frame i have in my animation is frame 60 so i'll copy the single keyframe at frame 40 and paste that there my animation is now complete and the arrow repeatedly goes up and down this catches the player's attention and tells them that they have to press a button to move to the next message now by default this arrow will be visible all the time but we only want it to be visible when a message is complete so i'll go into the own next message objects add the create events and here set the image alpha of the instance to zero this way the instance will not be visible by defaults and i'm not using the visible variable because that's controlled by the sequence now we're gonna control this image alpha value in the old text box object inside the step event i scroll down to the block where it knows that the message is complete which is the else block and within the else block i'll set the image alpha of the o next message instance to 1 this way it will be visible when the message is complete now when we move over to the next message which we do by calling the next message method we should set the alpha back to 0 so the arrow becomes invisible again so we'll do that within the next message function the text box now controls when the arrow will be visible and when it'll be invisible let's run the game and talk to an npc when the first message is over you see the arrow and when you go to the next message it disappears and then it appears again and so the arrow is now working perfectly now finally i'll add a new dialog and apply that to a different npc for that i'll go into the dialog data script i'll make it full screen and inside the speaker struct i'll add two more speakers the two new speakers will be two new structs after the bob struck so the speakers i've added are rob and jess now i'll go to the bottom of the script and here add a new dialog this will be a variable called rob underscore monster in the global dialog struct and it will contain a bunch of messages and then at the end i'll add another message and this will be called jazz underscore help we can now go ahead and apply these dialog arrays to different npcs i'll go into the game room and double click on this npc i'll open the variables and edit the default dialog variable i'll set it to global.dialog.rob underscore monster i'll close this and find the jsnpc double click select variables and edit the default dialog variable i'll set this one to global.dialog.js underscore help now our first npc bob currently relies on the default value of the default dialog variable so i'll simply edit that so it becomes specific to this instance and so it's not relying on the default dialogue set for all npcs i'll run the game and talk to rob who has his own dialogue now and you can also go and talk to jess this section is now finished and you can go ahead and add your own npcs and dialogue you
Info
Channel: GameMakerStation - Matharoo
Views: 27,702
Rating: undefined out of 5
Keywords: gms, gamemaker, gamemaker studio, gamemaker studio 2, game maker 2, gamemaker 2, gm2, gm 2, gms 2, gms2, gamemaker language, gml, tutorial, coding, free, make games
Id: tYyuOFPLls4
Channel Id: undefined
Length: 141min 17sec (8477 seconds)
Published: Sun Aug 07 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.