top of page

Refactorization of my AI History Tool for Unity.

  • Writer: BrokePixel
    BrokePixel
  • Jan 11, 2025
  • 6 min read

Welcome back to those that are returning and greetings to those that are here for the first time! At the end of my last post I had mention that I wanted to refractor the way I was storing the data for the patrons decisions. I chose this because I foresaw issues arising when I would at some point want more data. I was at the time only using a struct that was held in a dictionary. While this was a simple thing it didn't allow for much flexibility in terms of viewing or storing additional data that would just take up space if it was unused. Also it would make the Editor window very cumbersome in that I would have to write code for each of the different windows I would need to display the additional data. I felt that this wouldn't last long once I started to flex the AI for the patrons and expand. So without further delay I will start with what I ended up doing as a solution. I will explain why I made which choices and where I struggled and where I think I could have done better.


Patron has been selected.
Patron has been selected.

If you are a returning reader, you might recognize the layout of the editor window but you may also notice a slight change to it as well. There are a few reasons why I kept it simple and rather than try something more complicated. The first is that I already had the basic structure for the window and rather than change it while changing the underlying structure I wanted to not self induce more problems that I didn't need to deal with. So here much like before we have refreshed the Patron List and we have pulled all the logs for each patron and we will display a time that the decision was made. Now this display is actually only the children's label for the selector window. So if you were to look at the patron in MSV you would see that under patron it would have these TimeNodes. Now this is important because the structure is no longer a struct but rather a Graph using GraphNodes for a base class.


GraphNode Base class Functions
GraphNode Base class Functions

Above you will see the API that I will use going forward to handle any subclass of GraphNodes. I bring this up because this was a particularly hard challenge to get correct. While at time I felt this could have been easier if I had been able to use C++ rather than C#, though I am sure that it would have come with it's own set of challenges. In either case, TrimBranch was a particularly hard one to get correct as I was effectively having to recursively call remove child from the lowest branch up to the highest.




Now during this process I ended up running into quite a few issues regarding the order in which nodes were removing and being erased from their parents. I dealt with a few being removed but would end up with a iterator error because as children were told to TrimBranch they also have to ask their parent to remove them from the parents list of children. So I had to account for the shrinking of the list and instead would just remove the first child till all children have been removed based on a count rather than iteration through the list. I also had to ensure to remove all references to the RootNode and the parent for all the children. This honestly took the longest to get right before I was able to move on to create more Nodes and start integrating the Class into my Editor window. So with this out of the way I had a way to manage the data and clear things that were no longer worth keeping.

So now came the time to start trying to build the graph that I was actually going to be using rather than just connected nodes. But wait how can I add to a graph that already existed and use it with the bank I had created before? Well in truth I just changed the Dictionary to use a Graph Node instead of the struct. This would allow me to still find the Patron I required using their PUID (Patron Unique ID). This is based off a static variable for the patron class that increments as Patrons are created. This wasn't my first assumption of how I wanted it to work. Originally I wanted to just use a "Master Node" that would have all the patrons as it's child. But I would have to loop thru and find the node that I would want each time that I would want to add or remove things from it. So this is why I ended up leaving the old structure of the dictionary and just change how things were stored.


At this point I have the data being stored and could access the correct patron that I would want. But the old Editor window was based off the struct and it would not be a good idea to continue with the way it was. While the Patrons window would stay relatively unchanged I now had to find a way to traverse up and down the graph that I have created and it had to be flexible enough that it wouldn't care what type of node that was being displayed as each node would only contain a set of info and I wanted to not have a ton of different windows for each node. So I knew I had to have a "SelectableLabel()" to be able to have the flexiblity for each node. Honestly this part was fairly straight forward. As I would traverse down the graph I would just rebind the labels and selections to all the children that were available. If there were no children I would just display "List is empty"


This is currently the DecisionNode which displays the choice and stats that a character had at the point in which they made their choice. Now this is the power of my structure is that I can add a ShopNode or some other kind of node it matters not. I would be able to insert more data. Such as what was the price of the shop or a list of all targets that were considered before the choice was made. Did they even consider something else? So we have managed to get to the bottom of our graph, now what? well I want to look at another choice that the patron may have chosen. Which is why I added the back button. As it will allow me to traverse back up the list to the same patron rather than having to reselect the patron over again get back to the top.


Back one from the Decision Node.
Back one from the Decision Node.

So here we are currently displaying the node from above as a selectable. We also cleared any data that was meant to be showing because if the node above also had data to show we would display that instead. This also made the tool feel cleaner and would make more sense as to what was going on. If we hit back once more we would be back to our time selections.


Overall I am pretty happy with the structure of the tool and it will allow for growth in such a way that it will make it easy to add more nodes type to display differing data without ever having to modify the Editor again just for a different node type. This has been a great learning opportunity in that I learned more about TreeView because it was also a consideration in using the Unity built in method. But I opted for what I did because it felt like the right choice in the long run. I was also able to learn more of the Editor Window for Unity and learned even more about toggles, buttons and other than that I didn't have a use for at the current time but I am sure the next time that I make another editor window I may have use for. Well that's all for now. I hope you have enjoyed the journey which was the refactorization of my tool. As always if you have questions or comments feel free to reach out to me.

Remember Take care of yourself and each other.

Till Next time Stay safe.

-BrokePixel

Comments


bottom of page