Adventures in Unity – 1.3 Initial GSM

Official_unity_logo

 

#1 What would I ideally like to achieve by the time I finish working today – Build a basic GSM incorporating a title and game over screen, displaying players score. Allowing games to end and be restarted.

#2 What’s the minimum I’d like to achieve by the close of play – Build a basic GSM incorporating a game over screen, displaying players score. Allowing games to end and be restarted.

 


 

With the game in it’s current state, there’s still a lot of work to do – I decided, for the moment, to stop developing the game-play and work on the GSM instead.

This was partly because I think the game itself is getting some shape (even with such little actual code in place), whereas the GSM & how I was going to implement it was still very much undefined in mind.

It was also partly because when testing the game I didn’t want to have to keep stopping & starting the test environment every time the player went off screen – It’s gets old fast.

Partly because it helps give the game some structure to work from.

& finally because the GSM is, for me, often the least interesting part of the game to develop, it’s easy to overlook, but is very important for giving players a sense/feel about the product as a whole.

 


 

My most recent experience building GSM’s comes from developing Xbox 360 indie titles. In that environment I used ‘screen-managers’.

XNA GSM Sample code

Explanation from XNA;

The ScreenManager class is a reusable component that maintains a stack of one or more GameScreen instances. It coordinates the transitions from one screen to another, and takes care of routing user input to whichever screen is on top of the stack.

Each screen class (including the actual gameplay, which is just another screen) derives from GameScreen. This provides Update, HandleInput, and Draw methods, plus some logic for managing the transition state. GameScreen doesn't actually implement any transition rendering effects, however: it merely provides information such as "you are currently 30% of the way through transitioning off," leaving it up to the derived screen classes to do something sensible with that information in their drawing code. This makes it easy for screens to implement different visual effects on top of the same underlying transition infrastructure.

This is very different to the way the GSM’s are handled in the Unity tutorials – Notably the ‘tanks‘ and ‘space shooter‘ sample code.

I figured I could replicate the XNA screenmanager GSM framework by using separate scenes instead of separate screens – Simple to implement and fairly clean.

But I figure part of the point of learning is to try something new, so I’ve used the  ‘tanks‘ and ‘space shooter‘ set-up for the GSM – If it works, hooray – If not, at I’ll know 🙂

 


 

Initially I pretty much ripped the ‘space shooter‘ GSM code wholesale.

It’s a nice simple set-up, easily replicable & I thought I could plug it in fairly easily…

I created an empty game object – called it ‘GameController‘ added a new C# script (also called ‘GameController’) – Into the script, I pulled over the relevant score, restart and game over code.

I added a UI-Text component, played with it a little, but as a rule I just replicated the settings from the ‘space shooter‘ game – Plugged these text components into ‘GameController‘ script, allowing it to handle when to display what text.

In the game itself, I needed to identify when it was game over – Since I’m just trying to set things up, I decided to keep things simple – If the players cube is at position -11 on either the X or Y coordinate (outside the screen to the left, or bottom)- Then it’s game over.

To make sure ‘GameController‘ reacted to the game over state – I created a global static bool called InGame – If InGame is true, game is running, if InGame is false then display the ‘Game Over text.

I added a little extra code to the player and platforms scripts – Ensuring they only updated when InGame was true.

But otherwise, that was pretty much it – It took a little smoothing, but it worked quite nicely.

 


 

The problem was, it was only a game over screen – At the moment, when the game starts running, it throws the player immediately into the game – Which I felt would be very confusing and a little off-putting for someone who’d just started the game up – I needed a title screen.

Again, I wanted something simple that played nicely with the modified ‘space shooter‘ ‘GameController‘ code.

Following the code in place;

When the game initially starts/loads InGame is set to false this ensures text is displayed and the player isn’t thrown, unexpectedly into the action.

Since the game has only just loaded, it seems a little rude to display the ‘Game Over‘ screen straight away.

I added an extra text field to hold the games title – currently called ‘TEST GAME‘ – Linked this into the ‘GameController‘ code.

I needed to figure out when to display the game title and when to display game over –

This I fudged – Given the interface I’d decided to work with, I wasn’t too sure of the best approach.

Creating a static bool called ‘counter‘ (originally it was an int, after updating I forgot to change the name). If counter == true then the games title text is displayed, if counter == false, then the game over text is displayed. By making the bool static, it keeps it’s value even after ‘SceneManager.LoadScene‘ is called.

 


 

Full ‘GameController‘ code;

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using UnityEngine.SceneManagement;
public class GameController : MonoBehaviour
{
     //---
     //---
     public static bool inGame;
     private float scoreActual;
     private int scoreDisplay;
     public Text scoreText;
     private bool restart;
     public Text restartText;
     private bool gameover;
     public Text gameoverText;
     private bool title;
     public Text titleText;
     public static bool counter = true;

     //---
     //---
     // Use this for initialization
     void Start()
     {
          scoreActual = 0;
          scoreDisplay = 0;
          UpdateScore();
          gameover = false;
          gameoverText.text = "";
          restart = false;
          restartText.text = "";
          //---
         if (counter)
          {
               title = true;
               titleText.text = "TEST GAME";
               counter = false;
               inGame = false;
          }
          else
          {
               title = false;
               titleText.text = "";
               inGame = true;
          }

     }
     //---
     //---
     // Update is called once per frame
     void Update()
     {
          if (restart)
          {
              if (Input.GetKeyDown(KeyCode.R))
               {
                    SceneManager.LoadScene(Application.loadedLevel);
               }
           }
              else if (title)
               {
                    if (Input.GetKeyDown(KeyCode.R))
                    {
                         title = false;
                         titleText.enabled = false;
                         inGame = true;
                    }
          }
          else
          {
               AddScore(0.1f);
               UpdateScore();
          }
     }
     //---
     //---
     void UpdateScore()
     {
          scoreText.text = "Score: " + scoreDisplay;
     }
     //---
     //---
     public void AddScore(float newScoreValue)
     {
          scoreActual += 0.1f;
          scoreDisplay = (int)scoreActual;
          UpdateScore();
     }
     //---
     //---
    public void GameOver()
     {
          gameoverText.text = "Game Over";
          gameover = true;
          restartText.text = "Press 'A' to restart";
          restart = true;
          Debug.Log("GAME OVER GAME OVER GAME OVER");
          inGame = false;
     }
     //---
     //---
}

 


 

So I had a basic GSM – A little funky, but it works – It’s an approach I hadn’t tried before & it’s simple enough that I can either adapt it (if I want to stick with the code) – Or remove it if I decide to go for something more substantial.

 


 

Play this build (WebGL)

 


 

Grab a copy of the project here

 


 

 


 

Next post: 1.4a Tighten & Tidy

Last post: 1.2 Initial Code

Contents page.

 


 

Adventures in Unity – 1.2 Initial Code

Official_unity_logo

 

For me, the very start of the project is always the best and worst part.

On the one hand everything is still up for grabs – Everything is potential.

On the other hand, I’m staring at an empty project trying to figure out where to start.

 


 

When I sit down to code I generally try have two objectives in mind;

#1 What would I ideally like to achieve by the time I finish for the day.

#2 What’s the minimum I’d like to achieve by the close of play.

In this case:

#1 What would I ideally like to achieve by the time I finish working today – Would be having the initial platform & player code in place

#2 What’s the minimum I’d like to achieve by the close of play – To have the platform code in place.

There’s no guarantee I’ll achieve either, but it gives me a daily goal to work toward and somewhere to start.

 


 

After staring at the screen for far too long & trying out a few dead ends, I eventually got to a point where I felt I had a basic structure in place – I’d split the project into three basic aspects;

 

1. Platforms;

A platform is currently a default unity ‘cube‘ object set-up as a prefab. I thought if I set it up as a prefab it would make any later customisation easier. It has a mesh renderer so it can be drawn to the screen & a box collider to it can interact with the player.

 

2. Platform Manager;

This is just an empty element with a ‘platform manager‘ script attached. This script is what actually manages the platforms.

The ‘platform manager‘ script contains a list of ‘platform‘ objects. At the beginning of the game the list is initialised with cubes positioned from the far left to the far right of the screen (extending off-screen in both directions). Each cube is given a random width & height (giving the player a reason to move/jump).

each update loop;

  1. All cubes are moved/scrolled to the left.
  2. Any cubes that are scroll off the left side of the screen are removed
  3. A check is made to see if more cubes need to be created – If so cubes (with random widths/heights) are added to the list positioned on the right hand side of the screen.

 

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

public class PlatformManager : MonoBehaviour {

     //---

     public GameObject platform;
     List<GameObject> platforms = new List<GameObject>();

     float speed = 0.1f;

     float farLeft = -30;
     float farRight = 30;

     float widthMin = 2;
     float widthMax = 10;

     float heightMin = 2f;
     float heightMax = 4f;

     float basePosition = -3;

     //---

     // Use this for initialization
     void Start () {

          initalRoof();
          PopulatRoofs();

     }

     //---
     //---
 
     // Update is called once per frame
     void Update () {

         //---

          for (int counter = 0; counter < platforms.Count; counter++)
          {

               platforms[counter].transform.position = new Vector3(platforms[counter].transform.position.x - speed, platforms[counter].transform.position.y, platforms[counter].transform.position.z);

               if (platforms[counter].transform.position.x <= farLeft)
               {
                    Destroy(platforms[counter]);
                    platforms.RemoveAt(counter);
                    counter--;
               }

          }

          //---

          PopulatRoofs();

          //---

     }

     //---
     //---

     private void initalRoof()
     {

          float posX = farLeft;

          float width = widthMax;
          float height = heightMax - (heightMin/2);

          posX += width / 2;

          Vector3 position = new Vector3(posX, -2 + (height / 2), 0);
          Vector3 scale = new Vector3(width, height, 10);

          //---

          platforms.Add(Instantiate(platform, position, Quaternion.identity) as GameObject);
          platforms[platforms.Count - 1].transform.position = position;
          platforms[platforms.Count - 1].transform.localScale = scale;

     }

     private void PopulatRoofs()
     {

          float posX = farLeft;
          if (platforms.Count > 0)
               posX = (platforms[platforms.Count - 1].transform.position.x + (platforms[platforms.Count - 1].transform.localScale.x/2))+1;

          while (posX < farRight)
          {

               float width = Random.Range(widthMin, widthMax);
               float height = Random.Range(heightMin, heightMax);

               posX += width / 2;

               Vector3 position = new Vector3(posX, basePosition + (height/2), 0);
               Vector3 scale = new Vector3(width, height, 10);

               //---

               platforms.Add(Instantiate(platform, position, Quaternion.identity) as GameObject);
               platforms[platforms.Count - 1].transform.position = position;
               platforms[platforms.Count - 1].transform.localScale = scale;

               posX += (width/2)+1;

          };
 
     }

}

 

3. Player;

Player is a default unity ‘cube‘ object. It has a mesh renderer so I can be drawn to the screen & a box collider to it can interact with the platforms – It also has a rigidbody and C# script (called ‘player‘) to manage movement.

The ‘player‘ script is very simple and uses code modified from Unity’s ‘2D platformer‘ tutorial. It sets the initial position for the player at the start of the game & uses two methods – Update & Fixed Update – To allow the player to control the cube.

Update checks to see if the player is trying to jump (pressing the spacebar) – If the player is trying to jump it sets the ‘jump‘ boolean to true – Since the platforms as moving from left/right – at this point – the player only needs to move up and down.

FixedUpdate handles the actual ‘jumping‘ – If the player wants to jump, it adds a ‘jumpForce‘ to the cubes rigidbody and sets the ‘jump’ boolean to false.

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {

     [HideInInspector]
     public bool jump = false;

     public float jumpForce = 10;

     private Rigidbody rb;

     //---

     // Use this for initialization
     void Awake()
     {

          rb = GetComponent<Rigidbody>();

     }

     // Update is called once per frame
     void Update()
     {

          if (Input.GetButtonDown("Jump"))
               jump = true;

     }

     //---

     void FixedUpdate()
     {


          if (jump)
          {
               rb.AddForce(new Vector3(0f, jumpForce, 0f));
               jump = false;
         }


     }

 //---

}

& That’s it – By letting Unity’s in-built physics & collision engines to handle the heavy lifting we have the core to an endless/infinite runner game.

 


 

Play this build (WebGL)

 


 

Grab a copy of the project here

 


 

 

Now, don’t get me wrong – There’s still a long way to go before this is a game – & there is a LOT wrong with/missing from the current code. But this does provide an interesting basis to work from.

 

Next step I’m looking to wrap a simple GSM around the game. This will allow the game to be replayed without needing to stop/start the engine every time.

 


 

Next post > 1.3 Initial GSM

Last post < 1.1 Introduction

Contents page.

 


 

Adventures in Unity – 1.1 Introduction

Official_unity_logo

I ran through a few of the Unity tutorials back in November 2015. With the intention of putting something together straight away – while everything was fresh in my mind – but life, the universe and Christmas got in the way.

While I did manage to keep develop Bit:Shift (uploading to Google Play & Amazon App Store) over the holiday period – Learning Unity was put on the back burner.

By the time I did get back to looking at Unity it was mid-January 2016 & I’d forgotten almost everything.

Rather than go back to the tutorials – which may have been the sensible option – but would have been time-consuming &tedious. I decided to put together a very simple game – something I could make by referencing my existing tutorial code; that would allow me to play with different aspects of unity (game play, GSM, Sound, multi-platform, etc) and which I could expand on over time.

Something which I could potentially develop despite forgetting almost everything I’d learnt the previous year.

Now, the code was going to be horrible – There’s no getting around that – But it would be a project I’d developed from scratch – It would be a start.

screen640x640

[Image from Canabalt]

After I little thought, I settled on a 2.5D endless/infinite runner type game.

I figured this would be a good way to start since so few elements are required: player & platforms.

It can run nicely using simple graphics, I could let Unities built in collision/physics engines handle all the heavy lifting which I worked on trying to understand the development environment & structure.

It also means I don’t need to spend a lot of time designing aspects of the game – I can focus on learning while coding.

All good in theory – Now to see how well that works when I actually try 🙂

 


 

Next post: 1.2 Initial Code

Contents page.

 


 

10 Print “Hello World”

Hi – My name is Scott Lewis, I develop video games under the ‘20 Goto 10‘ banner.

 

Initially developing games for the Xbox 360, publishing EOLMagic Thighs & Slightly Phil, Twist Imperfect, Fat Cow · Hot AirnorT:Tron ’84

 

I followed these up with four small ‘one-tap’ Android games; Bit:Run, Bit:Rise, Bit:Fall & Bit:Shift

 

Currently I’m slowly teaching myself Unity & looking for a job (who knew it was possible to make so little money making indie video games? 🙂 )

 

I thought I’d try writing a blog – maybe update as I develop new games, post-mortem past projects – Try to give some perspective on what seemed to work & where I went wrong.

 

I hope you stick around to see how things go.