Revamping the UI: Select Your Level

The Level Select Screen required the largest amount of updating when we tackled the UI changes.  We went from a simple grid that placed all of our levels in one screen to a system that divides our levels into panels that can be swiped to reveal each other group.  The staggering change can be shown below.

BeforeAndAfterSpringItUI.png

Additionally, the panels could be changed by dragging the slider bars across the screen as shown in the picture below.  These slider bars would be stored on the right and left of the screen, but only two would be visible on each side at most.

Spring It Sliding across.png

You will notice, during the drag across, the red bar moved to the left and occupies the green bar's previous spot.  The yellow bar will then push the blue bar to the left as it snaps into its place on the left hand side. 

Creating this effect was the most challenging aspect of this screen and required me to learn a lot about NGUI.  Laying out the GameObjects in Unity's hierarchy was crucial to how this screen functioned.   The two pictures below highlight how the GameObjects were arranged for this functionality.

 Heirarchy

Heirarchy

The picture on the right shows how the slider bars were able to be moved across the screen.  Two scroll views were created, one on the left and one on the right.  These scroll views overlapped the main panel only slightly, the width of two slider bars.  This is the only section of the scroll panel that is visible to the player.  The rest of the scroll view stores the remaining slider bars to either the right or left of the panel depending on which side of the panel it is on.  Each slider bar's movement was constrained in the vertical direction but was treated as a DragAndDropObject for NGUI's sake.  Next, to prevent the slider bars from stopping mid drag, I made drop container's for each scroll view that occupied roughly half of the panel.  these drop containers take any DragAndDropObject that is dropped into them and stores them in an associated scrollview or table.

With that I was able to drag the slider bars across the screen, from one scroll view to another.  But before I was finished, I encounter one small issue.  The user could select the EITHER of the two revealed slider, thus messing up the order of my level panels.  To stop this, I created a click guard (just a collider) that would be placed over the slider bar I did not want clicked, thus stopping any click event from being passed to the slider bar below.  The next step was to hide or reveal each panel when the slider bar moved from one side of the screen to the other.  This was accomplished with the function below.

//From Class LSSliderBar
void UpdateAnchorPosition(){
  
        float percentOfPosition;

        mCurrentRelativeX = transform.localPosition.x + Mathf.Abs((int)mLeftGridPosition);
        percentOfPosition = mCurrentRelativeX/(Mathf.Abs((int)mLeftGridPosition) + Mathf.Abs((int)mRightGridPosition));

        mLevelGroupReveal.SetRevealPercentage(percentOfPosition);

        if(mLevelGroupHide !=null){
            mLevelGroupHide.SetHidePercentage(1 - percentOfPosition);
        }           
}
//From class LSLevelGroup
public void SetRevealPercentage(float currentRevealPercent){

        gameObject.GetComponent<UIPanel>().leftAnchor.absolute = (int)(mMaxPanelOpen * currentRevealPercent) + mStartingLeftAnchor;
    }

In the code, you can see that the slider bar checks its position relative to the total distance it can travel across the screen and then sends its percent of progress to the panel that is being revealed or hidden.  This panel's anchor is then changed accordingly.  The anchor on the panel must be changed rather than the texture behind it so I could achieve the sweeping effect.  If the texture in the background was parented to the panel and/or the texture's anchor was changed, the texture would scale down or up when the slider bar swipes across.  This was not what I was looking for and it does not look good for our game's aesthetic.

With the sliding effect finally working, I only needed to make sure the levels icons would spawn in on their correct panels.  That is where the LSLoadLevelGroup script comes in.

public void LoadLevelGroup(int currentSuffix, int endSuffix){

        Transform gridTransform = levelGrid.transform;
        levelGrid.columns = mNumberOfColumns;
        
        int currentLevelSuffix = currentSuffix;
        string levelName;

        for(int i = currentLevelSuffix; i <= endSuffix;i++){

            levelName = this.levelPrefix + i.ToString();
            GameObject newLevelItem = GameObject.Instantiate(this.levelItemPrefab, Vector3.zero, Quaternion.identity) as GameObject;
            newLevelItem.transform.parent = gridTransform;
            newLevelItem.transform.localScale = Vector3.one;
            newLevelItem.GetComponent<UILabel>().text = i.ToString();
            newLevelItem.GetComponentInChildren<UITexture>().mainTexture = mMenuLevelItemTexture;
            
            MenuLevelItem menuScript = newLevelItem.GetComponent<MenuLevelItem>();

            menuScript.levelToLoad = levelName;
            menuScript.levelLoadInt = i;
            LevelLoader.instance.AddLevel(levelName);
        }
  
        this.levelGrid.Reposition();
        mLSLevelGroup.StartLevelGroup();
    }

LSLoadLevelGroup is a relatively simple script that accepts two integers, the start and end suffix of the JSONs it will load, and outputs a table with 10 level icons.  I have one other script, LevelSelectLoader, that would distribute these integers to each of the level groups.  With these two scripts, the levels loaded in perfectly and we have a variable system ready for when we push past the current 40 levels.

The video below shows off the final product of this code. The screen is not complete yet, but is functionally close to how we envision our final product.