- 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 downNow 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