UNITY DIALOGUE GRAPH TUTORIAL - Save&Load Graphs

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everyone welcome to another unity tutorial in this episode we're gonna continue from where we left off at the first episode of the node based dialogue system tutorial so in the first episode we have created the graph and node so it was fully functional we were able to connect nodes create new nodes and stuff like that but we were unable to save and load data into the files now in this episode we're gonna implement this functionality and we're gonna do some customization so without further ado let's jump into tutorial let's continue from where we left off at the last part we were able to create nodes connect them and create branching structures also we were able to zoom in and out now this week we are going to add save and load functionality to our graph so let's close this we know and jump back to the writer then let's go to dialog graph script and add a few UI elements to toolbar that we created earlier let's start by adding a text field as a file name to do our graph then let's set its default value as new narrative for now additionally to update the visual we need to mark it as dirty otherwise text field may not update with the new value now we need to add a change call back listener to change the file name from UI but to do so we need to save it to a variable for this I'm gonna create a new string and call it as file name also I can set a default value as new narrative and replace our default value as follows now let's assign the new value to our variable when we change the file name from editor then finally we can add it to our toolbar okay if we go back to unity and open up the graph as you can see there's a text field and I'm able to change its value great now we can go back and add some buttons into Toolbar I'm gonna add a new button and pass a click event as a lambda expression I'll call a method named save data then I'll set the label off my button as save data I need to do the same thing for low data to stun now I can create those methods which I referred in lambda expression if I go back to unity we can see that we have these buttons showed up at the toolbar cool now we can actually start creating save related stuff let's close the graph then let's create a folder called runtime and now I'm going to create some c-sharp classes for data serialization first I'm gonna call this one as dialog no data then I'll pass a few properties into it this class will hold every single nodes data so we need to save node gooood than actual dialog text and finally nodes position in the graph then I'll mark this class with serializable attribute nice now I'm going to create another class called node linked data this class will hold data about connections between two nodes so let's add a property as Bayes node couid second we need to add the port name which connects those two nodes finally we need to add the other nodes good which is the target node and we will call it as target node gooood lastly I'll mark this one as serializable as well now I'll use no sterilised classes in a scriptable object called dialog container let's open up the script change its base class to scriptable object and since we're gonna hold all the node and the connection needing to this object I'm creating a list for both of those classes and finally I'll mark this class as sterilizable too cool now to actually save and load the scriptable object I'm going to create a class called graph save utility and I'll put that into the editor folder because we will use it only in the editor then let's open it up and start by creating a static method that returns a new instance of graph state utility this will make our lives easier when we integrate this to our toolbar buttons we got a need to get which graph view we're going to save so let's create a private property and pass the value in the static method then I'll create two methods as save graph and load graph obviously they need to get file name as a parameter to save and load the file good now let's go back to our graph class and take a look at our save and load data methods you know what actually we don't need to separate those methods for our purpose instead let's create a single method and pass a boolean parameter to distinguish saving and loading between them first of all I want to check whether or not this filename is empty if so I'll show an error message and return the method this way nothing else will be executed then I'm going to get a new instance of craft stain utility for this graph view since we already have a local variable created for the graph view we can just pass it as a parameter to this method all right if we want to save the data this if condition will call save graph method in the graph save utility and we'll call the load graph method if we want to load something now let's go back to unity and take a look okay as you can see if I try to say with an empty field it'll give me an error and doesn't save or load anything awesome now let's go back to save utility and implement the actual functionality first I want to cache the edge list as a variable this way I can access to my graph views connections quickly then I'll cache the nose but I want to cast them to dialogue node because we're gonna want access to node GU it inside of the dialog note class when we try to save them little data now we can go into the save graph method and start saving some data let's start by checking it is there any connection made if not we will not save anything then I'll create a new dialog container instance as follows ok now let's get the parts that connected just to be clear since every node supposed to have a single input port regardless we are only saving output choice ports which means if an output port is connected to an input port we can count it as a valid connection right with that knowledge I'll ear it or these connected ports and at the inside of this loop I'll get to output node and the input node of this connection since they can be casted to dialogue node class I can get there good and save the good as an identifier then I'll add a new element to my node links list and I'll pass output nodes gooood as BAE's note good in the constructor as the port name I'll just get two output ports name instead off the input port because input ports will always have the same name thus we can identify ports with outputs that means you can only have the same choice in your dialog node at once which makes sense finally I pass the input nodes good as target node good ok with that we are able to save connections between nodes now it's time to actually save the nodes let's create another for each loop and this time I'll iterate over all the nodes except the entry point note because enter point node will be in present regardless at the inside of the loop I'll add a new element to my dialog no data list and create a new instance as you can see this will hold all the individual node lists inside first off foremost I'll pass gooood as this items good in the constructor next I'll pass actual dialogue text from our dialogue notes dial-up text property finally I'm going to gather the position off this particular node I can do that by get position dot position variable I need to get the position individually because get position method actually returns erect rather than vector to position of the node then using unities asset database class we can save the scriptable object to our resources folder as follows now let's go back to unity and open up the graph and try to save oh we're getting an error message that indicates there's no resources folder exists in our assets folder so we can create the resources folder by hand or automate it through the code this way we don't have to create resources folder every time when we try to use the system in individual different projects to do so let's quickly go back to the code and check is there every sources folder exists in our assets folder if not let's create this folder then if I go back to unity and add few nodes to my graph and try to save it as you can see every sources folder got created and we successfully saved our graph data into a scriptable object awesome now it's time to load this data back to the graph let's go back to the writer and implement it first I want to cache our target dialogue container then I'll load the file from resources folder and assign it to our cached property next we need to check that is this file really exists or not with a null check then we will show an error message and return if the file is present this return will not going to be executed because the file is there which means we can proceed with few steps first and foremost we need to clear the existing Brad because we can have a remnant nodes and connections from old graph as the second step will generate nodes and finally we will be able to connect those notes which we created in this step 2 ok let's generate the first method quickly I'll start by finding the entry point in the graph and change its gooood because we're gonna have the entry point right after that when we open up the graph that's how we coated it in the first place remember so the first node link in our container will always be the entry point since first thing that we going to connect will always be the entry point right thus I can get to first elements go ahead and assign it to the entry points gooood then I'll iterate over all the nodes but entry point because I want to keep the entry point since it doesn't have anything specific to the graph besides for new good which we already changed then I'll get each output connection that we have made by this node as I explained earlier we only save output ports so we can validate that with if port is connected to another nodes input port there's a valid connection then I'll iterate over all those connections and remove them from the graph after removing all the connections we can finally removed a node from the graph now we can create our second method which is creating new nodes that exists in our save file I'll start by iterating over all the dialogue node data in my cache scriptable object in the loop I'll simply call create dialogue node method from my graph view class and I'll pass the dialogue text as the parameter after creating a new node we need to change its gooood to our saved nodes good then we can add this node to the graph view now it's time to create choice ports of this node we can do that by accessing to denote links of our cached and get port names which we saved earlier so to determine is this part belong to current node we make link query as follows then we will cast it into a list then now we can iterate through this list and add each of these ports to this node but we have two problems this ad choice port method is private and doesn't get a port name from outside well we can solve the first problem really easily let's convert this to a public method for the second one let's go to the methods definition and add an optional parameter as a second parameter to this method then a limbus string parameter is overwritten port name and pass an empty string is the default value so that existing calls to this method will not be broken now we need to use this parameter to display our port with the given port name okay well we're going to make an empty check off this parameter and if it is empty we will call the port as choice just like we have done earlier and if this is not empty we use the parameter from the outside then we can assign the variable to the port name alright since we are in the script we can make few changes to make things more convenient as you can guess in their dialogue system with different options we should have the ability of changing those choices right this is exactly what we're going to do to do that we're going to put a text field into this port and we will alter it inside of the node to do so we need to create a text field and pass the choice port name as the default value then I'll resist for a change callback that will change the port name when we change the text field from the graph and from the node now I'll create a dummy label with two spaces in it to bring a gap and I'll add this label along with the text field into the port's content container also quite naturally we should be able to remove this choice is from the editor to do so I'll add a button and call a new method called remove port then I'll pass the target node and the target port has parameters then we will add this button to content container as well now if we go back to unity we can create different options and change choice port names as well great now there's an enhancement that we can do which is removal of existing port labels well don't worry it's really simple it's not a rocket science or something we need to query in this ports content container to do so and to actually query in a UI element we need to use a method called dot q which is a generic function and we can specify type and name we are looking for in this UI element which in our case we're looking for a label named as type after gathering this Yan element we will remove it from the content container off our generated port now if we return to unity all the weird labels are gone and we can see and change our options wonderful and if we attempt to save it as you can see all these port names and choices will be saved into our scriptable object Cole Cole Cole now we can add removal of these ports we created the remove port method but we didn't code anything in it all right in there first things first we need to access to our edge list off the graph view and get the ports that has generated ports port name but this is not enough we also want to make sure that this generated port the lung star dialog node we don't want to delete the input port of other nodes right then if there's a port which matches to these requirements we get it using a built in c-sharp method called first so we want to get that edge and disconnected before deleting it otherwise we can delete the port but the line that show the connection will remain in the graph which we don't want it with that being said after disconnecting this port to remove the visual line we need to remove the edge as follows then finally we can remove the target port from output container after deleting a port as we usually do we need to refresh ports and the node visual to update its graphic now in unity we can remove both connected and haven't connected ports in our nose and if we try to load stuff without saving it we can see that those ports still will be there although as you might notice there's a problem the existing notes should be cleared by clear growth method which we created earlier seemingly there's an issue here let's quickly check it out alright the problem is we are returning the loop rather than skipping to the next element thus loop runs just once at the first element of our graph which is the entry point we can quickly fix it by changing the return to continue this way it'll skip rather than stop the loop now if we try to load a graph again as you can see it clears the existing nodes and connections and loads all the nodes awesome that brings us to last piece off the puzzle connecting these loaded notes together let's jump back to writer for it and create our connect nodes method we're going to start by looping through all the nodes in our graph view then we're gonna get the node links from L cache save file and match the gooood of connections between current node output nodes this way we can find is that node has any connections that's saved into the file then I'll create another loop which will be nested into this one and we'll loop through all the connections then I'll gather data about nodes that are connected together I can get gooood Street identify those nodes then after getting the connected node to current node I'll call a new method to link those port together I'm doing that by accessing two ports from output container off to connection together to matching output ports off curtain node of this loop and I'll pass the input port off the outer node as second parameter finally I'll set the position of the target node from the safe file that we have been using one thing to keep in mind that set position method wants us to pass the size of the note2 to set the default node size I need two acts as a parameter which we created in the first episode although we made it as a private variable in the first part so we are unable to access it right now let's go to graph view class and change its access modifier to public cool now let's implement linked nodes method to actually create an edge between glows ports first of all I'll create a new edge and pass input and output ports into it then I'll connect them as follows finally I'll add this edge into the graph thus I'll show a connection line between edges alrighty now we are really close to complete our dialogue graph system so everything related to save and load supposed to be working cool as you can see I have save and load graphs and it works like a charm one thing that you might have been wondering is where the hell is the actual dial-up text which is a totally righteous demand luckily it is really easy to add this dialogue text field since all data is already being serialized in our earlier work to do that let's go into the graph view script and find create dialog node method while creating the nodes we can also show dialogue text field into them okay let's simply add a text field and set its label as empty to reduce the clutter then register a new change call back in that callback we are going to assign the text fields new value to our dialogue notes dialog text property also I want to show the dialogue text as the title of the dialogue note so I'll pass it into the title property as well now let's pass the existing value of the dialogue node and the default value without firing this change callback using set value without notifying method this way the callback which we have created will not be triggered and value will be set finally I want to add this text field into the main container off the dialogue node which is the bottom of the note at the current state so as you can see now I can change the dialogue text also note that this value is being saved and loaded we have a fully functional dialogue graph now but we can do better for sure let's make some visual enhancements quickly let's add a new u-s-s file into the resources folder just like we have done in the first part and call it as node this time we can change the title color of the node this way let's open it up in use following the USS prep processor as follows but if we open up the graph we can't see anything because we haven't binded this stylesheet to our node to do so let's go back to create dialogue node method and add our node USS file to stylesheets as follows now as you can see we have green titles in our nodes one enhancement we can do is making this entry point node as not deletable any movable we can simply do that with going into the entry point creation method and change notes capabilities using bitwise operators any nouns as follows so if that makes you confused the only thing that you need to know is to remove something we use this syntax with a flagged enum now back in the graph as you can see we can't move or delete the entry point node which is quite appropriate since we need it to save and load the graph cool as a final touch let's add it meet them up into our graph don't worry unit it provides it by default which is super easy to use let's go to dialog graph class and add-on enable method let's create a new method called generate mini-map then I'll create this mini-map method and get a new mini-map instance as follows as I said this mini-map class is coming from unities embedded the graph view API which makes things super simple and efficient now I'll pass a parameter into it called anchored and said it's true this way mini-map will not float around when you click on it and stay anchored into the position that we set talking about the position let's quickly set its position and size with following values finally let's add this to our graph view good now let's go back to unity and as you can see we have a mini-map cool part of is it's fully functional you can see I can click on it and it'll take me to that node that I'm clicking well that looks really nice to me finally we are able to zoom in zoom out connect nodes and branches save and load them from files this is all the stuff we're gonna do in this episode in the next episode we're gonna make some optimizations a little more stylization then we can add a search bar to add nodes and we will implement the graph into a runtime gameplay alrighty that's all for this episode I hope you like it in the next episode as I mentioned earlier in the video we're gonna make further improvements we're gonna make it run in the actual gameplay and because we're gonna do some customizations so if you want to be notified as soon as that video is up I recommend you to be a subscriber to my channel that would be really really helpful for me and if you like this video you can press the like button if you want to see more videos like that you can as I said subscribe to my channel and share this video with your friends and your discord groups wherever you want to and additionally you can find the entire project so far in my personal github repo which will which I will add it to the description box is a link at the below so you can check that out as well I guess that's all for this episode and I will see you in the next one
Info
Channel: Mert Kirimgeri
Views: 18,811
Rating: undefined out of 5
Keywords: unity, game development, visual scripting, no-code, unity development, shader development, unity tutorial, node system, node based dialogue system, branching narrative, shader graph, visual effects graph, narrative based game, graphview
Id: OMDfr1dzBco
Channel Id: undefined
Length: 27min 23sec (1643 seconds)
Published: Thu Dec 26 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.