How to Make Video Games 10

How to Make TetrisWe continue making a Tetris clone in this video. Our goal this time is to get those Tetris shapes to stack on each other. A lot more goes into that then we may have thought. I’ll be covering Simulating Game boards in Arrays, Printing Arrays, Removing Event Handling from Objects, Instantiating Objects, Debugging, Moving All Shapes in a Scene and a whole lot more.

I continue with my new teaching format in which I make mistakes and then fix them to help you learn. All of the code follows the video below.

If you like videos like this, consider donating $1 on Patreon, or just turn off AdBlock. That helps a lot.

[googleplusone]

Code from The Video

SHAPESPAWNER.CS

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShapeSpawner : MonoBehaviour {

    // Array that holds all the shapes
    public GameObject[] shapes;

    public void SpawnShape()
    {
        // Generate a random index
        int shapeIndex = Random.Range(0, 6);

        // Create the shape at the ShapeSpawners location
        Instantiate(shapes[shapeIndex],
            transform.position,
            Quaternion.identity);
    }

	// Use this for initialization
	void Start () {

        // Spawn the default first shape
        SpawnShape();
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

GAMEBOARD.CS

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GameBoard : MonoBehaviour {

    // ---------- NEW STUFF ----------

    // Surround all GameObjects with GameObjectGroup
    // and move it the amount of space to make the 
    // gameboard lie at the 0 0 mark

    // Stores all the cubes on the gameboard
    public static Transform[,] gameBoard = new Transform[10, 20];

    public static void PrintArray()
    {
        string arrayOutput = "";

        // Gets size of gameboard array and then subtract
        // 1 because the array starts with 0
        int iMax = gameBoard.GetLength(0) - 1;
        int jMax = gameBoard.GetLength(1) - 1;

        // Cycle through the array and print N or X 
        // depending on if you have a null or transform
        for(int j = jMax; j >= 0; j--)
        {
            for (int i = 0; i <= iMax; i++)
            {

                if (gameBoard[i, j] == null)
                {
                    arrayOutput += "N ";
                } else
                {
                    arrayOutput += "X ";
                }
            }

            arrayOutput += "\n \n";

            }

        // Get a reference to the Text component
        // and change its value
        var myArrayComp = GameObject.Find("MyArray").GetComponent<Text>();
        myArrayComp.text = arrayOutput;

    }
}

SHAPE.CS

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Shape : MonoBehaviour {

    // Define that we want to fall 1 unit per second
    public float speed = 1.0f;

    // Tracks the last time the shape moved down
    float lastMoveDown = 0;

	// Use this for initialization
	void Start () {
		
	}
	
	// Update is called once per frame
	void Update () {

        if (Input.GetKeyDown("a"))
        {
            // Modify position
            transform.position += new Vector3(-1, 0, 0);

            if (!IsInGrid())
            {
                // Switch to previous
                transform.position += new Vector3(1, 0, 0);
            } else {

                // Update the GameBoard array
                UpdateGameBoard();
            }
        }

        if (Input.GetKeyDown("d"))
        {
            transform.position += new Vector3(1, 0, 0);

            if (!IsInGrid())
            {
                transform.position += new Vector3(-1, 0, 0);
            } else {
                UpdateGameBoard();
            }
        }

        // Move Shape down when s is pressed, or once every second
        // First time through Time.time will have a value of 1 and
        // then 2, etc. 
        // lastMoveDown will increment each time through as well

        if (Input.GetKeyDown("s") || Time.time - lastMoveDown >= 1)
        {
            transform.position += new Vector3(0, -1, 0);

            if (!IsInGrid())
            {
                transform.position += new Vector3(0, 1, 0);

                // Disconnect the script actions from the shape
                enabled = false;

                // Spawn another shape
                FindObjectOfType<ShapeSpawner>().SpawnShape();
            } else {
                UpdateGameBoard();
            }

            lastMoveDown = Time.time;
        }

        if (Input.GetKeyDown("w"))
        {
            transform.Rotate(0, 0, 90);

            if (!IsInGrid())
            {
                transform.Rotate(0, 0, -90);
            }
            else
            {
                UpdateGameBoard();
            }
        }

        if (Input.GetKeyDown("e"))
        {
            transform.Rotate(0, 0, -90);

            if (!IsInGrid())
            {
                transform.Rotate(0, 0, 90);
            }
            else
            {
                UpdateGameBoard();
            }
        }

    }

    public bool IsInGrid()
    {
        // Cycle through every block in the shape
        foreach(Transform childBlock in transform)
        {
            // Get location of the block and round to int
            Vector2 vect = RoundVector(childBlock.position);

            // Check if the position is within the border
            if (!IsInBorder(vect))
            {
                return false;
            }

            // Check what is located in the GameBoard array
            // This should be its own method
            if(GameBoard.gameBoard[(int)vect.x, (int)vect.y] != null &&
                GameBoard.gameBoard[(int)vect.x, (int)vect.y].parent != transform)
            {
                return false;
            }

        }
        return true;
    }

    // Round the cubes position to an int so it can fit 
    // in the array
    public Vector2 RoundVector(Vector2 vect)
    {
        return new Vector2(Mathf.Round(vect.x), Mathf.Round(vect.y));
    }

    // Check if between the border
    public static bool IsInBorder(Vector2 pos)
    {
        return ((int)pos.x >= 0 &&
            (int)pos.x <= 9 &&
            (int)pos.y >= 0);
    }

    // 
    public void UpdateGameBoard()
    {
        for(int y = 0; y < 20; ++y)
        {
            for(int x = 0; x < 10; ++x)
            {

                // If the 1st isn't null that means there
                // is a cube at that position
                // Then we check if the shape passed in
                // is already there
                if (GameBoard.gameBoard[x, y] != null &&
                    GameBoard.gameBoard[x, y].parent == transform)
                {
                    // If the shape moves down then we want
                    // to remove it from the gameBoard array
                    GameBoard.gameBoard[x, y] = null;
                }

            }
        }

        // Iterate over all spaces on our gameboard
        // and add the new cubes for out shape
        foreach (Transform childBlock in transform)
        {
            // Shorten our position object
            Vector2 vect = RoundVector(childBlock.position);

            // Put our cube in the gameboard array
            GameBoard.gameBoard[(int)vect.x, (int)vect.y] = childBlock;

            Debug.Log("Cube At : " + vect.x + " " + vect.y);

        }

        GameBoard.PrintArray();

    }

}

Leave a Reply

Your email address will not be published. Required fields are marked *