How to Use Signals in Godot and Handle User Input (Godot Retro Text Adventure #3)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to add on to the input field we created in the last video and let you actually respond to user input so if i type something like hello you'll see a response come back from the server we'll also make sure that if you continue to type things we add a scroll bar so that you can mouse back over the history of what's been typed and see your input over time let's get started so in the last video this is where we left off we were able to process text input or to allow the user to type it but we weren't actually processing or handling it or you know taking the input when the user entered it but now we're going to get to the fun stuff and we're going to start learning how to process the input that the user enters when they hit the enter key so in order to do that there's a couple things we need to do the first thing we need to talk about are signals and so any node or any scene in godot is able to emit a signal if you've programmed in other languages signals are the same as actions or dispatchers or observer it's really just that same pattern that's common in so many different languages where you have some kind of a signal or event that happens and is dispatched and then there are subscribers or listeners so signals are are basically events or actions and then you can have different nodes or scenes subscribe or listen to those events in godot it's called emitting a signal and connecting to a signal instead of dispatch and subscribe or whatever you're used to so there are a couple ways to connect to signals that an element has or that a node has you can do it via code but you can also do it by the editor and that's what we're going to do right now and so if i select our input field here and then come over not to the inspector tab but select this node button you're going to see signals and groups we're not going to go over groups right now groups are basically like tags in unity pretty much the same thing we might use them later on but no need right now but you'll see a bunch of signals some of them are common to every single type of scene or item in godot like nodes and objects and canvas items some are unique to control nodes so you see a bunch of things about focus and gui input mouse entered and exited and then there's ones that are specific to the specific type of node you're dealing with so like a line at it and the line edit node has a signal called text entered and if you hover over it you'll see that this signal gets emitted or dispatched when the user presses the enter key on the line edit which is exactly what we want we want to whenever the user enters like hits the enter key to respond to whatever is currently inputted in that input field and so we can connect to this signal and do something with it and handle the input that we're getting in so in order to connect we can either click on this text entered oops we can click on text entered and we can hit the connect button here down at the bottom or we can just double click it and then connect it there and so when you connect a signal you have to select which script or which node which scene to connect it to now we only have a script right now on our input field and we don't really want to connect it here because we want our input field to be responsible for letting user input stuff we don't actually want to have it processing that input so we need to create another script on something else and for now what we're going to do is select our game so the top level node here and we're going to attach a script to it so i'll click the attach attach script button and we'll just call it game.gd and hit create so we'll let the default work and you'll see now in our file system we not only have an input script but a game script and then in our script view here we can switch in between those two as needed in our input script remember all we were doing is grabbing the focus when our node enters the scene tree and in our game script we've got a bunch of boilerplate that gets added in there by godot and we're going to change this in a second so if i save our game then select our game node here so that we come back to this the 2d view i can select our input now and double click the text entered signal to connect it to our game script so we'll have our game kind of be responsive for delegating the handling and processing of input away from the actual entering of it so we're delegating responsibilities we're keeping code modular it's only doing one thing this is a term in programming often called the single responsibility principle which is each piece of code or each item or element or object should really only be responsible for one type of thing so the code in our input field is only going to deal with handling input coming in or or dealing with either user typing but our game can handle delegating the processing of that input somewhere else so i'm going to hit connect and now we'll see in our game script here we have this on input text entered function and it's going to autofill with a name and parameters for this function and remember if we come here we see that text entered uh you can you can change this this fee this down here to change the default generated function name but remember we see here in our signal view that this signal has a parameter so it comes with information about the new text like what text was entered and so you'll see that once we connected this and it auto-generated the function that matches it it's also going to auto-generate this parameter as well so we automatically have everything we need here i'm gonna get rid of all the boilerplate to have the text that's entered so just to show this let's just print it out in godot there's a print function and whatever you print here will just be set to the output down below so we can just print out new text and so now if i run our game and i type something so i'll type hi friends and i hit enter we should see it appear down here in our output so i hit enter there it is and i can keep doing it as much as we want so this is great we are taking the input once it's entered and we're doing something with it right now we're only printing it which isn't what we want to do but we're doing something now another thing that would be cool is that when we enter text this field was cleared out here because we don't want the user to be able to print the same thing or to be able to just hit enter repeatedly it's not a great experience for the user and it could just cause a ton of crap commands get processed so there's a couple things we could do we're handling this on input text entered signal on our game script so one thing we could do is we could somehow get a reference to our input all the way down this tree and then clear the text whenever the signal comes in but that's kind of tedious and our game shouldn't have to be responsible for telling our input to clear its text this is just part of handling user input is that whenever it's entered we want our input field to know it should clear so what we're going to do is actually connect another function to this same signal so if i select our input and then come over to the text entered signal we'll double click it again but this time we're going to connect it on our input field itself so you can connect a signal from in from a node or scene to itself so we will connect this on input text entered signal to itself so we'll create a new function here and we'll see that we now have this new function it matches what's in our game but it's on our input node and here what we can do is just say text dot clear or actually we don't even need to do that there's a clear function built in to input fields so we can just call clear here and now if i run our game and i type hello friends we'll see it appear below but we'll also see our input be cleared boom just like that so it's really easy to do that in godot whatever i type whenever we enter it it clears our input and now we've got something that's really starting to feel and look like a text adventure game we're handling input the way that a user would expect it to be handled and the experience is much better now so just that to show that you can connect multiple functions to the same signal whether it's via code or via the editor like we did and that's totally okay obviously you want to be careful with connecting signals because those will get called those functions will get called every time that singles signal is emitted so you know you're trying to be responsible with it but for us you know the user is only going to hit the enter key after they've typed something it's not like it's happening every single frame so it's totally fine for us to connect both of these sig or both of these functions to that same signal okay so now we've got something where the user can enter text it's going to clear the text once it's entered and we're receiving the text that was entered but it'd be really cool if we could actually start displaying either responses from the game or at least kind of giving a history of what the user has entered to them so let's add something like that now in order to do that we're going to be able to start populating our game info area which we haven't really touched yet and so in order to do that we're going to need a couple things one is that we kind of want to have a scrollable history of all of our game input and we can edit how much of that history should that be remembered like how many commands should the game show and remember and let the user scroll back through but we want to at least have some functionality that does that but the importance here is it needs to be vertical so we need to stack things vertically here and we already know how to do that we've added a node that lets us do that a couple times now and it's a v box container so i'm going to select our game info area and add a vbox container and again this is going to be our history rows and we'll talk about how to make it scrollable later for now we'll just add this and make it make it work as needed and so typically when you look at old school games they uh the way that they handle player input is they would reprint that input out on the info the history screen but then also show the response right below it so we're gonna try and recreate that so we're gonna build out what that will look like right now and then we're going to save it as a scene so we can reuse it multiple times so in order to do that i need an egg in another v box container because we want this to be a we want each set of prompt and response to be their own kind of thing so i'm going to say input response for this new vbox container and this is going to be kind of our parent node for our responses so we're going to be able to to create new ones of these scenes new scenes of input responses that we can continue to use over and over and so in our input response there's going to be two things there's going to be a first label and this is going to say input history and we're going to duplicate that i'm going to hit command d and call this response and so our input history is going to be something like this also for both of these let me select them both and then i'm going to come down to custom fonts and we'll drag in we'll start with the 28 so it'll be the same size for now so dragging the 28 there and then for our input history i'm gonna do similar to what we did with our carrot space carrot space so that it matches what's below and say this is what the user typed and then here i'm gonna say this is what the game will give back and so what i'm gonna do to kind of make this look a little bit better is a couple things one is i think i'm gonna bring the font on this one down on the history just so it's like this is less important than what the game is saying back so i'm going to bring the font down a bit so this is what the user typed and you might want to find like we might do a 24 here so i might actually let's just do that just so we have a bit of um variance in our fonts so i'll create a new 24 font bump this up to 24 so i duplicated our 16 and bumped it up the duplicate up to 24 and we can drag this 24 in so it's slightly smaller but not too much but it's noticeable and i think i'm going to make the color of this this input history a little darker so again we're bringing attention to the response and that's what the user typed so i can go to custom colors here and change this font color and i can change it to just a slightly more gray one something up in here about half gray but just again so now you look the attention is clear here it's drawing your eye to this um response and this is just kind of here as reference you don't this isn't actually what you're being focused on one other thing is we notice there is a bit of we probably want a bit of a margin here so in order to do that we can add a margin container to our history rows or to our game info section um uh we'll we'll come back to that this will be good for now so this is kind of what we want want to have going for us and so in godot we basically what we want to do is whenever the user types something we want to create one of these objects we want to create a v box container that has two children like this to give us the ability to do something like that where we have a reusable scene we can actually right click on our input response container on this one so right click on this and we can hit save branch is seen and what this is going to do and i'll just do input response keep the default name and hit save this is going to save our input response as its own scene branch and you'll notice i can't actually expand it now but i can hit this button and it'll open the scene up in a different window and this right here is the power of godot you can save any collection of nodes even a single node itself as their own scene and you can reuse that scene and customize it in your game as many times as you want all of a sudden now we have this really nice reusable input respon response scene where we can eventually add a script to handle setting what these two text fields should contain but we can keep reusing this as many times as we need in our game and it's going to give us a really nice easy way to keep adding responses every time this or the user types something so now that we have this input response we can actually get rid of it because we don't want one to be there we're gonna actually load it into our game and the way we're gonna do that is by coming into our game script and so there are a couple ways that you can give scenes that are not in your game give basically they're like prefabs in unity there's a couple ways that you can load those in one is to do it by the editor there's certain ways you can make export variables they're called we'll get to that later on in the series but the way we're going to do it now is using preload so preload is a function you can use in any godot script that will load in something from into memory upon the whenever that script is parsed so i can do const and we're going to say const here because we want this to be constant it's never going to change and this is going to be input response we want to upper case this we're going to pascal case this because it is a a packed scene itself it's the scene data but it is not an actual game object it's not a scene or a note in our game it is holding the data for what that scene should look like in memory and so because it's basically think of it as a class it's a script class but not an actual instance in our game and so we it's like an abstract class that we need to instance whenever we want one in our game and so we're going to use pascal case here and i'm going to use preload this function built into godot and then i just have to give it the path to our scene and this is going to be res and then input response as we see down here so i can find that in the autofill hit enter and it'll just be there and all of a sudden whenever our game loads and this script is parsed we're going to save the data for this input response scene into this input response variable and now what we can do is whenever we enter text we can create a new one but we want to make sure we're creating it as a child of this history rose object so first we need to get a reference to that and in order to do that we're going to type on ready one word var and this is going to be history rows and then i'm going to say equal sign and then the dollar sign and just start typing history rows and we'll find it here godot is going to autofill it for our scene tree and let me break down what's happening in this line when you want to get access to a node or a scene in your tree you can use this dollar sign to select it so this is just the path of this history rose seen in our tree you'll notice background margin container rows game info history rows that matches exactly what the the uh code is right here so this is how you select a scene or a node in your game that's currently in your tree and affect it however you want to make sure that whenever you do this that you're only doing it after this specific scene you're trying to access is in your scene tree we know in godot whenever the ready function fires so i'm going to add it to this right here whenever the ready function fires of a parent you can guarantee that all of its children have also already been ready they've already already been ready to or added to the scene tree so within the ready function of our game for example it is safe to assume that all of its children which are all of these have been added to the tree however within the ready function of our game info for example if we added a script here we could not assume that we could access our background node from within it because background is not a child of game info you can't guarantee that actually game info will always be readied before background is and thus you don't want to access it so you only want to use this to access children to go down the tree not upwards but because in our game script here in our game scene we can always be sure that when our game is readied when this ready function is called it is safe to access our history rows because history rose is further into the tree it's a child and so what we could do is we could say something like background the same thing we had up there where we can do history rows because we know it's safe to access history rows here savar history rows however it gets really tedious when you're writing this for every single thing you want to access every scene you want to access so godot provides a helper and it's this on ready keyword here so when you prefix variable with onready uh it's what it's going to do and you can only do this at the top of your scene or at the top of your script it's going to say hey when we're going to fire this ready function but right before we actually do then we're going to load in history rows we're going to load in this node path into a variable so this on ready means that it's going to happen right as we're calling ready it's going to happen when it's safe to safe to access this node but before the ready function is fired so if i try and do print history rows not only will there be a value in history rows because we are accessing this variable this scene this history row scene when it's safe to do so we'll also be able to print it out here because this happens right before the ready function is called so this is a super helpful way in godot basically whenever you want to keep track of a child node or child scene this is usually the best way to do it anyway just a little bit of info on why we're doing this and what this line means and how to access scenes in godot from within code so now that we have access to this history rose we're ready to add scenes to it and so what we want to do i'm going to get rid of this ready function here because we don't need it is whenever we enter text so whenever we enter new text now instead of printing it what we're going to do is say var input response equals and this is going to be capital input response dot instance so there's a couple things going on here remember that this capital input response here is the data itself it's not the input response scene and whenever we want to add that to our game we need to actually create an instance of that input response scene and so we're going to create an instance of it and then save it to this lowercase the snakecase input response variable so this one this variable contains an actual instance of our input response scene whereas this is just the data of that scene it is a packed scene packed into a data a resource so now we've gotten this lowercase input response here our actual instance that we want to deal with so it's not enough to just instance something in godot though we actually need to add it to our scene tree as a child of something for it to be visible and in order to do that we want to add it as a child of our history rows so we can actually just say historyrose.addchild and we're just going to give it the node which in this case is input response so what we're doing here is saying we're going to add we're going to create an instance of our input response scene and then we're going to add that scene that input response as a child of our history rows and what this is going to do it's going to be the same thing as if we add our input response here it's doing the exact same thing that we just did by adding manually by the editor input response is a child of history rows and if we continue to do that we're just gonna create more and more of them so you're learning right now how to do via code what we're doing by the editor right here so i'm going to delete all these by the way we've talked before about this plus button lets you create built-in godot nodes this little chain button here lets you instance a scene that you've created so if you want to you want to create and add to your scene tree something that you've created your own scene like our game or input response you would use this little chain button up here or link button i think it's a chain whatever though you get the you get the point so now that we have this we can run our game and see that whenever we type something so i type hello we're gonna get a new response and obviously it's not responding to anything we type but it's being added to our scene which is exactly what we want there's an issue though that if we keep going it's gonna keep pushing things down lower and lower in our game which is not what we want so this is where we need to add a scroll container to properly handle this okay so in order to add a scroll container what we're going to do is come back to our scene i'm going to click on game info here and i'm going to hit command a and look up scroll container so godot actually has a built-in scroll container that will automatically handle adding vertical and horizontal scroll you can access vertical and horizontal scroll bars yourself to manually add them but the scroll container is much easier and it will configure a lot of it under the hood so we're going to add that now if i add the scroll container as a child of our game info section you'll see it's got this little warning thing on it and if i mouse over it it'll say hey use a container as a child of a scroll container like a v box or h box well good news is that we have a v box container here in our history rows so we're going to drag this to be a child of our scroll container and we'll see that warning go away now on our scroll container there's a couple things we need to configure so if i select it and come over to the scroll property you'll see that there's a horizontal scroll enabled section here we don't want to horizontal scroll we just want vertical scrolling so i'm going to turn this off and that actually should be good enough for now so if i run our game and just start typing a bunch of things you'll very quickly see we actually get an error that crashes our game and the problem is that it's saying hey we're you're trying to call the function add child so we're calling it right here you're trying to call add child on a null instance so that's saying and telling us that history rose is null and the reason that history rose is null is because we had this hard-coded node path here but it's since been updated there's a scroll container in the mix now that we haven't accounted for and thus it can't resolve history rows so the way to fix that is we have to find what's changed in our node path so we have rows game info okay and it's after game info that the scroll container should be there so after game info on our path here i'm going to say scroll container so that it matches what's in our scene tree now this is somewhat tedious admittedly there are ways around this you can use godot has a built-in node path that lets you do drag and drop and it'll automatically update we won't cover that because this isn't so much of a big deal here but just as an example i wanted to go through and kind of debug this error just so you can see why you're getting it because this is a this uh attempting to call a function in base null instance is a very common error and it's almost always because you have a variable you forgot to update the path or is being set null somewhere you're using it before it's ready so now if we start our game and i start adding a bunch of things and typing it you'll see that all of a sudden we have a scroll bar it's not actually pushing everything else in the game down but it's letting us scroll through all of the input that we have in our game so this is perfect in this video now we've got a game that lets us respond to user input and print something back out it also lets us scroll as we continue to add more and more user input in the next video we'll actually handle getting moving our scroll bar to the bottom when the user types in input and being able to manually set and change what this input and response is coming back from the game thanks so much for watching everyone i hope this video has been helpful if it has a like and subscribe to support the channel are always appreciated we'd love to have you in our discord server the link to that is in the description you can ask any questions about the tutorial there and if you find my work helpful donating a coffee on buy me a coffee linked also in the description is really helpful and helps me continue to make great tutorials thanks so much for watching see you in the next video you
Info
Channel: jmbiv
Views: 3,090
Rating: undefined out of 5
Keywords: godot, godot engine, godot 3.2, godot tutorial, godot 2d, how to make a game in godot, game development, game development tutorial, game development for beginners, godot for beginners, game dev, indie game dev, how to godot, gamedev, godot game engine, godot text adventure, godot text adventure tutorial, godot input, godot user interface, godot control node, godot control, godot beginner tutorial, godot signals, godot signal tutorial, godot handle input, godot input event
Id: 5gP1eOtR5Kg
Channel Id: undefined
Length: 26min 23sec (1583 seconds)
Published: Mon Feb 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.