Unity Traffic System Tool Class Ver Postmortem
This tool was a tool made for my game portfolio class. The "Traffic System" is a tool made in/for Unity where you can add waypoints and agents will follow them. You can create branching paths, mark waypoints as "stop" or "building" points and the agents have an obstacle avoidance algorithm on them to help make the movement seem more natural as well as an fov (field-of-view) tool to help save on the costs of raycasts. This devblog goes over what I was able to get done in 3 weeks for the class, but I do plan on polishing and publishing it later on in which case an updated devblog will be posted and linked here.
The base of the tool is the waypoint editor. Here the user can easily create waypoints to then create a "walking path" that the agents can follow. Before starting this tool, I had some experience creating tools for the editor in Unity thanks to the development of my dialogue tool (which you can read more about here).
The waypoint tool has multiple functions. After setting a root waypoint (which is just an empty gameobject that holds all of the waypoints) you can either create a new waypoint, create a branching waypoint, create a waypoint before or after the current selected waypoint as well as removing the current selected waypoint. The "create waypoint before or after" is designed to be used on a waypoint that's between two other waypoints making going back and editing easier.
Each waypoint has a Waypoint.cs script attached to it. Each waypoint has a few variables including the waypoint before and after it, a list of branches attached to it, a bool checking if it's a stop point (think like a stop sign) as well as a bool checking to see if it's an entrance to a building and finally a float that stores how long an agent should wait at the waypoint.
Underneath those, there's two more floats with ranges which is width (how wide the waypoint is) as well as branchRatio (used to determine which branch to take). The script also holds a function GetPosition(). To be able to visualize it all, I use gizmos to have them appear in editor. Using lines to show the width of waypoints as well as their connections plus a sphere for the waypoint itself. A selected waypoint will be at full opacity while a not-selected waypoint will be at half opacity.
When it comes to actually making waypoints, there's 4 functions for each way to make a waypoint (mentioned earlier) with each following more or less the same method. When creating a waypoint it'll always spawn at the location of the previous waypoint. It not only takes the position of the previous waypoint but also the width, so the user doesn't constantly have to be adjusting each waypoints width. If it's a waypoint with no previous waypoint then it'll spawn at the position of the root and the width will be set to the default width.
When adding a waypoint before or after another waypoint, it spawns the same way but the previous and next waypoints for the connected waypoints are updated to adjust for the new waypoint automatically. A similar thing happens with the RemoveWaypoint() function, but instead destroys the waypoint after the connecting waypoints previous and next waypoints have been updated.
Creating a branch waypoint is a bit different, the waypoint is still created at the same location and width as the waypoint that you want to branch from, but is instead stored as a branch in a list of branches that each waypoint has that is then referenced for when the agent walks by. So one waypoint will add the branch waypoint to its list if branches to choose from, when the agent walks by it'll decide whether or not to walk on the branch, and it'll then follow the branch path. Each branch has two branch waypoints, one with a branch ratio of 1 to act as the exit branch. In case of a dead end.
The movement system for the agents are overall pretty simple. The function MoveToDestination() is called in the Update() function. From there it checks to see if an obstacle has been detected, if it hasn't then it calculates the direction to the destination. If it has, then it ignores this bit of code since the destination was already calculated from the Obstacle Avoidance() function earlier which is called from the FOVTool.cs script in the OnTriggerStay() function. The obstacle avoidance algorithm was made for my advanced game AI class which you can read more about here. The fov tool is a separate gameobject that is a child of the agent, which is what has the FOVTool.cs script on it and checks for collision. The fov tool is part of a bigger tool designed for testing I'm making for my capstone team, which once it's complete you can read more about here.
Once the agent is close enough to the target waypoint, then it skips the movement code and instead goes into checking for the type of waypoint it is. If the waypoint has no type then it just marks it as reached and generates the next waypoint. If it's marked as a stopWaypoint, then the agent will stop and wait for the designated stopLength the user assigns in the inspector. If it's not a stopWaypoint then it also checks to see if it's a buildingWaypoint, in which case the agent will become "invisible" as to make it look like it went into the building. From there it'll wait for the designated buildingTime (again assigned by the user in the inspector). Once the time is up it'll become visible again and move on to the next waypoint.
Obstacle Avoidance & FOV Tool
If you're curious about a more in-depth discussion on how the obstacle avoidance algorithm works you can read about it here. A quick overview on how it works however, goes like this: the fov tool is used to check for when an obstacle is nearby (you could also just do this with a simple box, sphere etc. collider, the fov tool just gives more freedom in the fov angle), once it enter the trigger, the WaypointNavigation.cs script will run the ObstacleAvoidance() function to calculate the direction which is gotten from shooting a raycast from the agent to the obstacle. Then as the movement script is called the direction is updated based on this function.
The fov tool is part of a bigger tool designed for getting more testing data from players, if you're interested to learn about how it works then once it's complete you can read about it here. A quick overview on how it works however goes like this: you add an empty gameobject child to the agent that has an fov on it and you attach the FOVTool.cs script to it. From there you can adjust the angle, distance, height and color of the fov, the mesh for which is generated in the code which updates in the editor. The collider is a trigger, so from there you just add whatever you want to happen when it hits the trigger in the script.
Polishing & Future Plans for the Tool
Overall, the tool is what I'd consider in an MVP state. It does what I set out for it to do initially and proves the concept. Besides adding in the ability to set an ultimate destination waypoint and have it be able to find a path to that waypoint through the other waypoints, as well as add another kind of stop waypoint where instead of starting from the top with it's countdown every time, it acts more like a stop light where the agent is getting the time left based on the waypoint and not itself. Outside of this I also want to make sure it can work well with cars/boats since I think that'd be a nice edition and really make the tool fit (what I feel like) is the most common areas you need a traffic system like this used.
Besides adding in a few extra features, most of the work will be polishing mainly on the obstacle avoidance algorithm. The obstacle avoidance algorithm isn't perfect, it can be a bit jittery and cause some other weirder bugs and from my tests it seems to be what's causing the majority of the bugs left. Once the tool is complete and available for sale, you'll be able to read more about it here.