- Back to Home »
- Tetris game tutorial - part 1
1 June 2014
Hello,
By the Able_Elizalde request, I will start the tutorial about ,,How to create a simple tetris game".
So far I've never tried to make a tetris game. And this may not be the best way to do tetris style game.
Anyway, what we need to do:
- Generate board
- Create a shape
- Move shape down
- Collision between other blocks and edge
- User input
- Block rotation
- Check if there is full row, destroy and move blocks down
Before we start you can test final result.
Generate board
To generate a board, we will first need to set board width and height. Tetris board size is 10x20. But we will also add left and right edge of the board. Which is 1 + 10 + 1 = 12.
Same for the height 1 + 20 + 1 and for the block spawn +2 = 24.
In a new c# script we will define few variables we will need for this tetris game.
Same for the height 1 + 20 + 1 and for the block spawn +2 = 24.
In a new c# script we will define few variables we will need for this tetris game.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Tetris : MonoBehaviour {
//Board
public int[,] board;
//Block
public Transform block;
//Spawn boolean
public bool spawn;
//Seconds before next block spawn
public float nextBlockSpawnTime = 0.5f;
//Block fall speed
public float blockFallSpeed = 0.5f;
//Game over level
public int gameOverHeight = 22; //20 board + 2 edge
//Current spawned shapes
private List<Transform> shapes = new List<Transform>();
//Set true if game over
private bool gameOver;
//Current rotation of an object
private int currentRot = 0;
//Current pivot of the shape
private GameObject pivot;
void Start(){
//Deafult board is 10x16
//1+10+1 - Side edge
//+2 - Space for spawning
//+1 - Top edge
//20 - Height
//+1 - Down edge
board = new int[12,24];//Set board width and height
Now we will need to generate a board as soon as the game start, so make sure to call GenBoard in a Start function.
We will generate a tetris board like this:
- Edge of the board, we will mark it in board 2D array, so we can later check where is edge
- Board, mark it in board 2D array as empty space
void GenBoard(){
for(int x=0; x<board.GetLength(0);x++){
for(int y=0; y<board.GetLength(1);y++){
if(x<11 && x>0){
if(y>0 && y<board.GetLength(1)-2){
//Board
board[x,y]=0;
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(x,y,1);
Material material = new Material(Shader.Find("Diffuse"));
material.color = Color.grey;
cube.renderer.material = material;
cube.transform.parent = transform;
}
else if(y<board.GetLength(1)-2){
board[x,y]=1;
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(x,y,0);
Material material = new Material(Shader.Find("Diffuse"));
material.color = Color.black;
cube.renderer.material = material;
cube.transform.parent = transform;
cube.collider.isTrigger = true;
}
}
else if((y<board.GetLength(1)-2)){
//Left and right edge
board[x,y]=1;
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = new Vector3(x,y,0);
Material material = new Material(Shader.Find("Diffuse"));
material.color = Color.black;
cube.renderer.material = material;
cube.transform.parent = transform;
}
}
}
}
Create a shape
void SpawnShape(){
int shape = Random.Range(0,6);//Random shape
int height = board.GetLength(1)-4;
int xPos = board.GetLength(0)/2-1;
//Create a new pivot
pivot = new GameObject("RotateAround"); //Pivot of the shape
//SShape
if(shape==0){
pivot.transform.position = new Vector3(xPos,height+1, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos-1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height+1,0)));
Debug.Log("Spawned SShape");
}
//IShape
else if(shape==1){
pivot.transform.position = new Vector3(xPos+0.5f,height+1.5f, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+2,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+3,0)));
Debug.Log("Spawned IShape");
}
//OShape
else if(shape==2){
pivot.transform.position = new Vector3(xPos+0.5f,height+0.5f, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height+1,0)));
Debug.Log("Spawned OShape");
}
//JShape
else if(shape==3){
pivot.transform.position = new Vector3(xPos,height+2, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+2,0)));
Debug.Log("Spawned JShape");
}
//TShape
else if(shape==4){
pivot.transform.position = new Vector3(xPos,height, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos-1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
Debug.Log("Spawned TShape");
}
//LShape
else if(shape==5){
pivot.transform.position = new Vector3(xPos,height+1, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos-1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+2,0)));
Debug.Log("Spawned LShape");
}
//ZShape
else{
pivot.transform.position = new Vector3(xPos,height+1, 0);
shapes.Add(GenBlock(new Vector3(xPos, height,0)));
shapes.Add(GenBlock(new Vector3(xPos+1, height,0)));
shapes.Add(GenBlock(new Vector3(xPos, height+1,0)));
shapes.Add(GenBlock(new Vector3(xPos-1, height+1,0)));
Debug.Log("Spawned ZShape");
}
}
//Create block at the position
Transform GenBlock(Vector3 pos){
Transform obj = (Transform)Instantiate(block.transform, pos, Quaternion.identity) as Transform;
obj.tag = "Block";
return obj;
}
Move shape down and collision
if(!spawn && !gameOver){//If nothing spawned, if game over = false, then spawn
StartCoroutine("Wait");
spawn = true;
//Reset rotation
currentRot = 0;
}
Then we will wait some time before shape is spawned.
//Wait time before next block spawn
IEnumerator Wait(){
yield return new WaitForSeconds(nextBlockSpawnTime);
SpawnShape();
}
Now if you run the code you should see a random spawned shape, and also board in the background.
Let's now move that shape down.
void moveDown(){
//Spawned blocks positions
if(shapes.Count!=4){
return;
}
Vector3 a = shapes[0].transform.position;
Vector3 b = shapes[1].transform.position;
Vector3 c = shapes[2].transform.position;
Vector3 d = shapes[3].transform.position;
if(CheckMove(a,b,c,d)==true){ // Will we hit anything if we move block down(true = we can move)
//Move block down by 1
a = new Vector3(Mathf.RoundToInt(a.x),Mathf.RoundToInt(a.y-1.0f),a.z);
b = new Vector3(Mathf.RoundToInt(b.x),Mathf.RoundToInt(b.y-1.0f),b.z);
c = new Vector3(Mathf.RoundToInt(c.x),Mathf.RoundToInt(c.y-1.0f),c.z);
d = new Vector3(Mathf.RoundToInt(d.x),Mathf.RoundToInt(d.y-1.0f),d.z);
pivot.transform.position = new Vector3(pivot.transform.position.x, pivot.transform.position.y-1, pivot.transform.position.z);
shapes[0].transform.position = a;
shapes[1].transform.position = b;
shapes[2].transform.position = c;
shapes[3].transform.position = d;
}
else{
//We hit something. Stop and mark current shape location as filled in board, also destroy last pivot gameobject
Destroy(pivot.gameObject); //Destroy pivot
//Set ID in board
board[Mathf.RoundToInt(a.x),Mathf.RoundToInt(a.y)]=1;
board[Mathf.RoundToInt(b.x),Mathf.RoundToInt(b.y)]=1;
board[Mathf.RoundToInt(c.x),Mathf.RoundToInt(c.y)]=1;
board[Mathf.RoundToInt(d.x),Mathf.RoundToInt(d.y)]=1;
shapes.Clear(); //Clear spawned blocks from array
spawn = false; //Spawn a new block
}
}
bool CheckMove(Vector3 a, Vector3 b, Vector3 c, Vector3 d){
//Check, if we move a block down will it hit something
if(board[Mathf.RoundToInt(a.x),Mathf.RoundToInt(a.y-1)]==1){
return false;
}
if(board[Mathf.RoundToInt(b.x),Mathf.RoundToInt(b.y-1)]==1){
return false;
}
if(board[Mathf.RoundToInt(c.x),Mathf.RoundToInt(c.y-1)]==1){
return false;
}
if(board[Mathf.RoundToInt(d.x),Mathf.RoundToInt(d.y-1)]==1){
return false;
}
return true;
}
But this is never called. So let's call it in Start function, just this time we will use InvokeRepeating.
InvokeRepeating("moveDown",blockFallSpeed,blockFallSpeed); //move block down
Now the block will move down until it hits something, then it will stop marking current shape position as filled.
Source code


the dropbox link was expired... please..... reupload please...
ReplyDeleteGood job, I like yours.
ReplyDelete