Talking about SameGame game, C#, Game development and Unity3D.
If you are enjoying my tutorial series about SameGame game, I am sure you will appreciate this new step, featuring the Unity prototype I blogged about last week with animations and commented code, which I strongly recommend you to compare with the same prototype made with Phaser, this will allow you to learn two languages at the price of one. First, look at the game: You know how to play, just look at the animations. This is the commented code I want you to compare with the code of the HTML5 game you can find in this post. They are very similar in my opinion, and although Unity does not natively support tweens, with LeanTween you can use tweens pretty much the same way you are used to do with Phaser.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Script : MonoBehaviour {
// the tile itself
public GameObject tileObject;
// array with game colors
private Color[] colors = new Color[4];
// howw many rows?
private int numRows = 8;
// how many columns?
private int numCols = 8;
// two dimensional array which will contain the game table
private GameObject[,] tilesArray = new GameObject[8, 8];
// this List (basically an array with a twist) will be used to store flood fill results.
private List filled;
// tilesToMove is used to see how many tiles we have to move with LeanTween
private int tilesToMove = 0;
// can the player pick a tile?
private bool canPick = true;
void Start () {
// defining colors to be used as tile tint
colors [0] = new Color(1f, 0f, 0f, 1f);
colors [1] = new Color(0f, 1f, 0f, 1f);
colors [2] = new Color(0f, 0f, 1f, 1f);
colors [3] = new Color(1f, 1f, 0f, 1f);
// looping through the whole table
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++){
// function to create a tile
createTile (i, j);
}
}
}
// this function is executed at each frame
void Update () {
// if the player clicked/touched AND can pick a tile...
if (Input.GetButtonDown ("Fire1") && canPick) {
// getting mouse position
Vector2 firePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// each tile has a collider to determine if mouse position overlaps
Collider2D hitCollider = Physics2D.OverlapPoint(firePosition);
// if there is a collider, that is if we clicked a tile...
if (hitCollider) {
// filled List is set to empty list
filled = new List ();
// running flood fill algorithm
floodFill (hitCollider.GetComponent ().coordinate, hitCollider.GetComponent ().value);
// if there are more than one tile in the flood fill result…
if (filled.Count > 1) {
// player can’t pick anymore at the moment
canPick = false;
// looping through filled List
for (int i = 0; i < filled.Count; i++) {
// destroying the game object
Destroy (tilesArray [(int)filled [i].y, (int)filled [i].x]);
// setting list entry to null
tilesArray [(int)filled [i].y, (int)filled [i].x] = null;
}
// fill vertical holes, if any
fillVerticalHoles ();
}
}
}
}
void createTile(int row, int col){
// creation of a new tileObject instance
GameObject tile = Instantiate(tileObject);
// determining vertical position
float yPos = 3.5f - 1f * row;
// determining horizontal position
float xPos = -3.5f + 1f * col;
// placing the tile at the proper position
tile.transform.position = new Vector2 (xPos, yPos);
// choosing a random color
int tileColor = Random.Range (0, colors.Length);
// setting value property with the chosen color
tile.GetComponent ().value = tileColor;
// saving coordinate property
tile.GetComponent ().coordinate = new Vector2 (col, row);
// applying the tint color to the tile
tile.GetComponent ().material.color = colors [tileColor];
// adding the tile to tilesArray array
tilesArray [row,col] = tile;
}
// function to fill holes by making tiles fall down
void fillVerticalHoles(){
for (int i = numRows – 2; i >= 0; i–) {
for (int j = 0; j < numCols; j++) {
if (tilesArray [i, j] != null) {
int holesBelow = 0;
for (int z = i + 1; z < numRows; z++) {
if (tilesArray [z, j] == null) {
holesBelow++;
}
}
if (holesBelow>0) {
tilesToMove ++;
moveTile (i, j, i + holesBelow, j);
}
}
}
}
if(tilesToMove==0){
fillHorizontalHoles();
}
}
// function to fill holes horizontally, that is to move columns to the left to replace missing columns
void fillHorizontalHoles(){
for (int i = 0; i < numCols - 1; i++) {
if (tilesInColumn (i) == 0) {
for (int j = i + 1; j < numCols; j++) {
if (tilesInColumn (j) != 0) {
for (int z = 0; z < numRows; z++) {
if (tilesArray [z, j] != null) {
tilesToMove ++;
moveTile (z, j, z, i);
}
}
break;
}
}
}
}
if(tilesToMove==0){
canPick = true;
}
}
// function to move a tile, this is where LeanTween comes into play
void moveTile(int fromRow, int fromCol, int toRow, int toCol){
tilesArray [toRow, toCol] = tilesArray [fromRow, fromCol];
tilesArray [toRow, toCol].GetComponent ().coordinate = new Vector2 (toCol, toRow);
// vertical tween
if(fromRow != toRow){
LeanTween.moveY (tilesArray [toRow, toCol], 3.5f – 1f * toRow, 0.5f).setOnComplete(completeYMovement);
}
// horizontal tween
else{
LeanTween.moveX (tilesArray [toRow, toCol], -3.5f + 1f * toCol, 0.5f).setEase(LeanTweenType.easeOutBounce).setOnComplete(completeXMovement);
}
tilesArray [fromRow, fromCol] = null;
}
// this function is executed each time a vertical tween is completed.
// we decrease tilesToMove and once it reaches zero (no more tiles to move)
// we call fillHorizontalHoles function to move tiles horizontally, if we have to.
void completeYMovement(){
tilesToMove –;
if(tilesToMove == 0){
fillHorizontalHoles ();
}
}
// this function is executed each time an horizontal tween is completed.
// we decrease tilesToMove and once it reaches zero (no more tiles to move)
// we set canPick to true so the player can pick again
void completeXMovement(){
tilesToMove –;
if(tilesToMove == 0){
canPick = true;
}
}
// function to count how many tiles we have in a column, simply counting values different than “null”
int tilesInColumn(int col){
int result = 0;
for (int i = 0; i < numRows; i++) {
if (tilesArray [i, col] != null) {
result++;
}
}
return result;
}
// flood fill function, for more information
// http://emanueleferonato.com/2008/06/06/flash-flood-fill-implementation/
void floodFill(Vector2 p, int n){
if (p.x < 0 || p.y < 0 || p.x > numCols – 1 || p.y > numRows – 1) {
return;
}
if (tilesArray [(int)p.y, (int)p.x] != null && tilesArray [(int)p.y, (int)p.x].GetComponent ().value == n && !filled.Contains(p)) {
filled.Add (p);
floodFill (new Vector2 (p.x + 1, p.y),n);
floodFill (new Vector2 (p.x – 1, p.y),n);
floodFill (new Vector2 (p.x, p.y + 1),n);
floodFill (new Vector2 (p.x, p.y – 1),n);
}
}
}
You can also download the entire project and play with it. Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.