Cloning the Classics: Arkanoid

March 5, 2021

Arkanoid clone image

The Game


Arkanoid is a classic arcade video game developed in 1986 by Taito. It is based off Breakout, a successful game engineered by Steve Wozniak for Atari, Inc. in 1976.

In Arkanoid, the player controls the Vaus, a space vessel that is used to bounce a ball to destroy the bricks on screen while preventing the ball from leaving the playing field. Once all the bricks are destroyed, the player moves on to the next level. Power ups are dropped randomly from destroyed bricks and, in some levels, floating enemies appear as obstacles.

Research


Although I remember playing Arkanoid as a kid and I remember what it looked like and how it played in general, I didn’t remember the history or game mechanics that made it special. I needed to do some research to understand what it would take to build the game.

Research consisted of reading the Wikipedia [1] entry to relearn basic gameplay and art which will need to be created. During my research, I luckily ran into an Arkanoid StrategyWiki [2] that explained the mechanics, rules, and levels.

I didn’t have the game to play as a resource. So, I watched several videos of people playing the game. The first video I found had a player that was very [3] good which meant losing mechanics were nonexistent in the video. I had to search farther for how the game acted upon losing. I guess people don’t really want to upload a video of them not being perfect at a game.

Development


I chose Python’s Arcade framework [4] to develop the clone. It is a relatively new framework but seems to be actively maintained and has decent documentation along with basic tutorials to get started.

I tried to break up the game into small goals before starting any development. This gave an initial map of the path forward and a method to keep track of small wins. Doing this keeps motivation up as the TODO list is constantly being ticked off during the limited time I have in the evening. Also, my mind was more settled before sleeping as I felt I accomplished something each night.

The plan and TODO list was broken down into quite a few steps:

  1. Install Virtual Environment, Python, and the Arcade library
  2. Write simple game.py that opens a window
  3. Draw Vaus (player) sprite
  4. Add player with controls
  5. Draw wall sprites
  6. Add left, right, top walls
  7. Draw ball sprite
  8. Add a ball that can be shot from the player sprite
  9. Implement the ball bouncing off walls
  10. Draw brick sprite
  11. Add a brick
  12. Implement the ball bouncing off bricks
  13. Add more bricks and destroying of bricks
  14. Add score keeping
  15. Add sound effects
  16. Add level 2
  17. Implement transition to level 2

As you can see, each item was limited to a very small and actionable task. Ideally, each task could be done within an hour or, at most, a couple hours.

I won’t be going into every step listed above but there were a couple of noteworthy issues that I think are worthwhile to mention and discuss in the following sections.

Bounces, Reflections and Vectors


One of the most important mechanics of the game is the ball’s ability to bounce off walls, bricks and the Vaus (the player). How the ball bounces off any of the pieces can make or break the game which is why we want to make sure to do it right.

Two things had to be done to ensure a smooth and fun bouncing experience:

  1. Use the correct vector math to calculate the reflection of the bounce
  2. Add a slight angle depending where the ball bounces on the Vaus

To calculate the reflection vector, we can use the formula R = V - 2(V ยท N)N. [5] Where R is the reflection vector, V is the original vector and N is the normal vector.

Reflection Vector

Reflection Vector off the Vaus

from collections import namedtuple

Vector = namedtuple('Vector', 'x y')

def reflect(vector, normal):
    dot = (vector.x * normal.x) + (vector.y * normal.y)
    z = Vector(x=(2 * dot * normal.x), y=(2 * dot * normal.y))
    return Vector(x=(vector.x - z.x), y=(vector.y - z.y))

Considering the lack of friction and air resistance, if the player shot the ball straight up, bounces would only result with an inversion of the Y vector. The ball would bounce straight up and down forever. Not so fun.

We needed to add a way to change the ball’s path if it gets stuck in an infinite loop. One way to do this is to alter the X component of the normal vector if the ball bounces off a particular part of the Vaus. This will give the player more play variation and some control of the bounce angle.

Reflection Vector with nudge

Reflection Vector off the Vaus with a slight nudge.

We give a slight nudge on the X-axis depending on where the ball bounces. This prevented the ball from finding itself in an infinite bouncing loop if the ball happened to bounce exactly perpendicular to the player. A simple method is to divide the Vaus into equal thirds (Left, Center, Right).

The player divided into thirds

The Vaus divided into thirds and Left, Center, and Right sections.

v = Vector(x=self.change_x, y=self.change_y)
location = self.player.collision_location(self)
normal = Vector(0, 1)

# Determine where the ball collided to "enhance" angle of reflection
if location == Player.LEFT:
    normal = Vector(0.196, -0.981)
elif location == Player.RIGHT:
    normal = Vector(-0.196, -0.981)

new_v = reflect(v, normal)
self.change_x = new_v.x
self.change_y = new_v.y

Multiple (Quick Succession) Collision Detections


Using the native collision detection system in Arcade, there were several times a collision was detected but before the ball could exit the collider box of the sprite, the framework would detect another collision. This would typically result in the ball either reflecting back down below the paddle, out of play, or it would bounce repeatedly within the paddle sprite until it finds the exit at the end of the sprite.

To prevent this type of situation, we can turn off collisions between sprites temporarily once a collision is detected.

if (ball.collides_with_sprite(self.player)
        and ball.player_collision_counter == 0):
    ball.player_collision_counter = 20  # Reset counter for 20 frames
    ball.collides_with_player() # Execute the collision code

Once a collision is detected, a frame counter is initialized to 20 frames. For every frame, the counter is decremented until it is 0. If the ball collides with the player within those 20 frames, the collision will be ignored. This should give the ball enough time to exit the collider box. Similar code was used with the walls and bricks.

Conclusion


It was fun going down memory lane while building the basics of Arkanoid. Breaking the project into smaller actionable goals helped keep motivation up and frustration down. Although there were several glitches, it was rewarding to work through the possible solutions and end with a playable game.

I didn’t set out to write a full tutorial on developing a game or building a Breakout/Arkanoid clone. I did want to highlight my overall process and some interesting issues that I ran across. Hopefully you found it interesting as well.

Thanks for reading. Feel free to checkout the Github Repository.

References


01: Arkanoid Wikipedia

02: Arkanoid Strategy Wiki

03: A Ridiculously Long Play of Arkanoidon on YouTube

04: Arcade Framework

05: Reflecting a Vector