Moving Into User Interface & Game Design in Unity

Home / Technology / Game Development / Moving Into User Interface & Game Design in Unity
Moving Into User Interface & Game Design in Unity

Summer is really heating up, and so my Summer of Code! I was able to successfully complete both of my goals for this week, though they admittedly took a bit more time than I had originally anticipated. It was well worth it, though. Over the past few days, I gained even more hands-on experience with C# while moving into more realistic game design with a proper user interface.

It was truly an educational and productive week. During this time, I created a new text-based game based on a post-apocalyptic choose your own adventure theme. Then I had the chance to take another look at the Number Wizard game before modifying and refactoring it to create a more user-friendly interface and positive gaming experience.

Task 1. Text101 – Choose Your Own Adventure Game

With the basic set-up well out of the way from last week, my first task this week was to move into the next game project for the Complete C# Unity Developer 2D course.

This one just happened to be one of my favorite styles of game – choose your own adventure! I created a text-based game with a very simple user interface. The rules are also very simple. The player views part of a story and has to make a decision based on 2-3 different options. Their answer determines how the rest of the story continues.

Setting Up The Story Hooks

The theme of my game was a post-apocalyptic, exploration / survival style game set in 2021, just 18 months after the fall of civilization. I know, I know. So many video games already feature this post-apocalyptic scenario. I really don’t care. I love it; and besides, how could I resist?!

My first task was to find an image to use as inspiration for the game. While looking online, I found this video (now converted into a gif), which was even better.

Choose your own adventure game inspiration

In this game, the player assumes the role of Dr. Venton. He is a brave, albeit somewhat reckless scientist tasked with leading a small group of new settlers. It has been 18 months since a nearly apocalyptic war, and they have just returned to ground. He and the other settlers must move from base to base, discovering new resources and fighting off the dangers that surround them. The ultimate goal is to create safe zones so the remaining survivors may also return to ground.

There obviously wasn’t time to develop this entire story, but I was able to create a small snippet of how it might progress. The main point of this exercise was to begin thinking about gameplay. Also, it is the first game of this course where we move away from the command window and into an actual gameplay screen. I mean, command line games are fun and all, but they aren’t very practical. 😏

Game Development

This new game is the first time I was able to create and use a user interface in Unity, which means I learned a ton of new information since last week. Again, I’m not going to go through every little thing. There really was a lot this time, but here are just a few things I learned:

  • Creating Text variables and importing the UnityEngine.UI namespace in order to use those variables
  • Using [SerializeField] in order to allow changes to be made to the variable from within the Unity editor
The result of using [SerializeField] with a variable - it is now a reference within the editor and can be linked with text components.
The result of using [SerializeField] with a variable – it is now a reference within the editor and can be linked with text components.
  • Organizing information using states (actions or behavior) and state machines to transition from state to state
  • Managing state using scriptable objects
  • Creating an asset menu, which lets you create new states
Creating an asset menu to allow additional states to be created directly in Unity.
[CreateAssetMenu(menuName = “State”)]
  • Defining methods using access modifiers to control their scope as well as other return value types when the method should have a return value
  • Creating and using arrays (ex. int[] numbers = {1 , 2, 3};)
  • Using var in methods when the variable is declared and initialized in the same statement (i.e. the variable type can be assumed based on the data provided)
  • How to use flow diagrams and similar organizational tools to design an exciting game and get a better understanding of the story flow

One of the challenges in this section was to create a flow chart that maps out the rest of the story. Due to time constraints, I have made the conscious decision to leave my story where it is at. Because of this, as well as the fact that I have created 100+ flow charts in the past, I skipped this part entirely.

AdventureGame.cs (Main Script)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class AdventureGame : MonoBehaviour
{

    [SerializeField] Text textComponent;
    [SerializeField] State startingState;

    

    State currentState;

    // Start is called before the first frame update
    void Start()
    {
        currentState = startingState;
        textComponent.text = currentState.GetStateStory();
        
    }

    // Update is called once per frame
    void Update()
    {
        ManageState();
    }

    private void ManageState()
    {
        var nextStates = currentState.GetNextStates();
        if(Input.GetKeyDown(KeyCode.Alpha1))
        {
            currentState = nextStates[0];
        } else if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            currentState = nextStates[1];
        } else if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            currentState = nextStates[2];
        }

        textComponent.text = currentState.GetStateStory();
    }
}

State.cs (State Management Script)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "State")]
public class State : ScriptableObject
{

    [TextArea(10,14)] [SerializeField] string storyText;
    [SerializeField] State[] nextStates;

    public string GetStateStory()
    {
        return storyText;
    }

    public State[] GetNextStates()
    {
        return nextStates;
    }
}

Task 2. Create the UI for the Number Wizard Game

While it was nice to get started right away on C# without worrying about the UI, it was good to move away from that. After all, it is not practical to create a game that the player can only play in the console.

This is where my last task for this week came into play. I revisited the old Number Wizard game. There I created a simple little UI with a few different scenes, buttons, and text. Most of this was the same from what we did in the Text101 challenge. However, there were a few new things to learn and explore.

The biggest difference is we finally began working with sprites and buttons. Aside from that, it was all mostly the same. Once we got into scene management and the actual gameplay, however, that is when things began to change.

Scene Management

In the last challenge, I only used one scene. Instead of transitioning between scenes, I created a serialized state object. Then, as the state changes, the display text changes determines what text is displayed at any given time. For this project, however, there are 3 individual scenes, so the best approach was to use a scene manager to transition between scenes, depending on which one is currently being displayed.

Fortunately, scene management is already built into Unity with the UnityEngine.SceneManagement namespace. So, once I imported that into my code, it was just a matter of creating a few methods to load the next scene or, in the case of the game over screen, reload the start screen.

SceneLoader.cs (Scene Manager)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


public class SceneLoader : MonoBehaviour
{

    public void LoadNextScene()
    {
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        SceneManager.LoadScene(currentSceneIndex + 1);
    }

    public void LoadStartScene()
    {
        SceneManager.LoadScene(0);
    }
}

Refactoring the Number Wizard Code

Once the user interface was set up and scene management was in place, it was time to begin refactoring the original NumberWizard.cs script. The original code displayed the next guess in the console while also accepting input from the player based on keyboard input:

  • Up arrow = the number is higher
  • Down arrow = the number is lower
  • Enter (return) = the guess was correct

With the new user interface, the player controls the game by clicking on buttons for higher, lower, and correct guesses. Also, a text field updates to show the wizard’s current guess, which ultimately brings all input and output from the console into the interface.

Finally, the last major refactoring was the addition of a random number being used instead of the overly simplistic guess which used the number between the minimum and maximum value. This was accomplished by using the Random.Range function to return a value somewhere between the minimum and maximum values.

  • This Number Wizard UI project was created in Unity as part of my Summer of Code 2019. Learn more at blissfullemon.com
  • This Number Wizard UI project was created in Unity as part of my Summer of Code 2019. Learn more at blissfullemon.com
  • This Number Wizard UI project was created in Unity as part of my Summer of Code 2019. Learn more at blissfullemon.com
  • This Number Wizard UI project was created in Unity as part of my Summer of Code 2019. Learn more at blissfullemon.com

NumberWizard.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class NumberWizard : MonoBehaviour
{
    [SerializeField] int max, min;
    int guess;

    [SerializeField] TextMeshProUGUI guessText;

    // Start is called before the first frame update
    void Start()
    {
        StartGame();
    }

    void StartGame()
    {
        NextGuess();
    }

    public void OnPressHigher()
    {
        min = guess + 1;
        NextGuess();
    }

    public void OnPressLower()
    {
        max = guess - 1;
        NextGuess();
    }

    void NextGuess()
    {
        guess = Random.Range(min, max + 1);
        guessText.text = guess.ToString();
    }

}

Falling, Falling, Falling (A Bit of News)

After this week, I have a bit of good news as well as some not-so-great news. First, the good news is I am absolutely falling in love with Unity again. I can imagine myself continuing to create games with it for a long time to come. I already have so many ideas, too!

Now for the bad news…

I might be falling, but I am also falling behind. Nearly two weeks in, I am realizing now that I was a little over-eager with my weekly goals. I barely made it through this week! Actually, I owe my success in doing so to the fact that I fell really far behind on other projects. That just won’t work.

So, my plan is continue as originally planned. However, since I can’t allow myself to fall behind on anything else, I need to limit my game development time. The good news is I still have that last week for finishing up anything left undone. I anticipated that this might happen and, for once, actually prepared for it.


So, what do you think? Don’t forget you can enroll in the Complete C# Unity Developer 2D course over on Udemy. You can also follow along with my journey by entering your email address in the box below to get an alert when I make a new post. ❤

Join 1,467 other subscribers

Let's chat!

%d bloggers like this: