Recreating Breakout for the Web
Tags: elm, functional, elixir
Published: 2020-11-23 14:46:23

Last time, we took a look at [creating a web version of _Pong_](https://dev.to/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8), the classic Atari game. Here is an animation of what we ended up with:

![Pong Implementation](https://dev-to-uploads.s3.amazonaws.com/i/mkl885jk6nq7w04qcw4g.gif)

Pretty cool! It's a fun game to play, even after all these years. And it was even more fun **figuring out all the little things that made _Pong_ so compelling**.

In this post, I'll share some of the steps I took to adapt the _Pong_ implementation into _Breakout_.

![Breakout Implementation](https://dev-to-uploads.s3.amazonaws.com/i/ilz66klx0y73h2ajc447.gif)

The original goal for these blog posts was to share step-by-step tutorials of how to recreate classic games. But **the intent has evolved into sharing some interesting notes, ideas, and takeaways about the process of building these games**. 

## ⏳ tl;dr

In the last blog post, I buried the links to the playable demo and the source code all the way at the bottom of the post. It was my devious intention to force everyone to take hours of their precious time to scroll through my ~~shoddy~~ writing. This time, I'll link to them here in case you want to try the game out before reading on.

- 🕹 [**Playable Demo**](https://create-with-games.herokuapp.com/breakout)
- 💻 [**Source Code on GitHub**](https://github.com/create-with/games/blob/master/assets/elm/src/Breakout.elm)

## 🛸 Why Breakout?

After working on _Pong_ for a while, I was dying to move on to a different game genre. I've always wanted to learn how to create platform games like _Super Mario Bros._ and adventure games like _The Legend of Zelda_. But I decided to try _Breakout_ for a couple reasons:

- _Breakout_ was my favorite Atari game. I grew up during the [Nintendo era of video game history](https://en.wikipedia.org/wiki/History_of_video_games), so the Atari 2600 console was a little before my time. **But games like _Breakout_ felt timeless in their appeal**. I also remember being blown away by some sort of "fancy" _Breakout_ version in the arcade. I only recently found out that was a game called [_Arkanoid_](https://en.wikipedia.org/wiki/Arkanoid).
- I already had most of the core components of the game figured out like the ball, paddle, and game window. **With the basic mechanics in place, I'd be able to focus on other fun features like particle effects, pixel art, animation, music, etc.)**.

## 🤔 What's Interesting About Breakout?

_Breakout_ consists of similar elements we saw last time like a game window, a paddle, and a ball. While _Pong_ was meant as a two-player game, _Breakout_ could be played solo since the objective was to break through the rows of stationary bricks at the top of the screen.

![Breakout Sketch](https://dev-to-uploads.s3.amazonaws.com/i/5vuowpu46lnzzz7plmag.jpg)

Beyond the gameplay itself, _Breakout_ has an interesting history. **Before [Steve Jobs](https://en.wikipedia.org/wiki/Steve_Jobs) went on to found some company called Apple, he worked on _Breakout_ at Atari**. The story goes that he would invite his friend Steve Wozniak, who worked at Hewlett-Packard, to help him design and build the game. I find it fascinating to think that _Breakout_ had some influence on the design of the [Apple II](https://en.wikipedia.org/wiki/Apple_II) computer, given its place in the history of computing.

If you're interested in reading more about this, the [Breakout Wikipedia entry](https://en.wikipedia.org/wiki/Breakout_(video_game)) is a great place to start. And there are some fun videos on YouTube like [_Before Apple: Steve Jobs at Atari_](https://www.youtube.com/watch?v=p5IaCTJdVuM&t) from Gaming Historian.

But what's most interesting to me about Breakout is how **we can layer features and "game feel" elements on top of the simple core mechanics**.

## 🤯 Game Feel and "Juice"

When I started working on a _Breakout_ implementation, I knew I already had most of the features I needed for the game window and the paddle and the ball. You can see [my previous blog post](https://dev.to/bijanbwb/recreating-pong-for-the-web-with-elm-2bi8) for an overview of how I implemented those features.

I knew I'd have to figure out how to implement the rows of breakable bricks at the top of the screen, but **one of the first things I wanted to do was add a "screen shake" feature**. When the ball hit one of the bricks, I wanted the window to shake to give the _feeling_ that it was an impactful collision.

A screen shake is **one of those features where you kind of don't notice it's there, but you can "feel" it when you play**. It's used commonly in games, but proved surprisingly hard to find for browser games.

While looking for resources about how to accomplish this, I stumbled on this talk called [_The Art of Screenshake_](https://www.youtube.com/watch?v=AJdEqssNZ-U), and I became fascinated by this idea of adding seemingly small details to a game that add up to a lot in terms of game feel.

![The Art of Screenshake](https://dev-to-uploads.s3.amazonaws.com/i/ut0h7y7cs62bzwyl7q0t.png)

> "Just fill your game with love and tiny details."
Jan Willem Nijman

This guided a lot of the work I ended up putting into building _Breakout_. In addition to the core game mechanics and a screen shake, I added things particle effects, pixel art, and music to make the game more fun and appealing.

For more on the topic of Game Feel, there's also a great video from Game Maker's Toolkit called [_Secrets of Game Feel and Juice_](https://www.youtube.com/watch?v=216_5nu4aVQ).

## 🔄 Implementing a Screenshake

**So how does a screenshake work?** Thankfully we're working with a simple 2D game (as opposed to 3D or VR), so we only need to worry about moving the game window and then putting it back to restore its original position.

We start with our rectangular game window that's rendered with SVG. I've been working with the Elm programming language for these games, so I started with a type and set some initial values.

```elm
type alias Window =
    { backgroundColor : String
    , x : Float
    , y : Float
    , width : Float
    , height : Float
    }

initialWindow : Window
initialWindow =
    { backgroundColor = "black"
    , x = 0.0
    , y = 0.0
    , width = 800.0
    , height = 600.0
    }
```

The `x` and `y` represent the top left position of the game window. What we need to do is shift the `x` value to move the window left and right, and shift the `y` value to move the window up and down.

Then, after we shift the game window out of place, we restore its position back to the original position at `(0, 0)`. Its kind of subtle if you don't know to look for it, but obvious once you see it. Here's what it looks like with the game elements in place so the window shake is visible:

![Screen Shake](https://dev-to-uploads.s3.amazonaws.com/i/rb8xlpldetyw1oyael12.gif)

If you go [play the game in the production environment](https://create-with-games.herokuapp.com/breakout), you can actually click anywhere in the game window to simulate the screen shake feature.

I used a random number generator (which can be surprisingly hard to work with in Elm) so the screen shake didn't seem so predictable or jarring. And it does add a lot when the ball collides with a brick to trigger a screen shake.

If you're interested in learning more about screen shakes and more involved implementations, there's an amazing series of talks from the Game Developer's Conference called _Math for Game Programmers_. One of the talks is called [_Juicing Your Cameras With Math_](https://www.youtube.com/watch?v=tu-Qe66AvtY) and it's really fun to see the code you can use to implement your own amazing screen shake features.

## 🎉 Particle Effects

Next, I wanted to add some particle effects to the game. Particles are usually things like fireworks, explosions, smoke, etc. I already had the screen shake working, but **I thought it would be cool to create an explosion of particles when the ball collided with a brick**.

I can't take credit for how awesome this feature looks, because I used an existing Elm package that makes these kinds of particles easy to work with. [`elm-particle`](https://package.elm-lang.org/packages/BrianHicks/elm-particle/latest/) is a package from [Brian Hicks](https://github.com/BrianHicks), who not only organizes the yearly Elm conference called [elm-conf](https://elm-conf.com/), but is also the nicest person you'll ever meet.

Here's an animation that shows what the particles look like during gameplay:

![Particles](https://dev-to-uploads.s3.amazonaws.com/i/ilz66klx0y73h2ajc447.gif)

You can tinker with all sorts of settings for the particles. I ended up spawning ten small particles from the top left of the ball whenever it collides with a brick. In addition to the position, you can also tinker with things like how gravity affects the particles, how quickly they move and rotate, and how long they last before going away.

If you're interested in seeing more of the specifics of how the particle effects are implemented, check out the [`Breakout.elm` file](https://github.com/create-with/games/blob/master/assets/elm/src/Breakout.elm) in the source code. The `elm-particle` package documentation also has some fun examples of how to use it for fun things like water and fireworks.

## 🎨 Assets and Pixel Art

For the _Pong_ game I worked on, all the elements of the game were just based on simple shapes. So SVG rectangles were sufficient to represent things like the game window and the paddles and the ball.

But for _Breakout_, **I wanted to incorporate some pixel art assets into the game to make it look a little nicer**. I ended up using an iPad App called [Pixel Studio](https://apps.apple.com/gb/app/pixel-studio-for-pixel-art/id1404203859#?platform=ipad) to create the assets, but you might also want to check out [Aseprite](https://www.aseprite.org/) if you're interested in creating pixel art.

![Pixel Art Paddle](https://dev-to-uploads.s3.amazonaws.com/i/t8cg3n6afn7ykr15vvvi.png)

So instead of using `Svg.rect` to create a rectangle, I used `Svg.image` and linked to [the static assets in the repository](https://github.com/create-with/games/tree/master/assets/static/images). The `viewBall` and `viewPaddle` functions use familiar attributes for the size and position, and also use the `xlinkHref` attribute to pull in the pixel art images.

```elm
viewBall : Ball -> Svg msg
viewBall ball =
    Svg.image
        [ Svg.Attributes.xlinkHref "/images/pixel-ball.png"
        , Svg.Attributes.x <| String.fromFloat <| Util.Vector.getX ball.position
        , Svg.Attributes.y <| String.fromFloat <| Util.Vector.getY ball.position
        , Svg.Attributes.width <| String.fromFloat ball.width
        , Svg.Attributes.height <| String.fromFloat ball.height
        ]
        []
```

```elm
viewPaddle : Paddle -> Svg msg
viewPaddle paddle =
    Svg.image
        [ Svg.Attributes.xlinkHref "/images/pixel-paddle.png"
        , Svg.Attributes.x <| String.fromFloat <| Util.Vector.getX paddle.position
        , Svg.Attributes.y <| String.fromFloat <| Util.Vector.getY paddle.position
        , Svg.Attributes.width <| String.fromFloat paddle.width
        , Svg.Attributes.height <| String.fromFloat paddle.height
        ]
        []
```

Mozilla's Developer Network (MDN) is great for looking up how to work with [SVG elements and attributes](https://developer.mozilla.org/en-US/docs/Web/SVG). And then it's just a matter of translating it into Elm using the [`elm/svg` package](https://package.elm-lang.org/packages/elm/svg/latest).

## 🎮 Updating the Game Platform

**I ended up spending some time creating a new back-end for this project as well**. I had originally built _Pong_ and used a tool called [Parcel](https://parceljs.org/) to bundle the project. But I ended up running into trouble as soon as I started working with static assets, so I replaced it with the [Phoenix Framework](https://www.phoenixframework.org/), which is way more familiar to me.

It may be overkill to use Phoenix to serve a couple of small image files, but it also gives me some freedom to add back-end features like tracking scores as I build more games. I've also been playing with Phoenix's LiveView capability and love working with it:

{% twitter 1296919592237969409 %}

Given that I was going from one game to multiple games, I wanted to add an index page to serve as a game selection screen. I also added some simple routing features to navigate between the different games. And I imported the [Tailwind CSS](https://tailwindcss.com/) framework to start with a simple design and add a footer area with some helpful links.

![Game Platform](https://dev-to-uploads.s3.amazonaws.com/i/gabatg0ilu9ilz31tvmx.png)

## 🎼 Music

For _Pong_, I had a couple of files called `beep.wav` and `boop.wav` that I was using for simple sound effects. I left those out of _Breakout_, but I wanted to add some background music.

{% twitter 1131530464727064577 %}

In the past, I had tinkered with creating some custom "chiptune" style music using programs like [PICO-8](https://www.lexaloffle.com/pico-8.php) and [Bosca Ceoil](https://boscaceoil.net). They can be fun to play with, but my _Breakout_ implementation was already getting complicated enough, so I tried finding existing music online.

After Googling a bit, I came across [PlayOnLoop.com](https://playonloop.com) and found a royalty-free, upbeat song I liked and created a new [`CREDITS.md` file](https://github.com/create-with/games/blob/master/CREDITS.md).

To play the music, I use the [howler.js](https://howlerjs.com/) JavaScript library. It required using [Elm ports](https://guide.elm-lang.org/interop/ports.html) to sync up the JavaScript and Elm code, but howler.js has some great features that I'll likely continue to use as I create more games. 

## 🧱 Implementing the Bricks (Finally)

![Bricks](https://dev-to-uploads.s3.amazonaws.com/i/cpq9242dl4zmjy9btuua.png)

**The rows of breakable bricks at the top of the screen were the most important feature**, so naturally I procrastinated on implementing them.

Somewhere in the commit history on GitHub, there was a range of commits where I used various combinations of several data structures (`List`, `Dict`, `Array`) in hopes of finding something that felt right to work with. I won't bore you with the details, but I can at least share how some of the fun parts work.

### 🏗 Individual Bricks

This is what the fields look like for the `Brick` type along with the data for a default brick:

```elm
type alias Brick =
    { color : String
    , height : Float
    , hitCount : Int
    , hitThreshold : Int
    , position : Vector
    , strokeColor : String
    , width : Float
    }
```

```elm
defaultBrick : Brick
defaultBrick =
    { color = "white"
    , height = 16
    , hitCount = 0
    , hitThreshold = 1
    , position = ( 0, 0 )
    , strokeColor = "black"
    , width = 80
    }
```

One of the first things that might stand out is the `position`. For _Pong_, I was using separate `x` and `y` fields to store `Float` values. But I've been working towards learning Linear Algebra a little better for the next games that I plan to work on.

For _Breakout_, I used a custom `Vector` type, but for the next games I work with I'll likely use the [`elm-explorations/linear-algebra`](https://package.elm-lang.org/packages/elm-explorations/linear-algebra/latest/Math-Vector2) package. Khan Academy also has great lessons on [Linear Algebra](https://www.khanacademy.org/math/linear-algebra) if you're looking to learn more.

The other thing you might have noticed is that I added `hitCount` and `hitThreshold` fields. This allows for setting some breaks as "hard" bricks that take multiple hits to break.

### 🤔 Data Structures

After some initial thrashing about which data structure to use, I settled on using a Dictionary because it would allow for identifying bricks by their row and column. In this type alias, we create a `Dict` of bricks where the two `Int` types represent the row number and column number.

```elm
type alias Bricks =
    Dict ( Int, Int ) Brick
```

The implementation for the bricks may have ended up somewhat complicated, and it's possible a normal `List` would have sufficed. But I knew I wanted to adjust things like the `hitCount` and `color` for specific rows or bricks, and using a `Dict` made that a little easier.

Here are some of the important functions I used for constructing the rows of bricks.

```elm
buildRow : Int -> String -> String -> Bricks
buildRow rowNumber color strokeColor =
    List.range 1 10
        |> List.foldr (insertBrick rowNumber) Dict.empty
        |> setRowColors color strokeColor
        |> setRowPosition


insertBrick : Int -> Int -> (Bricks -> Bricks)
insertBrick rowNumber columnNumber =
    Dict.insert ( rowNumber, columnNumber ) defaultBrick
```

I'm glossing over the details, but definitely check out the [`Breakout.Brick` module](https://github.com/create-with/games/blob/master/assets/elm/src/Breakout/Brick.elm) if you want to see how it all comes together.

### 🎨 Styles and Animation

For the brick colors, I used the [color palette from Tailwind CSS](https://tailwindcss.com/docs/background-color) and looked up the corresponding hex values to create a ["ROYGBIV"](https://en.wikipedia.org/wiki/ROYGBIV) rainbow for the rows.

The "hard" row of bricks at the top takes multiple hits to break. So it has a different stroke color as a visual indicator that there's something different about those bricks, even if it's not obvious until the ball hits them.

Another cool feature that isn't obvious is that the opacity of each brick is calculated as the percentage of hits remaining to break the brick. In other words, if we made a brick that took ten hits to break, the brick would start out opaque and subtract 10% of its opacity after each hit. If we were to create new levels, this would be a great feature to consider.

![Brick Animation](https://dev-to-uploads.s3.amazonaws.com/i/pfgb1h8vrw57h1uymbem.gif)

**One of the most fun features to add was the drop-in animation for the bricks** when the game first loads. The [Animate.css](https://animate.style) library has tons of amazing examples for this kind of thing.

I used those examples to create a "bounceInDown" animation that you can find in the [`assets/css/animations.scss` file](https://github.com/create-with/games/blob/master/assets/css/animations.scss). Then, in the Elm code, I added that `bounce-in-down` class to the bricks to get the animation working.

## ✨ Wishlist

**It's amazing how many cool features you can add to a small game like _Breakout_**. But I wanted to find a good stopping point and move on to a new game. One of the big takeaways from this project was how distracted I can get while trying to finish something. I actually finished writing the code for the game months before I was able to publish this blog post.

But there are some known bugs and wishlist items that would be great to add to the game:

- Create Multiple Levels
- Improve Collisions
- Add Sound Effects
- Incorporate Randomness
- Save High Scores
- Expand Particle Effects

If you're looking for inspiration and more features to think about, here are some other great places to look:

- [Arkanoid](https://en.wikipedia.org/wiki/Arkanoid)
- [LazyDevs PICO-8 Breakout](https://www.youtube.com/playlist?list=PLea8cjCua_P0qjjiG8G5FBgqwpqMU7rBk)

## 📈 What's Next?

I've been having fun building a little arcade cabinet lately. At some point, I'd love to see one of the games I build running on it.

![Arcade Cabinet Front](https://dev-to-uploads.s3.amazonaws.com/i/lxmnrrczipihu1ewpt5p.jpg)
![Arcade Cabinet Rear](https://dev-to-uploads.s3.amazonaws.com/i/5gwobppi020e1rl4xq5s.jpg)

I've also loved getting to explore things like WebGL and Unity recently. But the next game I'm going to focus on building is the classic game [_Adventure_](https://en.wikipedia.org/wiki/Adventure_(1980_video_game)). And my plan is to _hopefully_ incorporate both 2D _and_ 3D features if I can get it all figured out.

If you're learning functional programming and game development, feel free to [get in touch with me](https://bijanbwb.github.io) and I'd be happy to hear from you. You can also [find me on Twitter](https://twitter.com/bijanbwb).

And here are links to the game and the source code!

- 🕹 [**Play the Game!**](https://create-with-games.herokuapp.com/breakout)
- 💻 [**View the Source Code on GitHub**](https://github.com/create-with/games)