Overview
During the development of Scrapload, we decided to implement a radial menu for building within the game. This decision came to assist our goal of ease-of-use and reducing any hindrance to the player when they build. A radial menu is a lot more efficient than a regular button focused menu, where the fast reaction based menu compliments the gameplay we are aiming to achieve. It helps players when in the middle of a fight and in need of building support structures.
Goals
When posed with the challenge of developing the radial menu, not only did I want it to function correctly, but I wanted it to be flexible where we can easily add or remove different options from the menu as we moved through the project. I needed to figure out a way to have the layout and data be separate, so it is programmatically created. I also wanted the data to be easily accessible, so as we balance and change the features of the game, we can easily update the relevant data without having it be load-bearing in any way.
Approach
The menu is constructed of different button widgets that are created and added to the menu. These buttons hold all the relevant data to that selection type, such as:
Button image
Icon (selected)
Inverted icon (unselected)
Name
Subtext
Buffs and debuffs
Cost to build
This data is initially stored in a data table that we can edit at any time throughout development, which helps streamline balancing and gameplay changes. On construction, I cycle through a data table and generate each button and store the relevant data on it. When the player hovers over the button, the center information is filled with the data stored on the button widget, such as the name, subtext, buffs & debuffs and cost to build. But how do we position the buttons to know which one the player has selected?
Button Positioning
Setting the positions of the buttons first required me to find out the rotation angle, which was found by dividing 360 by the total number of buttons. So for 8 buttons, the rotation angle is 45. Next, I take the button index, multiply that by the division angle, and then convert the results from degrees to radians. The last step is to find the final X and Y position of the button. For X pos, I multiply the distance from the middle by cosine of the radians, and for the Y pos, I multiply the distance from the middle by the sine of the radians. The distance from the middle value can be adjusted, where the smaller the number, the closer it will be to the center of the screen
Button Selection
The most important thing when building this menu was to ensure that the player's mouse position is accurately being read, so that the correct button is being selected. To ensure this was the case, I converted the mouse position to screen space to get its X and Y position, and tested the center of the screen to see if it falls outside of the exit button.
Once we have our mouse position, we get the normal of its position to the center of the screen and dot that against the up vector (1,0). The up vector represents 0, which is where our first button has been constructed in our menu. The value of this dot product will tell us exactly how far around the circle we are. Next I get the inverse cosine of this value, which will be the value in degrees, and determine if it should be negative or positive, depending on the Y value of our mouse position. Finally we add 180 to this to shift the range from [-180 to 180] to [0 to 360], and subtract half the division angle to get our final selection angle. We then loop through all our buttons to find the button at that angle, by taking the division angle away from the selection angle until we reach 0 or below.
Dot product of up vector with mouse position [x]
Further Adjustments
As the game developed, new features were added that required more data and images to be added to the data table. This includes checking if items have been unlocked or if they are purchasable. Thankfully, with the data table approach I took when creating the table, adding in these new features was very quick and simple, and required a function each to determine if an object was affordable or unlocked.
Final Thoughts
Radial menus are really cool and very useful tools. It was fun trying to figure out how to make a crucial part of the game that can easily be iterated on without having to significantly adjust it every time a change was made.