diff --git a/README.md b/README.md
index 09d5951..b3be05c 100644
--- a/README.md
+++ b/README.md
@@ -16,3 +16,6 @@ as change the background color of the application.
## Triangle Game
A simple "Triangle Game" that allows you to move a Roguelike '@' around the window (and off of it).
+
+## Brick Game
+A simple brick break / breakout game.
diff --git a/brick/README.md b/brick/README.md
new file mode 100644
index 0000000..9df4d81
--- /dev/null
+++ b/brick/README.md
@@ -0,0 +1,46 @@
+
+
+# About
+
+Classic brick game written in Ruby with the awesome [ruby2d](http://www.ruby2d.com) framework.
+
+![ruby_brick](https://i.ibb.co/VCDbKqX/ezgif-com-video-to-gif.gif)
+
+> Note: the low frame rate here is due to the GIF recording not the game itself.
+
+# Install
+
+Make sure you have installed:
+
+* [simple2d](https://github.com/simple2d/simple2d):
+
+```
+brew tap simple2d/tap
+brew install simple2d
+```
+
+* [ruby2d](https://github.com/ruby2d/ruby2d):
+
+```
+gem install ruby2d
+```
+
+Then clone the source code to your local:
+
+```
+git clone https://github.com/mosinski/brick.git
+```
+
+# Play
+
+```
+cd brick
+ruby brick.rb
+```
+
+Paddle control:
+
+* a: left
+* d: right
+
+Original code made by Tiago Guedesn (tiagopog) for Pong game (thanks!)
diff --git a/brick/assets/PressStart2P.ttf b/brick/assets/PressStart2P.ttf
new file mode 100755
index 0000000..98044e9
Binary files /dev/null and b/brick/assets/PressStart2P.ttf differ
diff --git a/brick/brick.rb b/brick/brick.rb
new file mode 100644
index 0000000..4448c7e
--- /dev/null
+++ b/brick/brick.rb
@@ -0,0 +1,121 @@
+require 'ruby2d'
+
+require './lib/ball'
+require './lib/paddle'
+require './lib/match'
+
+##
+# Window & FPS
+##
+
+set title: 'Brick',
+ background: 'black',
+ with: 640,
+ height: 480,
+ resizable: false
+
+fps_display = Text.new(get(:fps).to_i, x: 315, y: 463, size: 12)
+
+##
+# Pad
+##
+
+pad = Paddle.new(
+ x: get(:width) / 2 - 60 / 2,
+ y: get(:height) - 15,
+ width: 60,
+ height: 10,
+ speed: 7,
+ constraints: { x: { min: 0, max: get(:width) - 50 } }
+)
+
+##
+# Bricks
+##
+
+bricks = []
+
+4.times do |row|
+ 10.times do |column|
+ bricks << Paddle.new(
+ x: get(:width) / 10 * column,
+ y: 15 * row,
+ width: 60,
+ height: 10,
+ speed: 0,
+ constraints: {}
+ )
+ end
+end
+
+##
+# Ball
+##
+
+ball = Ball.new(
+ x: pad.x + (pad.width / 2) - 5,
+ y: 450,
+ size: 10,
+ speed: 5
+)
+
+##
+# Pause
+##
+
+pause_display = Text.new(
+ 'PRESS SPACE',
+ x: get(:width) / 2 - 110,
+ y: get(:height) / 2 - 20,
+ font: 'assets/PressStart2P.ttf',
+ color: 'gray',
+ size: 20,
+ opacity: 1
+)
+
+##
+# Main
+##
+
+match = Match.new
+
+# Paddle movement
+on :key_held do |event|
+ pad.move(event, left: 'a', right: 'd')
+
+ if match.paused?
+ ball.x = pad.x + (pad.width / 2) - (ball.width / 2)
+ end
+end
+
+# Game pause
+on :key_down do |event|
+ if event.key == 'space'
+ match.paused = false
+ pause_display.opacity = -1
+ end
+end
+
+update do
+ fps_display.text = get(:fps).to_i
+
+ if match.paused?
+ next
+ else
+ ball.move(window: get(:window), pad: pad, bricks: bricks)
+
+ if ball.scored?
+ ball.scored.each do |brick|
+ index = bricks.index(brick)
+ bricks[index].width = 0
+ bricks.delete(brick)
+ end
+ elsif ball.failed?
+ match.paused = !match.paused
+ pause_display.opacity = 1
+ match.restart!(get(:window), ball, pad)
+ end
+ end
+end
+
+show
diff --git a/brick/lib/ball.rb b/brick/lib/ball.rb
new file mode 100644
index 0000000..287ed83
--- /dev/null
+++ b/brick/lib/ball.rb
@@ -0,0 +1,112 @@
+# Deals with the logic of the brick's ball.
+# @author Miłosz Osiński
+class Ball < Square
+ DEFAULTS = {
+ speed: 3,
+ direction: { x: 1, y: 1 }
+ }.freeze
+
+ attr_accessor :speed, :direction, :scored, :scored_at, :failed_at
+
+ # @api public
+ # @param speed [Integer, Float, nil] ball's speed
+ # @param direction [Hash, nil] ball's x and y axis directions
+ # @return [Ball]
+ def initialize(speed: nil, direction: nil, **args)
+ super(args)
+ @speed = speed || DEFAULTS[:speed]
+ @direction = direction || DEFAULTS[:direction]
+ end
+
+ # @api public
+ # @param window [Window] the game's window
+ # @param pad [Pad] the game's pad
+ # @param bricks [Array] the game's bricks
+ # @return [Hash] ball's current position
+ def move(window:, pad:, bricks:)
+ self.scored_at = nil
+
+ if edge_collision?(:x, window)
+ self.direction[:x] *= -1
+ elsif edge_collision?(:y, window)
+ self.failed_at = Time.now if check_edge_collision(:y, window) == :bottom
+ self.direction[:y] *= -1
+ elsif pad_collision?(pad)
+ self.direction[:y] *= -1
+ elsif brick_collision?(bricks).any?
+ self.scored_at = Time.now
+ self.scored = brick_collision?(bricks)
+ self.direction[:y] *= -1
+ end
+
+ self.x += direction[:x] * speed
+ self.y += direction[:y] * speed
+
+ { x: x, y: y }
+ end
+
+ # @api public
+ # @return [Boolean] did it score a new point?
+ def scored?
+ !scored_at.nil?
+ end
+
+ # @api public
+ # @return [Boolean] did it fail?
+ def failed?
+ !failed_at.nil?
+ end
+
+ # @api public
+ # @param window [Window] the game's window
+ # @param pad [Pad] the game's pad
+ # @return [Integer, Float]
+ def reset_position!(window, pad)
+ self.x = pad.x + pad.width / 2 - 5
+ self.y = 450
+ end
+
+ private
+
+ # @api private
+ # @param axis [Symbol] which axis to check the collision
+ # @param window [Window] the game's window
+ # @return [Boolean]
+ def edge_collision?(axis, window)
+ !check_edge_collision(axis, window).nil?
+ end
+
+ # @api private
+ # @param axis [Symbol] which axis to check the collision
+ # @param window [Window] the game's window
+ # @return [Symbol] edge side where ball has collided
+ def check_edge_collision(axis, window)
+ if axis == :x && x + width >= window.get(:width)
+ :right
+ elsif axis == :x && x <= 0
+ :left
+ elsif axis == :y && y + height >= window.get(:height)
+ :bottom
+ elsif axis == :y && y <= 0
+ :top
+ end
+ end
+
+ # @api private
+ # @param pad [Pad] the game's pad
+ # @return [Boolean] has the ball collided with the pad?
+ def pad_collision?(pad)
+ y <= pad.y + pad.height && y + height >= pad.y &&
+ [x + width, pad.x + pad.width].min - [x, pad.x].max > 0
+ end
+
+ # @api private
+ # @param bricks [Hash] the game's bricks
+ # @return [Boolean] has the ball collided with any of the bricks?
+ def brick_collision?(bricks)
+ bricks.select do |brick|
+ y <= brick.y + brick.height && y + height >= brick.y &&
+ [x + width, brick.x + brick.width].min - [x, brick.x].max > 0
+ end
+ end
+end
diff --git a/brick/lib/match.rb b/brick/lib/match.rb
new file mode 100644
index 0000000..78885a9
--- /dev/null
+++ b/brick/lib/match.rb
@@ -0,0 +1,40 @@
+# Deals with the logic of the brick's match.
+# @author Miłosz Osiński
+class Match
+ attr_accessor :paused, :score, :reseted_at
+
+ # @api public
+ # @return [Match]
+ def initialize
+ @score = { left: 0, right: 0 }
+ @paused = true
+ end
+
+ # @api public
+ # @return [Boolaen]
+ alias paused? paused
+
+ # @api public
+ # @return [Boolaen]
+ def wait_to_start?
+ !reseted_at.nil?
+ end
+
+ # @api public
+ # @return [nil]
+ def check_wait!(current_frame)
+ self.reseted_at = nil if current_frame - reseted_at >= 60
+ end
+
+ # @api public
+ # @param window [Window] the game's window
+ # @param ball [Ball] the game's ball
+ # @param pad [Pad] the game's pad
+ # @return [Ingeter]
+ def restart!(window, ball, pad)
+ ball.scored_at = nil
+ ball.failed_at = nil
+ ball.reset_position!(window, pad)
+ self.reseted_at = window.get(:frames)
+ end
+end
diff --git a/brick/lib/paddle.rb b/brick/lib/paddle.rb
new file mode 100644
index 0000000..39e138e
--- /dev/null
+++ b/brick/lib/paddle.rb
@@ -0,0 +1,49 @@
+# Deals with the logic of the brick's paddle.
+# @author Miłosz Osiński
+class Paddle < Rectangle
+ DEFAULTS = { speed: 3 }.freeze
+
+ attr_accessor :speed, :constraints
+
+ # @api public
+ # @param speed [Integer, Float, nil] pad's current speed
+ # @param constraints [Hash] pad's constraints (e.g. max "y")
+ # @return [Pad]
+ def initialize(speed: nil, constraints: {}, **args)
+ super(args)
+ @speed = speed || DEFAULTS[:speed]
+ @constraints = constraints
+ end
+
+ # @api public
+ # @param event [Ruby2D::Window::KeyEvent] event captured from keyboard
+ # @param speed [Integer, Float, nil] pad's speed
+ # @return [Integer, Float] pad's current y position
+ def move(event, left:, right:)
+ if move_left?(event, left)
+ self.x -= speed
+ elsif move_right?(event, right)
+ self.x += speed
+ end
+ end
+
+ private
+
+ # @api private
+ # @param event [Ruby2D::Window::KeyEvent] event captured from keyboard
+ # @param up [String] expected keyboard key for the up movement
+ # @return [Boolean] is it allowed to move up?
+ def move_left?(event, left)
+ min_x = constraints.dig(:x, :min)
+ event.key == left && (!min_x || x - speed >= min_x)
+ end
+
+ # @api private
+ # @param event [Ruby2D::Window::KeyEvent] event captured from keyboard
+ # @param down [String] expected keyboard key for the down movement
+ # @return [Boolean] is it allowed to move down?
+ def move_right?(event, right)
+ max_x = constraints.dig(:x, :max)
+ event.key == right && (!max_x || x + speed + height <= max_x)
+ end
+end