Bloop Boop is a 2D physics based arcade game for android, boop your bloop to the end of the levels!

Post news Report RSS Technical Design Blog: Creating a Menu System in Unity

This is a technical design blog by one of our programmers about the design of our menu system in Bloop Boop.

Posted by on

Over the past few weeks, I have been developing a game called Bloop Boop with 2 other Studio3 students. This game is a 2D physics arcade game being created for the Android phone to be published on the Google Play store. This project needed a system in which the player could cross between different menu panels whilst avoiding scene transition. This is a mobile game, so we were wanting to avoid as much lag as possible, having a simple system that can display different UI menu states and transition between them without using much processing power to transition was what we wanted.

I began this part of the project by looking at how we could easily hook up the system for testing and implementation. The graph shown to me by the designer made this necessary as a simple setup of the final idea was crucial in limiting the amount of time we would need to set it up:

image05.png

A little while into development I was able to talk to the designer about limiting the menus, this was mostly about the multiple menu items with similar stuff that we can use code to adjust and the scenes that were redundant with the design changes.

Once I began writing the system, I used a FSM(Finite State Machine)-eske approach, except it is just 1 state and multiple UI objects having their value unique. The controller for this I called the MenuStateMachine(MSM) which holds data for the current menu state which I called the MenuState. The MSM has a method that would take a single integer for moving to another state, which would call a method within the current menu state which would return what the new menu state would be. In the MenuState method I called, it would set up all the buttons to be pressed by the player. The way it would do this would be accessing the onClick variable in the button and supplying a lambda function which takes no arguments and has the code to run the MSM’s single integer method:

MSM:

 public MenuState curState;
 public void MoveTo(int index)
 {
 menuPath.Add(curState);
 MoveState(curState.MoveTo(index));
 }

MenuState:

 public List states;
 public MenuState MoveTo(int index)
 {
     //ReleaseButtons();
     AssignButtonIndices(states[index].state);
     return states[index].state;
 }
 public static void AssignButtonIndices(MenuState state)
 {
     for (int index = 0; index < state.states.Count; ++index)
     {
         int index2 = index;
         //Debug.Log(state.states[index].button + " when clicked will call MoveTo in " + state);
         state.states[index].button.onClick.RemoveAllListeners();
         state.states[index].button.onClick.AddListener(() => MenuStateMachine.instance.MoveTo(index2));
     }
 }

The lamda function is within the method call of the AddListener method for the onClick variable. As you can see there is some extra stuff, such as the index2 variable being created to put into the lamda function and the accessing of the MoveTo method through the instance variable within the MSM class.

The index2 thing was simple once it was explained to me: the lamda function doesn’t act like normal methods in C#, it doesn’t keep track of the value I give it, it keeps a reference to the variable I gave it, so if I gvae it the index variable and the index variable counts up to 2 before exiting (state.states.Count may be 2), when the lamda function is run, it will use the value it currently has, which would be 2, since it has kept a reference of it. The reason this stumped me was because C# has values such as strings, floats, ints, and doubles as structs, stuff that can only be passed on by reference if you explicitly state it is a reference, whereas classes are always passed by reference.

The instance is just an instance of the class that I can use to easily reference what I want, it allows me to treat it as if I have a reference to it in the class I am currently working on,this is called a Singleton, something I should have lead with. This isn’t a generic Singleton though, so I have to do the same Singleton code for each class I want to have one:

public static MenuStateMachine instance;
void Awake()
{
    if (instance == null)
        instance = this;
    else
        Destroy(this);
 }

void OnDestroy()
{
    if (instance == this)
        instance = null;
}

the MoveState method in the MSM is just:

public void MoveState(MenuState newState)
{
    newState.gameObject.SendMessage("Exit",SendMessageOptions.DontRequireReceiver);
    curState.gameObject.SetActive(false);
    curState = newState;
    curState.gameObject.SetActive(true);
    newState.gameObject.SendMessage("Enter", SendMessageOptions.DontRequireReceiver);
    MenuState.AssignButtonIndices(newState);
}

All it does is deactive the old one, activate the new one, and sends the appropriate messages to the game objects of the old and new states. These messages are picked up by any game object deriving off of an interface called MenuSystemEvent which requires them to implement methods called Exit and Enter:

public interface MenuSystemEvent
{
    void Enter();
    void Exit();
}
Thanks for reading,

Dan.

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: