Block Breaker

Updated on June 26th, 2021 at 1:08 am

What is it?

This was a project that I made as a final project for a Udemy Course that I took for fun. The goal of the project was to make an Arkanoid-like block-breaking game using my own sprites, my own scripts, and my own physics. The course taught 2D game development with Unity and Block Breaker was one of the chapters in the course. Though this game is not completed, a small demonstration of the game can be played with the link above.

The game was once at a more completed state, but through time, files were lost and now all that remains is a small portion of the game. I am currently working on rebuilding the missing parts so that the game will once again be back to its former glory.

What does it do?

The goal of Block Breaker is to use the paddle at the bottom of the screen to bounce the ball between the paddle and the bricks at the top of the screen. You can move the paddle by dragging the mouse across the screen. If the ball bounces off of a brick, the brick loses a hit point and once the brick is out of hit points, it disappears. The color of the brick determines how many hit points it has. When all of the bricks are removed, the game progresses to the next level.

screenshot of the block breaker game
A screenshot of the Block Breaker game

How does it work?

Block Breaker is powered by the Unity game engine. The project consists of a background sprite, a sprite sheet made of 39 sprites, one font, one material, 3 scenes plus a scene for every level, 6 scripts, and an audio file that loops through the gameplay. I also created 13 prefabs for the paddle, the ball, the background, the level manager, the playspace, and each of the 7 types of bricks.

Sprites

The sprites are from a sprite sheet that I drew with Illustrator. Using Unity, I divided the sprite sheet into fixed-sized blocks that became sprites. Once a sprite was added to a scene, I then made it a prefab of it that could easily be duplicated across the different scenes.

spritesheet for the block breaker game
The sprite sheet for the bricks, ball, and paddle

The sprite sheet for the bricks, ball, and paddle support the various cracked versions of bricks for every color (even though they may never appear in the game). This was so that I had the ability to easily change the hit points for each color in the game. At the moment, red bricks only have a single hit point, so you will never see a cracked version in the game, but I can easily change that color to green without having to draw a new sprite sheet. The gray brick does not have cracked variations because it will always be indestructible. I figure it is probably the same material as the paddle.

Scripts

There are six scripts that make up the game. They are written in C#. The ball, paddle, and brick all have their own scripts to dictate how they function in the game. The level manager-script determines which scene to load and when to switch it to the next. The lose-collider script determines how the “Lose Scene” is activated and the music player script is responsible for playing the background music.

Ball.cs

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

public class Ball : MonoBehaviour {

    private Paddle paddle;
    private bool hasStarted = false;
    private Vector3 paddleToBallVector;
    private Rigidbody2D ball;

    // Use this for initialization
    void Start()
    {
        paddle = GameObject.FindObjectOfType<Paddle>();

        // Place the ball right above the paddle
        paddleToBallVector = this.transform.position - paddle.transform.position;

        // Instantiate the ball object as the current classes Rigidbody2d
        ball = this.GetComponent<Rigidbody2D>();
	}
	
	// Update is called once per frame
	void Update()
    {
        if (!hasStarted)
        {
            // Keep the position of the ball equal to the postion of the paddle
            this.transform.position = paddle.transform.position + paddleToBallVector;

            // Launch the ball when mouse is clicked
            if (Input.GetMouseButtonDown(0))
            {
                Debug.Log("mouse clicked");
                ball.velocity = new Vector2(0f, 400f);
                hasStarted = true;
            }
        }
	}
}

Paddle.cs

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

public class Paddle : MonoBehaviour {

	// Update is called once per frame
	void Update ()
    {
        // Get the mouse position on the screen
        float mousePos = Input.mousePosition.x;

        // Get the paddle position using the Vector3 structure
        Vector3 paddlePos = new Vector3(0.0f, this.transform.position.y, 0.0f);

        // Change the paddle position according to mouse movement
        paddlePos.x = mousePos;
     
        paddlePos.x = Mathf.Clamp(mousePos, 50, 750);
        this.transform.position = paddlePos;
    }
}

Brick.cs

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

public class Brick : MonoBehaviour {
    
    public Sprite[] cracks;
    public static int breakableCount = 0;

    private int maxHits;
    private int timesHit;
    private bool isBreakable;
    private Vector3 crackVector;
    private LevelManager levelManager;

	// Use this for initialization
	void Start ()
    {
        isBreakable = (this.tag == "Breakable");

        // Keep track of breakable bricks
        if (isBreakable)
        {
            breakableCount++;
        }

        levelManager = GameObject.FindObjectOfType<LevelManager>();
        timesHit = 0;
	}

    // When the ball hits a brick
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (isBreakable)
        {
            HandleHits();    
        }
    }

    // What happens when a ball hits a brick
    private void HandleHits()
    {
        timesHit++;
        maxHits = cracks.Length + 1;
        if (timesHit >= maxHits)
        {
            breakableCount--;
            levelManager.BrickDestroyed();
            Destroy(gameObject);
        }
        else
        {
            LoadSprites();
        }
    }

    // Handles changing of sprites when a brick is hit
    private void LoadSprites()
    {
        int spriteIndex = timesHit - 1;
        if (cracks[spriteIndex])
        {
            this.GetComponent<SpriteRenderer>().sprite = cracks[spriteIndex];
        }
    }
}

LevelManager.cs

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

public class LevelManager : MonoBehaviour {

    // Function to goto a scene
    public void LoadLevel(string name)
    {
        Debug.Log("Level load requested for: " + name);
        SceneManager.LoadScene(name);
    }

    // Function to quit the game
    public void QuitRequest()
    {
        Debug.Log("Game quit");
        Application.Quit();
    }

    public void LoadNextLevel()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
    }

    public void BrickDestroyed()
    {
        if (Brick.breakableCount <= 0)
        {
            LoadNextLevel();
        }
    }
}

LoseCollider.cs

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

public class LoseCollider : MonoBehaviour {

    private LevelManager levelManager;

    private void OnTriggerEnter2D(Collider2D trigger)
    {
        print("Trigger");
        levelManager.LoadLevel("Lose");
    }

	private void Start()
	{
        levelManager = GameObject.FindObjectOfType<LevelManager>();
	}
}

MusicPlayer.cs

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

public class MusicPlayer : MonoBehaviour {

    static MusicPlayer instance = null;

    // Awake called before Start
    private void Awake()
    {
        // Destroy any new instances of MusicPlayer
        if (instance != null)
        {
            Destroy(gameObject);
            Debug.Log("Duplicate music player self-destructing");
        }
        else
        {
            instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
    }

Links