### Part 0: Common Ground^ top

I suck at writing Introductions, so let's dive right in:

This tutorial will teach you how to use HardonCollider. It is divided into three parts:

• Part One covers the basic concepts of the library.
• Part Two introduces more shapes and more concepts.
• Part Three offers a complex collision detection task and shows some coding tricks that make your life easier.

#### Prerequisites

You should already know how to program games with Lua and LÖVE. If not, this, this, this and also this, this and this and finally this will get you started.

### Part 1: Hello, PONG!^ top

In our first steps with HardonCollider we will write (yet another) clone of Pong. Using a collision detection library for this task is probably a little over the top, but Pong serves well to introduce some of the libraries core concepts. Let's begin:

Create a new folder called `hardonpong`. Download the latest version of HardonCollider and put it into that directory. Create an empty file named `main.lua`. The directory content should look like this before we go on:

```hardonpong
|-- hardoncollider
|   |-- class.lua
|   |-- init.lua
|   |-- polygon.lua
|   |-- shapes.lua
|   |-- spatialhash.lua
|   `-- vector-light.lua
`-- main.lua```

#### Holy Trinity and a Half

Fill your main.lua with the following:

``````HC = require 'hardoncollider'

function on_collide(dt, shape_a, shape_b)
end

function love.load()
Collider = HC(100, on_collide)
end

function love.update(dt)
Collider:update(dt)
end

function love.draw()
end``````

This is the basic code skeleton for using HardonCollider.

`HC = require 'hardoncollider'` loads the module and puts it into the variable `HC`.

The next lines defines an empty function called `on_collide` in which we will handle what should happen when two shapes collide. We will cover the different parameters later.

`Collider = HC(100, on_collide)` creates a new collision detection instance, setting `on_collide` as callback function. The first argument defines a cell size which is used internally to speed things up. You don't have to worry about that at the moment.

Finally, `Collider:update(dt)` will check for collisions and run the callback functions if needed.

#### Filling the Void

Pong wouldn't be Pong without two paddles and a ball. In fact, it wouldn't be anything. So let's add them by creating two rectangles and a circle shape:

``````function love.load()
Collider = HC(100, on_collide)

ball        = Collider:addCircle(400,300, 10)
paddleLeft  = Collider:addRectangle(10,250, 20,100)
paddleRight = Collider:addRectangle(770,250, 20,100)

ball.velocity = {x = -100, y = 0}
end``````

We now have defined three shapes that are subject to collision detection. Because shapes are just Lua tables with some functions and properties in them, we can add anythin we like to them. We exploit this by adding a table named `velocity` to the ball, which will be used to move the it.

To see what we've created, we need to draw the shapes. Mostly for debugging purposes, shapes have functions for drawing themselves. We, however, will not use these functions for debugging, but as our only means to show what's going on:

``````function love.draw()
-- we can also use 'line' instead of 'fill'
ball:draw('fill', 16)    -- approximated circle with 16 edges
paddleLeft:draw('fill')
paddleRight:draw('fill')
end``````

To put things in motion (haha, get it?), we change the position of the ball according to it's velocity:

``````function love.update(dt)
ball:move(ball.velocity.x * dt, ball.velocity.y * dt)

-- check for collisions
Collider:update(dt)
end``````

#### Rebound

If you run what we have done so far, you will see the ball moving very, very slowly from the screen center to the left paddle. And then passing it. That's not Pong! The ball needs to bounce off the paddle. This is where `on_collide(dt, shape_a, shape_b)` comes in handy.

`on_collide()` will be called whenever two shapes collide (actually only when they first collide, more about that in Part 3). It's first argument `dt` is the same as to `love.update()`: the time passed since the last call of `love.update()`. The other two parameters are the shapes that are involved in the collision.

If the ball collides with a paddle, it should bounce off depending where on the paddle it hit it. We can get the current (center-)position of a shape by using shape:center(). Thus, by getting the difference between the ball's and the paddle's center's y-component, we can determine in what direction the ball should bounce off:

``````function on_collide(dt, shape_a, shape_b)
-- determine which shape is the ball and which the paddle
local paddle
if shape_a == ball then
paddle = shape_b
else
paddle = shape_a
end

-- reflect the ball on the paddle
local px,py = paddle:center()
local bx,by = ball:center()
ball.velocity.x = -ball.velocity.x
ball.velocity.y = by - py

-- keep the ball at the same speed as before
local len = math.sqrt(ball.velocity.x^2 + ball.velocity.y^2)
ball.velocity.x = ball.velocity.x / len * 100
ball.velocity.y = ball.velocity.y / len * 100
end``````

Although being a hypnotic, this has little to no entertainment value: We cannot move the paddles. Let's fix that:

``````function love.update(dt)
ball:move(ball.velocity.x * dt, ball.velocity.y * dt)

-- left player movement
if love.keyboard.isDown('w') then
paddleLeft:move(0, -100 * dt)
elseif love.keyboard.isDown('s') then
paddleLeft:move(0,  100 * dt)
end

-- right player movement
if love.keyboard.isDown('up') then
paddleRight:move(0, -100 * dt)
elseif love.keyboard.isDown('down') then
paddleRight:move(0,  100 * dt)
end

-- check for collisions
Collider:update(dt)
end``````

#### Re-Rebound

Hooray, we've done it! Or have we? As it turns out, we have missed two very important parts: The ball won't bounce off the upper and lower screen border and it's not reset to the screen center once a player scores a goal. We can do both by introducing more shapes defining special zones. These shapes won't be drawn - they are off screen anyway.

``````function love.load()
-- ... as before ...

borderTop    = Collider:addRectangle(0,-100, 800,100)
borderBottom = Collider:addRectangle(0,600, 800,100)
goalLeft     = Collider:addRectangle(-100,0, 100,600)
goalRight    = Collider:addRectangle(800,0, 100,600)
end``````

We also need to define what happens when the ball touches a border or a goal. Because there are now more things that can collide, the collision callback has to change:

``````function on_collide(dt, shape_a, shape_b)
-- determine which shape is the ball and which is not
local other
if shape_a == ball then
other = shape_b
elseif shape_b == ball then
other = shape_a
else -- neither shape is the ball. exit
return
end

-- reset on goal
if other == goalLeft then
ball.velocity = {x = 100, y = 0}
ball:moveTo(400,300)
elseif other == goalRight then
ball.velocity = {x = -100, y = 0}
ball:moveTo(400,300)
elseif other == borderTop or other == borderBottom then
-- bounce off top and bottom
ball.velocity.y = -ball.velocity.y
else
-- bounce of paddle
local px,py = other:center()
local bx,by = ball:center()
local dy = by - py
ball.velocity.x = -ball.velocity.x
ball.velocity.y = dy

-- keep the ball at the same speed
local len = math.sqrt(ball.velocity.x^2 + ball.velocity.y^2)
ball.velocity.x = ball.velocity.x / len * 100
ball.velocity.y = ball.velocity.y / len * 100
end
end``````

Because we want to react on collision only when the ball is involved, we return early if neither one of the shapes is the ball - can you tell what these shapes are in this case? (answer). The rest is relatively straightforward: If the ball hits a goal, it is reset to the screen center and will move to the scoring player's paddle. If the ball hit's either the top or bottom screen edge, it's y-direction is inverted. If it hit's one of the paddles, it is bounced off as before.

#### The Whole Picture

And there you have it: Your very first and very feature lacking Pong-clone using HardonCollider:

``````HC = require 'hardoncollider'

function on_collide(dt, shape_a, shape_b)
-- determine which shape is the ball and which is not
local other
if shape_a == ball then
other = shape_b
elseif shape_b == ball then
other = shape_a
else -- no shape is the ball. exit
return
end

-- reset on goal
if other == goalLeft then
ball.velocity = {x = 100, y = 0}
ball:moveTo(400,300)
elseif other == goalRight then
ball.velocity = {x = -100, y = 0}
ball:moveTo(400,300)
elseif other == borderTop or other == borderBottom then
-- bounce off top and bottom
ball.velocity.y = -ball.velocity.y
else
-- bounce of paddle
local px,py = other:center()
local bx,by = ball:center()
local dy = by - py
ball.velocity.x = -ball.velocity.x
ball.velocity.y = dy

-- keep the ball at the same speed
local len = math.sqrt(ball.velocity.x^2 + ball.velocity.y^2)
ball.velocity.x = ball.velocity.x / len * 100
ball.velocity.y = ball.velocity.y / len * 100
end
end

function love.load()
Collider = HC(100, on_collide)

ball        = Collider:addCircle(400,300, 10)
leftPaddle  = Collider:addRectangle(10,250, 20,100)
rightPaddle = Collider:addRectangle(770,250, 20,100)

ball.velocity = {x = -100, y = 0}

borderTop    = Collider:addRectangle(0,-100, 800,100)
borderBottom = Collider:addRectangle(0,600, 800,100)
goalLeft     = Collider:addRectangle(-100,0, 100,600)
goalRight    = Collider:addRectangle(800,0, 100,600)
end

function love.update(dt)
ball:move(ball.velocity.x * dt, ball.velocity.y * dt)

-- left player movement
if love.keyboard.isDown('w') then
leftPaddle:move(0, -100 * dt)
elseif love.keyboard.isDown('s') then
leftPaddle:move(0,  100 * dt)
end

-- right player movement
if love.keyboard.isDown('up') then
rightPaddle:move(0, -100 * dt)
elseif love.keyboard.isDown('down') then
rightPaddle:move(0,  100 * dt)
end

Collider:update(dt)
end

function love.draw()
ball:draw('fill', 16)
leftPaddle:draw('fill')
rightPaddle:draw('fill')
end``````

#### Room for Improvements

There is a lot of things you can do to not only make this game more fun but also practice using HardonCollider:

• Keep player scores by incrementing a goal-counter every time the ball hits a goal.
• Limit the paddle's movement so that they cannot leave the screen (Hint: Use `paddleLeft:center()` and `paddleRight:center()`).
• Add fancy graphics instead of using the shapes' draw functions.
• Add power-ups and traps that get randomly spawned between the paddles and are activated once the ball collides with them.
• Increase the speed of the ball every time it hit's a paddle.
• Add paddles to the top and bottom and make a four player game out of hardonpong.
• Add multiple balls depending on how often the ball hit the paddles.
• Randomly spawn obstacles that deflect the ball but get destroyed once the ball hit them.

### Part 2: Fly Me To The Moon^ top

This space intentionally left blank.

### Part 3: Down To Earth^ top

This space intentionally left blank.