GD50 Lecture 02 - Breakout

This is part of a series where I talk about how I approach the assignment portion of the GD50 lecture. These are written so that I can review them in the future without going through the code! Since this is an assignment, I won’t be posting the code unless it is not related to the assignment. If you are stuck at one of these assignments, these posts should contain enough information to help you progress. Feel free to let me know if there is an error. :)

I am back! This week, we will be looking at Breakout. Quick recap for this week: using sprite sheets with quad (artworks condensed into one image and we only have to retrieve it once, and then we can extract individual sprite using rectangles), using procedural layout (to ‘automagically’ generate different levels), adding level system, implementing particle system, improving the collision, and saving the high scores.

Before we begin, I would like to talk about breaking down problems. If you ever encounter something complex and you are not sure where to begin, try breaking it down to a more manageable smaller part and work through it step by step. This trick has been very helpful for me personally and I am gonna showcase this several times in this post. Let’s go!

  1. Powerup
  2. Various paddle size
  3. Locked brick
  4. Bugs & Changes

Powerup

Speaking of powerup, I was gonna implement powerup into the last game - Flappy Bird. I didn’t do it at the end but luckily this is the first assignment task for this lecture. Breaking it down on how to add a powerup that will spawn a ball:

If balls spawned from the powerup behave the same way as the first ball (which means players will lose health if they failed to catch the ball), players will be discouraged from picking up powerups because it is hard to catch all the balls at the same time. So I made some changes to address this. Balls that spawned from the powerup will not reduce player’s health and they will also have a distinct gold colour. Now, players can choose to prioritize catching the first ball instead! Powerups are meant to be helpful for the players and I felt like these changes make the game more enjoyable as well.

Powerup spawning!
Powerup spawning!

Instead of spawning two balls when the paddle collides with a powerup, I chose to spawn one because it makes the game feels more balanced. The assignment also wanted us to spawn the powerup based on a timer or when the ball hit a brick enough time, but I spawn the powerup depending on the score as I think this will make the game more manageable on later levels! Anyway, I coded the assignment version as well (powerup spawn when the ball hit the same brick twice):

Assignment version
Assignment version

This can be done by storing the amount of hit(s) in the bricks, and we increment it whenever the ball collides with the brick. If the amount of hit exceeded the defined amount, the game will spawn a powerup underneath the brick.

Various paddle size

This one is slightly easier but we can still break it down into a few steps:

We used a variable to store the score required to increase the paddle size, and the value of this variable will increase everytime the paddle grow. Make sure to pass this variable between states. Otherwise, it will be reset whenever the game’s state changed (moved to next level etc.). If this variable is reset on the next level, any increase in the score will grow the paddle because the player has a much higher score than the value of the variable. This will continue until the variable is back to the previous value.

Paddle growing and shrinking
Paddle growing and shrinking

Locked brick

A locked brick that can only be unlocked when the player obtained the key powerup. This is quite a complicated task but once again let’s break it down:

First, we have to choose how to spawn the key. In my implementation, a key will be spawned every 30 seconds on the upper half of the screen. This ensures that the player can still clear the level if they missed any of the keys.

Next up is the LevelMaker class. My LevelMaker scales with the levels. The first 9 levels will have no locked brick, and level 10 till 19 has 0 to 1 locked brick per now, while level 20 till 29 have 0 to 2 locked brick per row, and so on and so forth. The maximum amount of locked brick on a row is 3 because that is also the minimum amount of brick on a row. It begins by deciding the amount of locked brick for a row, and then it will randomly pick the positions to spawn the locked brick for that row.

Finally, I added some quality of life changes into the game including:

Unlocking locked brick with key
Unlocking locked brick with key

Bugs & Changes

Every hit is a health up!

if self.score > self.recoverPoints then
    self.health = math.min(3, self.health + 1)
    self.recoverPoints = math.min(100000, self.recoverPoints * 2)
end

The code above is used to recover player’s health when they achieve a certain score and notice that the self.recoverPoints is capped at 100,000. There is a bug here because when players achieved any score higher than 100,000, any increase in score after that will recover their health. It is kinda very hard to lose once we go beyond that 100,000 mark:

Gaining health when score increases
Gaining health when score increases

I am not entirely sure what is the purpose of the cap, it might be used to prevent overflow or it was used to prevent players from getting any more health up. Personally, I don’t think it is used to prevent overflow as 21024 or around 1e+308 is a huge number. So let’s try to implement the second one and fix the bug at the same time.

if self.recoverPoints < 100000 and self.score > self.recoverPoints then
    self.health = math.min(3, self.health + 1)
    self.recoverPoints = self.recoverPoints * 2
end

By simply adding a condition and using the and operator, we can terminate any health up once self.recoverPoints is larger than 100,000.

Minor bugs that were fixed

This has been a fun and thought-provoking assignment. I certainly learnt a few things and I hope it is the same for you too :)