Revamping the UI: Main Menu

This post has been a long time coming and is part of a three part series where I will show all of the changes to our UI system.  After all of our UI changes to the main menu, the current setup is shown below.  A lot of these changes were purely art and design placement, but this post will focus on the programming required for the options menu icon shown in the bottom right corner.

FinalMainMenu

The options menu, when clicked, will first expand horizontally, then vertically to a set size.  This creates an expansion opening effect that looks great.  The fully expanded menu is shown in the image below.

Post Changes comparison.png

To create this effect I first started by laying out exactly what I needed to happen to make this effect.  

- Hide the Options Icon because that cannot be on the panel that expands. 

- Expand horizontally to a LerpTarget.  

- Expand Vertically to a LerpTarget

- Reveal the buttons.

Naturally, to close the same menu these step must be performed in the reverse order.

To Hide the Options Icon, I decided it would be easiest to just have another panel remains hidden until it is time to open.  At that point, the options panel would hide and this new panel would reveal itself.  The buttons, which also start hidden, were parented to this panel so their position would be unaffected by the panel's final expansion size.

Expanding the menu horizontally and vertically were both accomplished in the same manner, by Lerping the anchors of the NGUI widgets from a starting point to  the LerpTargets.  This proved relatively easy when opening the menu.  I would check at the end of each frame to see if the horizontal targets had been reached before continuing onto the vertical targets.  This is shown in the following code.

void LerpHorizontalLeft(){
        float lerpFraction;
        mCurrentLerpTime += Time.deltaTime;

        if(CheckIfHorizontalStarted()){
            mCurrentLerpTime = 0.01f;
            mCurrentLerpTime += Time.deltaTime;
        }

        lerpFraction = mCurrentLerpTime / mHorizontalExpandTime;
        if(lerpFraction >= 1.01f) lerpFraction = 1.01f;
        mMenuObject.GetComponent<UISprite>().leftAnchor.absolute = (int)((mLerpHorizontalTarget - mLerpHorizontalStart) * lerpFraction + mLerpHorizontalStart);

        LerpTransition();
    }

 

When I started trying to close the menu, I struggled to get the menu to close horizontally after the vertical had completed because the vertical lerp function did not have a way to transition back to the horizontal.  I made both the horizontal and vertical call back to each other if they both were not at their targets, but this was messy code that was quickly replaced when I encounter the next issue.

The menu button's position on the screen was not static for all scenes, so if I wanted to use the same code I needed to make it so the code could expand to the right or left and up or down.  I decided to standardize the design for the game my making the menu always open horizontally before vertically, and always close vertically before horizontally.  So to solve this problem, I created the LerpTransition() function that you can see in the code below.

void LerpTransition(){
        bool rightAtTarget = mMenuObject.GetComponent<UISprite>().rightAnchor.absolute >= mLerpHorizontalTarget;
        bool leftAtTarget = mMenuObject.GetComponent<UISprite>().leftAnchor.absolute <= mLerpHorizontalTarget;
        bool topAtTarget = mMenuObject.GetComponent<UISprite>().topAnchor.absolute >= mLerpVerticalTarget;
        bool botAtTarget = mMenuObject.GetComponent<UISprite>().bottomAnchor.absolute <= mLerpVerticalTarget;

        if(mIsOpening){
            if(mLerpHorizontalAnchor == "right"){
                if(rightAtTarget){
                    if(mLerpVerticalAnchor == "top"){
                        if(topAtTarget){
                            EndLerp();
                        }else{
                            LerpVertical();
                        }
                    }else if(mLerpVerticalAnchor == "bottom"){
                        if(botAtTarget){
                            EndLerp();
                        }else{
                            LerpVertical();
                        }
                    }
                }else{
                    return;
                }

The above code is a fourth of the entire function but shows us everything we need to see regarding this function.  I can set mLerpHorizontalAnchor and mLerpVerticalAnchor to the anchor I wish to move.  Then this function will go through checks to determine what step is next based on what steps have been completed.   This allowed me to greatly reduce the size of each lerp function.  I created 4 functions that lerp in the direction and mode I required: LerpHorizontalLeft(), LerpHorizontalRight(), LerpVerticalTop(), LerpVerticalBottom().  Each of these four functions refer back to LerpTransition so the program knows where to go next.  With the addition of this function the flexibility of the MenuOpenClose program increased greatly.  The additional control allowed is best highlighted through the variables shown below.

public string mLerpHorizontalAnchor;
public string mLerpVerticalAnchor;
public float mHorizontalExpandTime;
public float mVerticalExpandTime;
public Vector2 mFinalExpansionDistance;
public Vector2 mStartingAnchorDistance;

As you can see, the script allows me to set the start and end sizes of the menu with the mFinalexpansionDistance and mStartingDistance variables.  I am able to set the amount of time each expansion direction takes.  Finally, using mLerpHorizontal allows me to choose whether the menu will expand to the right or left, while using mLerpVertical allows me to choose whether it will expand up or down.

This program's difficulty rested in the organization and logical order of the code rather than the more typical math based challenges of coding.  I plan to use this code's functionality for many different applications and future games.

The full code is displayed here.