Monday, July 22, 2013

Using Grid Framework to build a platformer

The last months have been insanely busy.  I may have overdone it on my still healing foot, and so today I find myself at home and forced to rest.  It sounds like a perfect opportunity to make a game AND a tutorial!!

I enlisted the help of my 4 year old daughter in deciding what kind of game to make.  She wanted a game where Happy Face has to collect a crown.  Happy Face will encounter a witch, a Mother Spider and her Baby Spiders.  So, I am going to be building a single screen platformer.  By single screen, I mean that what is displayed is the entire game, no scrolling, no extra rooms.  At least not yet :)

I have also just purchased Grid Framework and this is a great time to see what it can do.

First thing is to create the actual grid.  GameObject > Create Grid > Rectangular Grid will do the trick.  Hexagonal Grids and Polar Grids are also available.  Hexagonal grids will be perfect for deep strategy games.  A polar grid is a circular grid, and the only use I can think of for it right now is as some kind of radar or motion sensor display.

Grid with Default Settings

Now to shape the grid to fit our game world.  For this game, I need a grid twice as wide as it is tall.  I dont care about depth, so I set the Z to 0.  X is 12 and Y is 5.  Your dimensions may vary.

2D Grid
I should now be able to use this grid to create a basic level layout.  Open up the Grid Align Panel (Window > Grid Align Panel) and turn on AutoSnapping.  Make sure you have assigned your grid to the panel too.
Create a basic cube (GameObject > Create Other > Cube) and drag it onto the grid.  You will see that it is perfectly aligned, and moving it around will snap it to the grid.  Place a bunch of these and you have a level.
I will create a boundary first, to stop an eager 4 year old from jumping off the world into oblivion.

Once the boundary is created, lets get Happy Face into the game and moving.   All artwork has been provided by my daughter :)

For the sake of simplicity, I am faking a 2D sprite by creating a cube with a transparent diffuse and her painting attached.  Also add a character controller.  This will replace the default box collider.

Fake2D Sprite settings
Lets add some simple scripting to get this happy fella moving.  Attach this script to your 'sprite'

float moveSpeed = 3.0f;
float jumpSpeed = 8.0f;
float gravity = 10.0f;
Vector3 moveDirection = Vector3.zero;
// Update is called once per frame
void Update ()
{
//handle input and move character controller;
CharacterController cc = GetComponent<CharacterController>();
if(cc.isGrounded)
{ moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, 0); // Gets Horizontal movement. Edit > Project Settings > Input to find out more about Axis.
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= moveSpeed;
if(Input.GetButton("Jump") && cc.isGrounded)
{
moveDirection.y = jumpSpeed; }
}
moveDirection.y -= gravity * Time.deltaTime;
cc.Move(moveDirection * Time.deltaTime);


Test it out and you should be able to walk your sprite back and forth without it falling out of the world.  Lets add a few platforms and the crown.  The grid will allow me to easily line up platforms, and with the current gravity settings on the player I know that the sprite can jump just over 3 grid squares high, so I need a maximum distance of 3 squares floor to floor for the character to be able to make the jump.

Basic level


Lets add a quick script to the crown to allow it be 'collected'.
When the player touches the crown, the following needs to happen:
Record that the crown has been collected
Play a 'pick up' sound
'Destroy' the game object.

To make a trigger on the crown object, I select it and set 'Is Trigger' to true on the box collider.  I also have an empty object in my scene called 'Game Manager', with a game manager script attached.  I'll use this to track any information that the entire game needs to know about.  Right now it just consists of a single public bool to track if the crown has been collected or not.  Set it's default value to false (uncollected).

My crown script.  I used the free tool SFXR to generate my sound fx.

using UnityEngine;
using System.Collections;

public class Crown : MonoBehaviour {

void OnTriggerEnter(Collider other) //fired when an object ENTERS the trigger zone
{
//Record that crown has been collected
GameManager gmScript = GameObject.Find("Game Manager").GetComponent<GameManager>();
gmScript.CrownCollected = true;

//Play Pick up sound
audio.Play();

//Destroy Object
Destroy(GameObject.Find("Crown"), 0.3f);
}
}

Test and you should have a playable level with a pick upable crown.  Whats missing?  Friends, of course!!

Next part coming soon....