SameGame engine made with Unity and C# – adding animations + commented code

Read all posts about "" game
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://www.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.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stairs
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers