C# Godot | Creating a Scalable Dialogue System

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys this is mitch with finepoint cgi and today i'm going to talk to you guys about how to make a dialogue system inside of godot so first we're going to go through the process of planning our dialogue system then we're going to jump into godot we're going to build out our dialogue system inside of godot and then we're going to jump into c sharp and kind of code the entire thing now this tutorial is going to be a long one and it's kind of a continuation of this small 2d platformer thing i'm doing but you guys don't have to watch previous tutorials to to do this tutorial but you will need to do some finagling on your end to make it work with whatever it is you guys are doing so that's what i have in store for you guys today so let's go ahead and get started okay so the first thing we're going to do is we're going to plan this out so since we're creating a dialog system it's going to require us to actually plan out exactly what we want this dialogue system to do right we don't want to just go in and start coding without having a road map or an idea of what we want to build so the first thing that we're going to do is we're going to map out kind of what we already have so we have a game manager here right so if we remember correctly we have a game manager here and that kind of runs our game and then we have a player controller here and the player controller talks to the game manager whenever it needs to change game state so like for instance if the user dies or something like that that's what that's for right well now we're going to need to create what's called an npc character right so let's go ahead and create our npc character so that's going to go ahead and talk to our game manager here as well whenever it changes states for instance if the npc dies and the player gets coins or something like that or if the player talks to the npc the player will say hey i'm talking to the npc and the npc will give the game manager it's information right but also we need the ability to show what dialogue this npc has so this npc needs to give dialogue information to the game manager so the mpc needs to house this game or this dialogue information so we need to create what's considered like a a model object right so that houses all that data so let's go ahead and create this little sphere here or this little ellipse here and we're going to call this npc dialog and i can never spell dialogue there we go and we're going to pass that into our npc character so now the mpc character has an object that it can pass to our game manager to say hey here's the current npc's information and here's the current stuff that i'm i'm trying to handle basically and we can always extend this dialogue object in the future like maybe adding in more state management like a quest system or something like that but right now we'll just create a small dialogue object and then we'll extend it in the future but now that we have this we need to be able to post stuff out to our interface which means we're going to need an interface manager right so we'll go ahead and put that in and then we need to handle our dialogue as well so we're going to go ahead and place in a dialog manager underneath our interface manager awesome so what's going to happen is our player controller is going to walk up to our npc character right and it's going to say hey i need you or i want to talk to you right this is going to pass the dialogue object to the game manager and it's going to tell the player controller is going to tell the game manager hey i want to talk to the dialogue manager and i want to talk to this npc so then the game manager will say okay this guy and this guy want to have a conversation hey interface manager can you pop up a dialog right and the interface managers go yup dialog manager go ahead and take this dialog object and show your dialog options and then from there any interaction will go through the dialog manager the dialog manager will handle everything else so this should allow us to have a fairly extendable system that might be a little overkill but it's going to make it a lot more stable in the future if we want to expand on this let's say we have 5 000 npcs with you know a thousand different options each this is going to get big fast so we want to make sure that we build something that's extendable for the future so with that being said let's go ahead and build this thing all right so now that we're inside of godot what we're going to do is we are going to go ahead and right click on our game manager at a child node and we are going to add in a canvas layer so if we type in canvas let's see canvas layer and then what we're going to do is we need to go ahead and start building upon our little canvas layer here so what a canvas layer is used for is it is used for like user interfaces and things like that it's basically your screen that you actually see so now what we're going to do is we'll right click add in a child node we're going to add in a node and it's going to be actually i think it's called a control there we go we're going to add in a control and we're going to call this the dialog manager and we're going to name this canvas here we're going to call it interface manager as well so if you remember our diagram here we have our interface manager and then our dialog manager our dialog manager is going to handle all of our dialog elements so we'll do is we'll click on our dialog manager we're going to go to layout and we are going to do bottom wide and that will snap us to the bottom here and then we're going to pull this up something like i don't know about here ish something pretty large we'll drag up our little green dots here and if you don't know what the green dots are it's for scaling so you can actually set this up so that your interface will scale based on uh its relation to these little dots so if you were to put it up to the top like this then this would scale relative to how this scale so it scaled more vertically than it would horizontally because you have some space between your little box here generally speaking i like to keep them like this it just makes things a little easier now what we're going to do is we are going to right click add any other child node we're going to add in a pop-up here so we'll just go right straight to pop-up we're going to turn that on right here by clicking on little i and we are going to make that full wrecked so if you click layout and go to full rect that will pop all of this out for you all right now that we have that we want to have some kind of background here right so that it actually looks pretty good so let's go ahead and add a small background element here by putting in a color rect and we're going to also lay that out as a full rect and that's going to be a full-sized white box here so that way we can show up text on here now inside of our pop-up we're also going to add in a label and we'll set this up to be something like i don't know actually we'll just take a layout and we'll go top wide and we'll pull this down just a tiny bit let's pull that little green tick mark down as well we'll add in some text to our label we'll say test np c name and you can see that right now you can barely see it but it's there it's kind of white but you can't really see the text so let's go ahead and come down here to our custom colors section and change our font color to be black now i'm going to pull this out just a tiny bit and i'm going to pull this down just a tiny bit so that way it's got a little bit of buffer between the top of the screen and the left side of the screen so now what we're going to do is we're going to right click add in another child node we're going to add a rich text label here we're going to go ahead and double click that and we're going to make this full rect as well and we are going to pull this down until it's just slightly underneath the test name npc and the reason why is if we put a bunch of data a bunch of data in here so let's just throw a bunch of text in here let's go ahead and copy and just paste that a few times just to throw a bunch of data here you can see that we wouldn't want to cover the npc name right we can also see that we have the same issue as we had last time where the color is not the correct color so let's go ahead and change that custom color default color and there we go now we're also going to pull this up because we're going to give the user some options to be able to um respond to this player like you know hey thanks i i got your information right or whatever right we could say i'll take the quest right if it's a quest npc and we're going to pull this over a tiny bit and we are also going to pull this over a tiny bit just to give it a little bit of buffer room now one of the things that we want to make sure that we turn on is we want to make sure we have scroll active on and we also want to make sure that we have scroll following on and what that's going to do is as text rolls in here it will snap your your little scroll bar down to the bottom so if you see when i have something like this right and there's no scroll bar it's good right but if i let's copy this all of this right and if i uh go ahead and i paste this you'll see that it's staying at the bottom as the text flows in and the reason why you want this is that it will allow the user to not have to scroll down to read the rest of the text it just naturally scrolls down as the text kind of comes in so perfect so i'm going to go ahead and just paste in some words so we have something to look at and what we're going to do now is we are going to go ahead and add in a horizontal layout object so it's called an h box container here so we'll put that underneath our pop-up and we're going to go ahead and do a bottom wide on it and we'll pull this up to something like here ish sweet so now we'll pull this up as well and there we go and this will hold on to our selectable dialog elements so basically all the little selections that the user is going to make so that way they can make choices right like oh yes i'll accept the quest so now that we have that we need to go ahead and make our little selection object here so we'll go ahead and right click hbox container we're going to add in a control node and we will go ahead and change the size of our control notes so underneath rect here we're going to go ahead and change our minimum size here to 100 x and that is going to go ahead and allow us to have different selection options so if i uh when i put text in here now it'll maintain that 100 size so now that we have our control we'll go ahead and right click add in our child node and we're going to add in a label and we will go ahead and make that a right wide on our little control node here and we'll pull this over to something like that and i will pull this over to something like that and then we'll go ahead and put some test text in here and we're going to need to go ahead and change our color to black so that it works with our white background and we will align this to left center and then we're going to right click here and add in a texture that's a texture button not a texture right click add text erect and then i'm just going to go ahead and kind of size that up so that it works well for us great so now that we have this let's go ahead and click on this and call this interface selection and we will right click this and we will save a branch as seen as interface selection then we can go ahead and get rid of this now that we have one and like you can see if we duplicated it we'd have multiple so that's perfect one of the things i don't like so far is this needs to be centered so let's take our hbox and do alignment at center that way when the text box shows up it just kind of shows it in the center great so let's go ahead and delete those i don't need those anymore but now we know where everything's at now let's go ahead and select our dialog manager let's right-click attach a script call it dialog manager dot cs so that's perfect go ahead and hit create we're going to do the same thing with interface manager right click attach script interface manager that sounds perfect let's go ahead and hit create and so far there's not going to be much in here eventually it's going to get you know we're going to expand it it's going to be big and it's going to have a lot of stuff in it but right now there's not too much that we have to put in here so let's first get rid of that commented out variables and let's add in a public static dialog manager and let's just call it dialog manager we're going to say hey on ready go ahead and do dialog manager is equal to get node and we will say dialog manager and then we're going to say as dialog manager whoops as a capital d dialog manager awesome so what that's going to do is that's going to give us a external way to call our dialog manager so like for instance if the player needs to call the dialog manager for some reason like they're trying to talk to somebody they can say hey enter a gamemanager.interfacemanager.dialog manager dot do whatever it is that i need to do so now that we have this we're pretty much done with our interface manager class at least right now for this tutorial so we'll go ahead and open up our dialog manager here and we have quite a bit more coding to do here so the first thing we need to do is we need to make a method to show our dialog elements let's go public void show dialog element next we'll go ahead and pop up our dialog box so get node pop up and we are going to say pop-up in this case dot pop up like that and what that's going to do is that's going to tell the dialog element to pop up and then what we're going to do is we will go ahead and write some of our text here so we're going to say hey go ahead and get node rich text label pop-up rich text label we're going to say dot text is equal to test text and then we're also going to say get node label and we will grab the label is equal to uh dot sorry dot text is equal to test name and then we are going to say hey i'm ready show dialog element so what that should do is if i go back to here and i go ahead and i hit play is it should pop up our dialog element now in this case it is huge so what i'm wondering is is our dialogue pop-up broken it doesn't look like it do i need to hold on one second let's see if i make this full wrecked and i pull this from being full wrecked to only being a bottom wide and i pull this up to something like that let's see what that does see if that fixes our little issue so let's go ahead and hit play now that i made that little adjustment awesome so now you can see it has test name and test text so our code is working that's good news so you can see instead of having test npc name we have test name and instead of having the crazy text there we have test text so now we know that our code is working so the next thing that we need to do is we need to set up our npc so what we'll do is we're going to go back to godot and we're going to go ahead and put together our little npc character so what we're going to do is we're going to right click here add in a child node we will add a kinematic 2d body and the reason why i'm choosing a kinematic 2d body is a it's going to need to be able to use collision and b later if i want to make the mpc to walk around or to do different things it's a good idea to make sure that your character or your your npc can actually move around so kinematic 2d bodies are great for if you want to move physics objects with code so what we'll do is we'll right click here add in a child node add in a collision shape and we will make it a square shape so let's go ahead and grab a rectangle shape and then we're going to right click add in a child node and add in a sprite since we don't actually have a sprite here for us to use that we haven't already used here that's not like an enemy character what we're gonna do is we'll just take the archer hero we have here and we will right click uh here and go ahead and open file manager and we'll go ahead and go into our archer hero we're going to grab his idle and running state and we're going to open up curta or krita and go ahead and drop that in here and what i'm going to do is i'm just going to modify his color so i'm going to go let's see i believe it's adjust color balance and i'm just gonna grab his mid-tones and i'll throw him more of like uh i don't know cyan blue color yeah there we go so we'll just make them blue and we'll hit okay and i think that that's good enough that you can kind of see the difference between the guys and we'll go ahead and save that and we'll change this to idle running underscore good so that way he's got something to make him look a little different so we know which one's a good guy and which one's an enemy so let's go ahead and come in here it's going to go ahead and throw that in here and we will take our preset and change that to 2d pixel we'll reimport this and we're going to go over to our sprite and grab our texture and throw this in there now you'll see that he's got a few things actually you know what i'm going to do is instead of doing a sprite let's go ahead and get rid of that and let's add in a animated sprite and let's go ahead and add in a new sprite frame object and we'll go ahead and add in sprite frame from a sprite sheet you guys have probably seen me do this a few times but that's where the button we got to click so click that and go ahead and go to archer hero final and then idle good and we'll go ahead and set this to a let's see looks like eight horizontal and two vertical we'll grab these two frames and we're just going to call this idle so that way he has some frames to work with now we're once again like we did originally let's grab him we'll we'll lock him right here with our little lock and we'll drag him over here so we can kind of see how he compares in size to our actual um character here and we'll go ahead and change his scale down to i don't know something like this let's see something about that tall i think would be good and let's go ahead and un connect these two and drag this back into this little square here and then we're going to go ahead and make our collision shape about the right size for our character here perfect and now we'll go ahead and re-lock this and we're going to name this npc and we'll drag him over here so that way he's off on his own so that way the player can go over there and talk to him without fear of getting attacked or shot at or anything like that okay so now that we have a npc character let's go ahead and right click it attach a script and let's just call mpc.cs and let's go ahead and create that the first thing that we're going to need to have is we need to go ahead and set up what the npc is going to say so the npc is going to have a state where he's going to say here's my initial dialogue here's a couple of selections and then when you select one it's going to go ahead and bring up another selection right it's gonna bring up another piece of dialogue whether it's it's okay thanks have a good one then you can hit okay right and close the dialog box or it's something like hey i need you to go get me up an object right like go get me a quest like a quested object like like a necklace let's say right so what we can do is first we need to create an object to handle or to to be that um dialogue if that makes sense so they give it kind of like instructions on what the person can say so what we'll do is we'll make a class that is an npc dialogue class so it's going to house what the npc is going to say so create a new file and we'll say np c dialog and inside of here i'm just going to grab npc and i'm going to go ahead and paste this and we do not need it to inherit from kinematic body and honestly we don't need it to have any of that stuff and we probably don't need that either so if we go ahead and save oh this needs to have cs at the back at the back end here i didn't add that so dot cs awesome so what we can do with this is we can say all right what do we need do i already have oh that's because i copy and paste this okay i was like what let's make sure these match because godot has a small bug uh where if these don't match they will not compile properly so the first thing we're going to do is we're going to go ahead and plan this out a little bit so let me grab draw i o here real quick and you can see we have our little thing here um it says here that we have an npc character an npc dialog object at that character holds onto right that's kind of what we're creating now but one of the things that we also kind of need is we need a interface selection object right because the um dialog option has things that the user can select right so we're going to need a selection object for it to have so we need to also make this little object here so let's go ahead and make that little object so if we minimize this and we go ahead and control a control c create a new file and call it interface selection object dot cs that's not cs that's dot vs rename oops dot cs we'll go ahead and paste this in here and then we're also going to grab that name there and just paste it up there so now we have two classes here the npc dialog object and the interface selection object and the mpc dialog object will be holding on to some interface selection objects right so what we need to do is we need to [Music] first have an index and the reason why we need an index is because every object that's some form of selection or something like that should have an index to reference to so those interface selection objects will reference an index to determine uh the next interface or the next dialog object that that object or that dialogue can pull up if that makes sense next we'll have a public list of interface selection objects oh come on like this and we will call it since it's public it'll be capital and then we're going to say public list of npc dialog objects right and the reason why and i will draw this all out for you guys to hopefully better understand this then finally we're going to have our public string and we're going to call it display text awesome and now i need to add in here using system.collections.generic and that will allow us to use the lists here that we have now what we also need to do is we need to go to our interface selection object and we need to go ahead and make that so if we go over to our interface selection object it'll have two things it'll have two strings or an integer and a string and we're going to have a selection text and a selection index so if we go back to our diagram here let's kind of move over here real quick so what's going on is the workflow is going to be like this we pop up a dialogue so we get our npc dialog okay so it's going to get our mpc dialog and from there it's going to pull its text okay and then it's going to go ahead and it's going to get our interface selection objects okay so if we draw this across here then what it's going to do is it's going to go ahead and allow the user to make a selection so user makes selection now what it's going to do is it's going to say hey is our selection index in our npc dialog indexes okay and if it is it is going to go ahead and basically do the same thing here so it's going to go here and it's going to say select our next npc dialogue from our list of dialogues and we'll pull this up like this and then this will come back to here and it will pull the text to display and it'll get our interface it'll make another selection and it'll allow the user to make a selection if it doesn't exist what it's going to do is it's going to bail us out so that's the reason why we need the things that we have so if we look at our interface selection object it has a in a selection index so the index that when it gets selected that's going to be what it's going to search in our list of objects and our selection text so it's going to be the text that displays for the user and in our npc dialog we have a list of our interface selection objects saying here's the things that we can select we have a list of our npc dialog saying here's all of our npc dialogs that are underneath this npc dialog we have our display text which will get displayed and our index of this npc dialog so that way it can find it can be found by our selection object if that doesn't make sense go ahead and throw a comment down i know it's a little confusing but that's basically the gist of how this is going to operate so now that we have all of this let's go back to our npc here let's go ahead and make a private list of whoops list of our npc dialog here we'll call it npc dialog because i like original names and we'll say using system dot collections dot generic so that way we can go ahead and grab our little npc dialog here so now the first thing that we need to do is we need to go ahead and set up our npc dialog objects now in a future tutorial i'm going to go ahead and throw it out into json for you guys and we can actually pull up from json and populate our npc dialogue so that way we can you know better manage this but right now i'm just going to throw it in the ready so we're going to say interface selection object obj is equal to a new interface selection object and we are going to say obj.selection index is equal to 1 obj.selectionindex our selection text is equal to we'll say i don't want the quest i actually will say i do want the quest why not i like to be adventurous so so then what we're going to do is we'll create another interface selection object and honestly now that i'm looking at this let's go ahead and go into our interface selection object and let's go ahead and add in a a small constructor so we'll say public interface selection object and we're going to pass in a int index and a string selection text and all that's going to do is that is going to say selection text and it grab the wrong one selection text is equal to selection text and then we'll say selection index is equal to index and that's going to go ahead and just allow us to quickly construct this information so let's go over here and instead of us needing to do it like this we can actually just go one comma and grab our i do not want this quest or i do want this quest in this case there we go that's going to make things a little easier and we can just kind of construct it right so that way we don't need to to go through the process of of having multiple ones here so now we can say interface selection object obj2 is equal to a new interface selection object will make this a2 comma i do not want the quest whoops awesome and then what we're going to need to do is we're going to need to go ahead and create another one so what i'm going to do is i'm just going to duplicate this so ctrl c and let's go ahead and control v and control v and we'll set this as object and we will say uh selection index will be minus 1 and we're going to go ahead and say selection index is -1 as well and we'll say okay and okay now the reason why is because once they say hey i do want the quest or i don't want the quest we don't want if we want to have those selections available and we want to be able to have both okay actually i think we could probably just get away with one to be honest so now we need to go ahead and create our npc dialog object well much like what we did with our interface selection object let's go ahead and create a small constructor just to kinda handle it for us so let's go over here and say public npc dialog and we'll say hey i want a list interface selection object and we'll say interface selection objects comma string display text comma int index comma list capital l list of npc dialog objects and we'll call that dialog and we're going to go ahead and make that innulable so well by defaulting null and we'll go ahead and um create our braces there we'll go ahead and assign our variables here so we'll say interface selection object is equal to interface selection objects and then we'll say display text is equal to display text oh and i don't want a capital d here i want a lowercase d so let's go ahead and do that and then we'll say index is equal to index and then we're going to say hey if our dialogue does not equal null then we're going to say npc dialogues is equal to dialogues now the reason why we want to make this null is because if we make this null it allows us to say hey this is the end of the chain you know what i mean if if we can check if it's null that means that it's at the end of the chain of this whole mess here so now if we go back to our npc here we can go ahead and pass in our npc dialog object so let's go ahead and say npc dialog is equal to a new list of npc dialog and let's go ahead and make an object wrapper here so we're just going to go ahead and kind of throw it all into this little object here so what i'm going to say is i'm going to say new npc dialog and we'll say new list a new list of interface selection object and what i'm going to do is i'm going to pass in my obj comma obj 2. and we're going to pass in our um display text that we need and we'll say help i need you to help me and we need to pass an index we're going to say index of zero so what we're doing i know this is kind of a weird little system here but basically what we're doing is we're creating a new dialog object we're creating a new list object and we're passing in our two interface selection objects here and we are creating what our npc is going to say here and this is our uh index of this um speech here of this of this dialogue object so when we want to display our text since this is zero this is going to be the first one that gets displayed and if we were to select something and this were to say for instance zero when i select i do not want the quest it would go to one which would go to probably this one and otherwise it would go to this would go back to this one if that makes sense it's easier to show you than to explain it but that's kind of the direction we're going so let's go ahead and hit comma and say do the exact same thing here so i'm just going to go ahead and paste this so we have three of them and we will say whoops i have my caps lock on thank you so much for your help exclamation point and we're going to make this match this interface selection object here so we'll say one and in my case i want this to be two and then we're going to make this one two and for our objects we're going to make this object three and we're going to make this object 3 as well there we go and then i'm going to put a semicolon here awesome so i know that this looks kind of crazy but basically what i did was i created a way for us to be able to simply create and uh dialogue trees using this little method basically you just create your selections here you point them to your index and you can see here's our indexes here and if it's pointed to like for instance one when they select this one it'll take them to this dialog object this one is two so it's going to go ahead and take them to two right here and this little list here shows us which objects are going to show up so this one's going to show object 0 and object 1 and object 2 these two objects up here and this one is going to show object 3 which is basically just ok yeah that's fine and you can see that this one and this one are going to show the okay which will terminate our little script here so now that we have this we need to be able to display our dialog box so what we need to do is we need to go ahead and modify our player controller to uh detect if an npc is nearby so let's go ahead and take a look at our player controller here so we'll go to player.t or not tscn we'll go to playercontroller.cs and we'll go ahead and scroll up we'll say it about here and we're going to need to come up with a button for the user to use now i think we already have a button that we can use here but let's go ahead and take a look real quick go to project project settings and then go to input map and i think i'm going to go ahead and use the ui accept button here the enter key or in this case the space key but i believe i already have a jump so i'm not sure why i have ui accepted space let's go ahead and remove that i don't think we need that but it looks like we're going to go ahead just use the enter key to go ahead and talk to the user here so let's go ahead and hit clues and come to our player controller so we'll go here and we're going to go ahead and say if input dot is action just pressed ui underscore accept what we're gonna do is we are gonna go ahead and and get our npc so we're gonna have to go and find our npc so conveniently if i remember correctly we have um yeah we have left and right raycasts here so let's go ahead and see what the name of those raycasts are so if we click on our whoops i didn't mean to click on the script if we click on our player editor it looks like we have raycast left and raycast right is that correct yes it looks like raycast left and raycast right is the ones that we're looking for so so what will says will say hey if our node if get node raycast 2d quote left let's grab left raycast dot is colliding so it's going to say hey if our ray cast is colliding let's go ahead and see if that's an npc so node obj is equal to and we're going to cast that as a node get node raycast 2d left underscore raycast dot get collider what that's going to do is it's going to pull back our little raycast object that we collided with and we will say hey if our obj is of type npc then we know that we're colliding with an npc and we can actually talk to that npc so we'll say npc npc is equal to obj as npc awesome and then we need to go ahead and show our dialogue object here so so what we can say is interface con manager dot dialog manager dot show oh which one was it is it it's show dialog element right yes all right so what that's gonna do is when we get into the npc's range we'll be able to show our dialog element and now we'll go ahead and just grab this little bit of code here and we'll say else if and we'll pull all this and instead we're going to substitute this for right and right awesome so now let's go ahead and take a look at this and see if that works it might work it might not let's let's see what it does so well first things first we have our dialogue popping up so that's not okay so let's go to our player scene and grab our interface manager and hide our little pop-up dialogue because we don't want that up just yet let's go ahead and hit play and actually it might just pop up anyway yeah because we have code that is popping it up so let's go back over to our uh dialog manager and let's comment out this so let's go ahead and get rid of that awesome so now let's go ahead and hit play and it shouldn't play so if we run over here well first things first ah we just crashed so if i run up there and i hit enter it crashes get node left raycast relative to player not found so let's see what's going on raycast left oh my goodness i'm making all the mistakes today all right let's try this again all right let's try that one more time so if i run up there and i hit oh i fell off awesome so now you can see it came up which is good that's kind of what we wanted now one of the things that we've noticed a is if i try to run my character you notice that he runs but like he can't go through the the npc character right so that's a big problem so what we can do is we can go ahead and just have collision for the player or have the collision for the op for the um npc but let's go ahead and just throw them on a separate layer so we'll just throw them over here with our layer and our mask and then we're going to go ahead and allow our player to have collision here if i remember correctly that should work let's see if that works not quite i wonder if i need to disable collision here let's try that i might have gotten too far ahead of myself let's see there we go now if i hit enter you'll see that i can't hit it and the reason why is because they are on different layers so what i need to do is i need to go to my raycast and if i go to my player and i go to my raycast here these two raycasts need to have the second position here on their collision mask see how that's set differently now so now if we save that and we run this over here and we run back over there we should be able to talk to the to the player or to the npc you can see that we're behind the npc and the reason why is because the object that is at the bottom is on top of everything so if we just drag the player to the bottom like that he should be able to get behind the mpc now or in front of the mpc now and there we go perfect so now we need to draw this data from the npc so that way the npc can show us what uh he wants to say instead of just saying test name it test text so what we need to do now is we need to create a small um almost like a setting dialog option inside of our npc object so let's go ahead and create a function here so public void set npc dialog and then we'll go ahead and do interface manager dot dialog manager dot npc does it have one of those it does not so let's go to our dialog manager and we'll go ahead and create our npc dialog object so we'll say public list of npc dialog and we'll say npc dialog and we're going to say using system.collections.generic i can't type generic today there we go and that will allow us to call from it from here so npc dialog and oops not an object is equal to our npc dialogue there we go so what we're doing is hey we're going to go set the npc dialog object from our npc to our interface manager or to our dialog manager now we need to call this so the player controller is going to need to call this and say hey uh npc i want to talk to you go tell the dialog manager that you want to have a conversation with me so we will go here and we'll say npc.set npc dialog and then we're going to do the same thing up here and i know what you guys are probably thinking because i'm thinking the same thing this needs to be abstracted right there's no reason to have this copied code here right so let's go ahead and pull this out so let's come down here and let's create a whoops didn't want to do that let's create a private void show npc dialogue and we'll just have it do that which is simple enough and we'll pass in a object so it looks like it's going to be a node object and then if we come back up here we'll go ahead and just paste show npc dialog obj and then we'll do the same thing here there we go and that will just keep our code a little bit cleaner and a little bit healthier instead of us just dumping all of our code into um into an unusable mess that way if we want to make a small change we don't have to do it on both raycasts we can just do it on one instead of both so it helps with maintainability so let's go ahead and save that and now that we have that let's go out to our dialogue manager so we can come down into our show dialogue elements section here and we can just go ahead and say npc dialog and we'll just go ahead and throw zero in there right and that will allow us can be convert to string oh yeah and we're going to need to pass in dot display text and if we go ahead and we run this to go ahead and test our work we can come over here once this loads we're going to run over here we're going to enter and you can see help i need you to help me right he's freaking out he's having a good time right so that's perfect that's what we want right it's pulling back the data that we needed so now that we have that we need to make this a bit of code reusable right because we don't just want to show our dialogue element show the first element right we need to be able to make this uh interactive right and changeable so let's go ahead and throw a new function down here so let's say public void right and we'll pass in a npc dialogue and we'll just call that dialogue awesome and i probably spelled dialogue wrong i don't think so i think i'm good all right so we're going to have a public void right dialog npc dialog dialog and we'll go ahead and we'll grab this control c and we'll paste that in here and instead we are going to say it is equal to our dialog dot display text great and now instead of just passing here i'm going to take this and i'm going to put this here and i'm going to say right dialog and we'll say npc dialog and we're going to go ahead and put 0 in there so now it's going to pass in our first indexed uh npc dialog so now what we need to do is we need to actually display our selection elements so as you guys know we have our interface selection object here right as a cs right and we have our interface selection scene here but we also need an object for that interface selection to have right we almost need a a an additional object that holds on to our interface selection object if that makes sense so if i open up godot here and i go to our interface manager actually if i just go down here and i go to interface selection you can see that the interface selection does nothing it has no scripts attached to it so let's go ahead and attach a script to it and let's call it interface selection dot cs which works perfect for us and we will go ahead and go into that so the first thing that it needs to do is it needs to know if it's currently selected right so public bool will say selected we're going to go ahead and default that to false it might already default to false but let's just go ahead and do that and we also need to know what interface selection object it currently is so we need to say public interface selection object interface selection object and then we need to say uh on ready this dot get node and we're going to go ahead and grab our i'm assuming our label let me see what we have we have a label yep so we're going to go ahead and grab our label so we'll say label and then we're going to say label i believe it's lowercase l yes it is awesome so we'll say label and we will say dot text is equal to interface selection object dot selection text and then we should have a way to set our selected so public void set selected bool selected and we're going to go ahead and say selected is equal to selected so now that we're in our dialogue manager or first going to do is we're going to say for each var item in dialog dot interface selection objects and we're going to go ahead and instantiate our object but we don't actually have an object to instantiate yet so let's go ahead and go up to our top and do a little export here and let's say public um packed scene interface selectable object and we will come down here and go ahead and instantiate that object so we're going to say interface selection interface selection is equal to is equal to interface selection interface selectable object dot instance as interface selection and we need to capitalize that i all right and that's just going to pass us back an object after it instantiates it so that way we can work with it now next we have to say interface selection dot interface selection object is equal to item so that way we can uh go ahead and assign our interface selection object to our item or i guess our interface selection object yeah to our item our item to our interface selection object whichever and then we're gonna go ahead and say get node so we're gonna go ahead and get one of our sub nodes and we're gonna go ahead and grab popup slash in our case it is going to be popup slash hbox container we'll make that hbox container and then we'll add this my apologies dot add child and we're going to go ahead and add our interface selection here as a child object and then we need to go ahead and keep track of what selection objects are currently showing so let's come up here and say public list of interface selection objects and we will call them selections and we'll go ahead and instantiate it on startup so that way it just creates it we don't have to worry about it exploding anything and then we'll come down here and we'll say selections dot add interface selection that's going to go ahead and add that object and you can see that it says interface selection could i convert interface selection to interface selection object that's because that's my mistake this should be interface selection so we can keep track of what we have there we go and i don't want any of the objects to be selected so i want to make sure that they're not selected and that we blow away any previous selections that we've had so we're gonna say interface selection dot set selected and we're gonna go ahead and set that to false so that way it's no matter what's going to be defaulted to false i know it's already defaulted for to false but i just want to make sure so now that we have this this should instantiate our selection object so let's go ahead and take a look and see if it does if i come over here i hit enter and we've got a crash a hard crash too we go to here and it says hey no reference something's null right well what's null is that we don't actually have an interface selection object to instance so at least it's getting to this code which is good but it's not uh handling our little null here because our dialog manager here has an empty interface selection object so we need to go ahead and grab our interface selection scene here and drag that in here now if we go ahead and hit play we come over here we jump enter and you can see that they're a little bit on the law on the large sides so let's go ahead and either a expand the size of these or b reduce the actual words that we're using so let's go ahead and say instead if we go to npc and we change this from i do not want the quest to i can't help and let's do i will help we'll just make it a little easier a little smaller words so that way it's easier to work with awesome so now that we have that let's go to our dialog manager here and let us go ahead and set our first element as selected so what we need to do is first we need to go into our interface selection object here so if i focus in on that you can see it right here you can see we have a text erect here right now it's empty so let's first open up krita and let's go ahead and add in a new uh image here let's make it 16 by 16 which is about perfect and let's just kind of draw an arrow so let's just do something like this that's not too shabby for my first attempt here so let's see i'll probably make it more cursed as i go there we are and it's a png so we can actually just pull our background and now if we go ahead and save this in our celeste like tutorial let's make this a png and let's just call this selection cursor all right so now what we can do is we can say selection cursor is on our texture rect and we will go ahead and re-import this as a 2d pixel object there we go and we're going to go ahead and make it keep centered so that way it's centered and that looks like that'll work perfectly and what we're going to do is we're going to go ahead and hide it by default and we will save so now what we need to do is we need to go into our interface selection object and when we set our selected we're going to go ahead and get if our object is selected what we're going to do is we're going to get node and we're going to say our or we're going to call it a text erect and we're going to go and get our texture wrecked here so it looks like it's literally just text direct so that's fine dot visible is equal to true else we're going to go ahead and set the same thing to false so that should by default show us no selection objects if we come up to him and we run up and we hit enter there will be no selection objects available you don't see it but what we can do is we can go into our dialog manager and we can say selections zero dot set selected true and now when we run this and it builds we can come over here and hit enter and you will see that we have our little selection object here awesome i probably should be black to be honest with you i don't think blue works here um so maybe i should go update that to black um i just don't think blue works in this case so let's go ahead and set that to black there we go and uh now that i'm looking at it let's just kind of pull this like that that way it's a little bit nicer and we'll just go ahead and save that over so now if i hit play it should reload everything and if i hit here you'll see we have our black little line here perfect that's exactly what we need so now that we have that we need to disable our ability to move and what i mean by that is if if i run up here if i click on here and i run up here and i hit enter i can still run i can still jump i can still basically do everything that i could if uh i wasn't um in a dialogue right so what we need to do is we need to go ahead and make the player stop uh doing stuff if the um dialog box is up so what we can do is we can go ahead and go into our game manager and make that decision so remember how the game manager kind of houses everything that's important right it houses all of the major components and all of the uh thing that affects everything in the game right so if we wanted to pause the entire game we could through the game manager right so what we can do is if we go ahead and create a boolean up here we'll say up here we'll say public bool paused is equal to false we'll say game paused all right and if we come over to our dialog manager we type game manager dot you notice that we can't actually access our game manager from here right because it is not a static object so let's go ahead and use one of my favorite little tricks to make our game manager global so we're going to do is inside of our our uh game manager here what we're going to do is we'll say public static game manager and we'll say global game manager now i know that there's probably some better way to handle this inside of godot but i always like to do things just this way um and if you guys have a better way just go ahead and tell me but uh what i'm gonna say is hey if global game manager is equal to null then i'm going to go ahead and say global game manager is equal to this and the reason why i'm doing that is because i'm literally saying hey this is my global game manager else i am going to remove my game manager that way i never have two game managers in the project at the same time they're always just one a single source of truth so now what we can do is we can come up to our dialog manager and we can say gamemanager.globalgamemanager.com is equal to true and now that we're saying that we can go to our playercontroller let me save my dialog manager go to my playercontroller if we come up here and we go into our process and we're saying hey health does not equal zero or gamemanager.globalgamemanager.gamepaused.com does not equal true then we will allow you to be to do things so basically i am shutting off the ability to do anything inside of the player while the game manager says the game is paused so if i come over here and i hit play and i hit enter hope it didn't seem to work so let's see why it didn't work oh i see or and so i need and there we go i've been coding in python lately so i've been typing and instead of doing the and and so if we come over here and we hit enter you'll see that i can no longer interact with my player now you'll notice that our animation is a little weird so we got to figure that out but it looks like that will work for us so let's do a little bit of backwards coding here so we'll say else we must be paused or dead right so we'll play our idle animation there it is animated sprite dot play idle so we'll just go ahead and throw that in here and that should allow us to play our idle animation now the reason why i'm doing it this way instead of calling something else yeah see there we go now it's idling is because i don't want the game to completely pause when a dialog box is up i'd like to character enemies to to exist and things like that and i'd like the idle animations to play so that way the world seems more alive instead of just pausing everything so now that we've got our selection options running we have our character not moving and we have our stuff populating now we need to get our selection system to work fully so that is going to be a whole nother process so let's go into our script here let's go to our dialog manager here and let's uncomment this little bit of code here so if we type toggle line comment and we tab this over that will allow us to go ahead and use our process so what we're going to do is a i'm going to check to see if we're paused so hey if gamemanager.globalgamemanager.compaused all right so if the game is paused then we're going to allow you to interact with the dialogue but we don't but there's a possibility you might want to pause the game for another reason right we might want to pause the game because for like a setting screen or for maybe a power-up screen or something that's not an actual dialogue right so what we need to do is we need to create a boolean up here so we'll say private pool is dialogue up and we'll say hey we also want this and we want dialogue up and we're going to come down here to our dialog object and we're going to say down here is dialog up is equal to true there we are that way we can go ahead and make sure that we can interact with our dialog while having more flexibility so now what we're going to do is we're going to come up here and we're going to say if input dot is action just pressed and we will say ui underscore left and what we're going to do is we're going to say if item is for each var item in selections i believe we have that yep okay uh if item is interface selection item dot set selected false so that way if it's been selected it is no longer selected then what we're going to do is we're going to say um then we need to go ahead and kind of move our cursor to the left right so we need to go down our interface selection object if that makes sense so we almost need a rolling total of what our current index is so let's go ahead and do that so let's say private int current selection index and we'll just make that equal to zero by default and then we'll come down here and we'll say if it's left current selection index minus equals one and then we'll say hey if the current selection index is less than or equal to actually we'll say less than zero then what we need to do is we need to make current selection index equal to zero so that way we can't go past our index if that makes sense because we only have zero to whatever right so we can't go past what our we can't go past zero or else we won't have that index anymore if that makes sense so now what we need to do is we need to say selections and we'll put our current selection index dot set selected and we will set it to true so that's going to do is that's going to go and pull our index of our selections and say i need that one to be selected and now what we're going to do is we're going to say else if input dot is action just pressed ui underscore right and then we're going to say the same basically the exact same thing we can pretty much just copy this code here and paste it and instead we have to say plus flip our sign and what we can say is hey if it's above our select if our selection index is above our selections dot count then we need to make it equal to selections dot count minus one and the reason why is because the count that we're going to get back is going to be a number from one to um to whatever the count is but our selection index that we're expecting is supposed to be zero to whatever so it's a base one versus a base zero so that's why we are minusing one here and we're going to go ahead and set that selected so now if we hit save in theory providing that we've set up everything correctly this should work for us moving our little selection icons so let's go ahead and go here and you can see if i hit left and right and we just gotta crash but let's keep checking this out real quick and let's see why it's crashing but you can see if i go left and right it seems to be good but if i hit left twice it's good if i hit right twice it's not good why is it not good if i hit right twice it says hey system argument uh out of range index was out of range must be non-negative or less than size of collection and the reason why that's a problem is because when we increment our selection okay it's getting above our selections count so we need to see why that is and the reason why is because we need to say hey if it's greater than selection count minus 1 which is exactly what we did earlier remember we did that up right here right and the reason why is because again it's a base 1 versus a base zero so if we go back and we try that again we come over here now and no matter how many times i hit right you can see in the bottom right hand corner it's not going to blow up our little selection system perfect that's exactly what we wanted so now that we have that now we have to create some magic and what we need to do is we need to have our element start displaying the next element if that makes sense so if we come over to our dialog manager and we say hey else if input dot is action just pressed ui underscore accept because that's our enter key and we will pull that up like this and we'll create our little if statement here we need to create a small function that allows us to um to display our next dialogue element right so what we can do is we can come down here and say private void display next dialog element and what we're going to do is we're going to pass in the index of our selected element so what that will do is it will allow us to pull back our npc dialog object so what we're going to do is we're going to say hey if our npc dialog dot element at or default index and you'll see that it's upset with us because that doesn't actually exist but it is totally a thing right we are missing an assembly reference okay so we need to scroll up to the top and we need to pull in system.link and if you don't know what system.link is it is the best tool that you will ever see in c sharp so i'll pull that in and what this does providing i spelled it correctly let's see if i did dot element at or default i did okay cool um what that does is it says hey pull back an element at this index or if it's not that pull back a null object so that way we can actually check hey is this a null object did i make a mistake as a coder and not put the correct object in there or does that location not exist right or we can say if index is equal to -1 now i know you're going what what is this all for well the reason why we're doing this is a we want to make sure that the npc dialog exists that we're trying to pull back and b we're going to see if the index is negative 1 because negative 1 means that it's an invalid index and that means we probably want to close our dialog box so we're saying hey if it's null or if the index is -1 let's go ahead and close our dialog box what we're going to say is we're going to come up here and we'll create a small private function called shut down dialog and what it's going to do is it's going to allow me to say get node pop up and we will say quote whoops we'll say quote pop-up dot hide great and then we're going to say gamemanager.globalgame gamepause is equal to false and then we're going to go ahead and close our dialogue so dialogue is dialog up is equal to false and then from here we can call that so shutdown dialog now if it's not null or it's not -1 then we can say else we know that that index is a good index so let's go ahead and say write dialog and go ahead and pass in our npc dialog at that index so what does all this do basically it just lets you go it lets you select your dialog here then it's going to pass that index into here and say hey go fetch our npc dialogue at that index so if you remember back in our npc we have these little dialogues here that say these are the indexes that this dialog object is at so if i go ahead and i go here and i come over here and i play it and we run over here and we hit enter and i say i will help you'll notice that nothing seems to happen see that but what if i go ahead and i say let's go up here and say let's go to here and here and let's see if there's anything wrong here so let's go ahead and close godot and let's go ahead and run and debug this let's see what's going on so godot is going to pop up we're going to run over here we'll hit enter and we will pick i will help i can't help and it looks like almost like this isn't getting connected let's see oh that's because i didn't code up here well that would be why it's not working so let's go up here i totally forgot on this so we'll say display next dialog element and we're gonna go ahead and pass in our selections dot our selections and then our current selection index dot our interface selection object dot selection index i know that's a huge mouthful but basically what it's doing is it's going and fetching our selection object at that index so it's saying hey go get our object that we have selected then go out to that object and pull back its selection index so now if i close this and i play it without debugging let's see if this works we run over here oops we run over here we jump i will help thank you so much for your help but you've noticed something i will help i can't help it okay if we hit okay it now it's now whoa what's going on you know it's it's freaking out right why why is it freaking out right well the reason why it's freaking out is because a we're not deleting our our dialogue elements right you can see they're just duplicating so that's our first problem so let's take a look at that real quick so we write our dialog and we write our interface selection objects we don't go through and delete our previous selection objects right so we need to go ahead and delete those so we're going to do is we will say for each item in get node and actually i'm going to go ahead and make this a node item in get node and we will say uh node because i don't know what it's going to be necessarily i mean i have a good idea of what it's going to be but i'd rather just err on the side of caution and we'll say here slash pop-up slash and if i remember correctly we called it hbox yeah it's right here hbox container right there and then we're gonna say dot get children all right and then we're going to go ahead and i need a capital n here we're going to go ahead and query free that so item dot q free there we go so that should fix our small bug here where we're going ahead and um basically just uh duplicating objects so that kind of worked we got an error here cannot dispose of access objects so that's not a great thing um or cannot access disposed object so if we come back here uh something's blowing up right like oh no see you can see it's cannot access disposed object well what's going on is we're deleting our object when we write our dialogue but we are not pulling the object out of our selections objects so let's go ahead and go to our selection objects so selections is equal to a new interface selection object so now that we've done that it should go ahead and delete that list of objects basically think of it kind of like we're still holding on to those selection objects but they don't exist in godot's world so we're trying to access it and godot is going i don't have this object so now if i select this perfect that seems like kind of what we want but now we've got a system out of range must be non-negative and it looks like our interface is not getting deleted properly as you can see if we run over here so that's our first problem our second problem is if i hit i can't help and i hit ok on our left side it seems to go put on us it kind of blows up our entire program and let's first deal with our enter key stuff so first things first if we play this in editor and we have our two breakpoints here providing that godot wants to cooperate just good i want to cooperate well i'll be right back since godot's kind of crashing on me i'll be right back all right so if we run over here we jump we hit enter i will help you'll see that we have a break point here so let's take a look right npc dialogue that's what we wanted so go ahead and run through great hit okay shut down dialog that's exactly what we want so if we go in it runs through here it hides our pop-up and then it says is dialog up is false and then it runs through but for some reason it's coming back up why is that right well here's the reason so we're running through here we're setting our pause as false and then later in our script execution we are executing our player controller here and our player controller is running through here and saying hey i'm going to go through here i'm going to process my movement oh they pressed enter and now i'm going to do this little bit of code here so the npc dialog just shows back up right so what we can what can we do about this well what we can do is we can tell the dialog manager to go ahead and wait until all of the code has been executed and then continue so what we're going to do is we will come up to the top of our code for our process and we're going to say hey public async override and what that's going to do is it's going to tell c sharp to say hey run this whole section here off on its own go do its own thing i want you to just go do by yourself and don't let anyone else tell you what to do go do your thing okay and it's just gonna go put it off in its own little space and then what we're going to say is we're going to say hey i want you to await for a signal okay so two signal we're going to say get tree because we got to tell what signal we want to wait for and we are going to await for an idle frame now what is idle frame idle frame is the last thing that gets called out before a frame is finished so all script execution has completed everything is done it broadcast idle frame and then this is going to say hold on a minute i need to run my stuff real quick so now if we go over to our godot game and we run over here and we try it it should allow us to close our interface object perfect now we just need to figure out why it's crashing when we hit enter on our object here so let's see what it's doing so if we go ahead and debug our project so we go hit play an editor and let's see what happens when we attempt to hit ok on our second half so let's see what it does we run over here we hit enter i can't help it's going to write a dialog saying oh hey sorry you can't i'm that sucks please help me hit enter alright so it does not even get to this section so that's our first problem so we know that much now so now the question is when we hit enter here and we'll we'll go here i guess is it putting on so let's go ahead and play an editor let's run over here let's jump enter i can't help display next dialogue we know this one works so that's okay continue okay all right now let's see what's going on so what is our current selection index so this this now if there's one thing i don't like about c sharp uh for godot is this whole section here is kind of a mess you gotta like work around almost what um you know what it's looking for and i can't really hover over this and like you know debug like i can in visual studio so i'm assuming that it might be a visual studio and slash godot issue but what we can do is we can search for our current selection object so current selection index is one so in selections if we go find selections our count is two our count is one here zero so our index is one our current selection index our current selection index is one but our selections is looking for a zero so that's what's going on do we need to reset our selection index let's go ahead and check that out so if we say uh on right dialog selection index current selection index is equal to zero and let's see if that go ahead and fix it so let's kill that let's go ahead and come over here because it's possible that uh because we went to our right when we incremented our selection index if we hit enter that was what it was so what was the problem okay well the problem was is we hit over so we incremented our selection index to one we hit enter and our selection index was still one and because we did not move our selection index left or right our selection index was still one so by setting it to default to zero it fixed our problem this has been quite a journey to build this small little thing hasn't it but we are making great progress now there's one last little thing that we need to do and that is we need to set up the ability to see our npc's name here test name is not the correct name of our npc something else is right so let's go to our npc here and we will come over here and we will go ahead and create a private string and we're going to say npc name and uh we will go ahead in our constructor here we're in our ready we're gonna say npc name is equal to bob because bob is the best name set npc dialog so we're going to come over here and we're going to need to open up our dialog manager here if we go to our dialog manager we scroll up here we'll say private string dialogue actually it'll be a private public we'll make it public public string dialog header and we're going to come down here and we are going to set our text to dialog header there we go so now the npc can say here interface manager dot dialog manager dot dialog header is equal to npc name there we go so now if we come into godot here make sure i saved i did save save save yup yup yup if we run over here and we jump and we hit enter you will see it says bob now help i need you to help me i will help you thank you so much for your help i can't help you please help me perfect all right guys so that's all i have for you guys today i know it's been a long tutorial but it's worth it once you get it fully going so we went through how to set up a small interface manager and dialog manager we set up a small npc conversation system and we set up a selection system that allows you to run through some npc prompts now uh in a future tutorial we're going to go ahead and save the states of the npcs and things like that and pull back more data and stuff like that to make it more dynamic but right now at least we have it started so if you like this video go ahead and hit that like button hey you know if you dislike this video go ahead and hit that dislike button because i am here to make content for you guys and this was a viewer request so i do listen to you guys so if you guys have any ideas for future tutorials go ahead and throw them in the comments below and i'll be more than happy to throw them onto my trello board and make them into future tutorials now the next step for our uh c-sharp tutorials is going to be doing moving platforms and then we'll be moving into doing a small camera system but for now guys that's all i have for you today so thank you so much again for watching and i will see you all next time [Music] thanks [Music] you
Info
Channel: FinePointCGI
Views: 591
Rating: undefined out of 5
Keywords: godot, godot engine, godot tutorial, godot dialogue system, godot dialogue system tutorial, godot dialog system, dialogue, godot 2d tutorial, create a database in godot, godot dialogue, godot game engine, godot dialogue box, godot npc dialogue, godot talent system, make a database in godot, godot beginner tutorial, godot ability system, godot ui system, getting started with godot, godot skill system, C# Godot | Creating a Scalable Dialogue System
Id: kD2ODPRlQ_0
Channel Id: undefined
Length: 100min 35sec (6035 seconds)
Published: Mon Jul 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.