# HC.shapes¶

shapes = require 'HC.shapes'


Shape classes with collision detection methods.

This module defines methods to move, rotate and draw shapes created with the main module.

As each shape is at it’s core a Lua table, you can attach values and add functions to it. Be careful not to use keys that name a function or start with an underscore, e.g. move or _rotation, since these are used internally. Everything else is fine.

If you don’t want to use the full blown module, you can still use these classes to test for colliding shapes. This may be useful for scenes where the shapes don’t move very much and only few collisions are of interest - for example graphical user interfaces.

## Base Class¶

class Shape(type)
Arguments: type (any) – Arbitrary type identifier of the shape’s type.

Base class for all shapes. All shapes must conform to the interface defined below.

Shape:move(dx, dy)
Arguments: dx,dy (numbers) – Coordinates to move the shape by.

Move the shape by some distance.

Example:

circle:move(10, 15) -- move the circle 10 units right and 15 units down.

Shape:moveTo(x, y)
Arguments: x,y (numbers) – Coordinates to move the shape to.

Move the shape to some point. Most shapes will be centered on the point (x,y).

Note

Equivalent to:

local cx,cy = shape:center()
shape:move(x-cx, y-cy)


Example:

local x,y = love.mouse.getPosition()
circle:moveTo(x, y) -- move the circle with the mouse

Shape:center()
Returns: x, y - The center of the shape.

Get the shape’s center.

Example:

local cx, cy = circle:center()
print("Circle at:", cx, cy)

Shape:rotate(angle[, cx, cy])
Arguments: angle (number) – Amount of rotation in radians. cx, cy (numbers) – Rotation center; defaults to the shape’s center if omitted (optional).

Rotate the shape by some angle. A rotation center can be specified. If no center is given, rotate around the center of the shape.

Example:

rectangle:rotate(math.pi/4)

Shape:setRotation(angle[, cx, cy])
Arguments: angle (number) – Amount of rotation in radians. cx, cy (numbers) – Rotation center; defaults to the shape’s center if omitted (optional).

Set the rotation of a shape. A rotation center can be specified. If no center is given, rotate around the center of the shape.

Note

Equivalent to:

shape:rotate(angle - shape:rotation(), cx,cy)


Example:

rectangle:setRotation(math.pi, 100,100)

Shape:rotation()
Returns: The shape’s rotation in radians.

Get the rotation of the shape in radians.

Shape:scale(s)
Arguments: s (number) – Scale factor; must be > 0.

Scale the shape relative to it’s center.

Note

There is no way to query the scale of a shape.

Example:

circle:scale(2) -- double the size

Shape:outcircle()
Returns: x, y, r - Parameters of the outcircle.

Get parameters of a circle that fully encloses the shape.

Example:

if player:hasShield() then
love.graphics.circle('line', player:outcircle())
end

Shape:bbox()
Returns: x1, y1, x2, y2 - Corners of the counding box.

Get axis aligned bounding box. x1, y1 defines the upper left corner, while x2, y2 define the lower right corner.

Example:

-- draw bounding box
local x1,y1, x2,y2 = shape:bbox()
love.graphics.rectangle('line', x1,y1, x2-x1,y2-y1)

Shape:draw(mode)
Arguments: mode (DrawMode) – How to draw the shape. Either ‘line’ or ‘fill’.

Draw the shape either filled or as outline. Mostly for debug-purposes.

Example:

circle:draw('fill')

Shape:support(dx, dy)
Arguments: dx, dy (numbers) – Search direction. The furthest vertex in direction dx, dy.

Get furthest vertex of the shape with respect to the direction dx, dy.

Used in the collision detection algorithm, but may be useful for other things - e.g. lighting - too.

Example:

-- get vertices that produce a shadow volume
local x1,y1 = circle:support(lx, ly)
local x2,y2 = circle:support(-lx, -ly)

Shape:collidesWith(other)
Arguments: other (Shape) – Test for collision with this shape. collide, dx, dy - Collision indicator and separating vector.

Test if two shapes collide.

The separating vector dx, dy will only be defined if collide is true. If defined, the separating vector will point in the direction of other, i.e. dx, dy is the direction and magnitude to move other so that the shapes do not collide anymore.

Example:

if circle:collidesWith(rectangle) then
print("collision detected!")
end

Shape:contains(x, y)
Arguments: x, y (numbers) – Point to test. true if x,y lies in the interior of the shape.

Test if the shape contains a given point.

Example:

if unit.shape:contains(love.mouse.getPosition) then
unit:setHovered(true)
end

Shape:intersectionsWithRay(x, y, dx, dy)
Arguments: x, y (numbers) – Starting point of the ray. dx, dy (numbers) – Direction of the ray. Table of ray parameters.

Test if the shape intersects the given ray. The ray parameters of the intersections are returned as a table. The position of the intersections can be computed as (x,y) + ray_parameter * (dx, dy).

Example:

local ts = player:intersectionsWithRay(x,y, dx,dy)
for _, t in ipairs(t) do
-- find point of intersection
local vx,vy = vector.add(x, y, vector.mul(t, dx, dy))
end

Shape:intersectsRay(x, y, dx, dy)
Arguments: x, y (numbers) – Starting point of the ray. dx, dy (numbers) – Direction of the ray. intersects, ray_parameter - intersection indicator and ray paremter.

Test if the shape intersects the given ray. If the shape intersects the ray, the point of intersection can be computed by (x,y) + ray_parameter * (dx, dy).

Example:

local intersecting, t = player:intersectsRay(x,y, dx,dy)
if intersecting then
-- find point of intersection
local vx,vy = vector.add(x, y, vector.mul(t, dx, dy))
end


## Custom Shapes¶

Custom shapes must implement at least the following methods (as defined above)

## Built-in Shapes¶

class ConcavePolygonShape()
class ConvexPolygonShape()
class CircleShape()
class PointShape()
newPolygonShape(...)
Arguments: ... (numbers) – Vertices of the Polygon().
newCircleShape(cx, cy, radius)
Arguments: cx,cy (numbers) – Center of the circle. radius (number) – Radius of the circle.
newPointShape()
Arguments: x, y (numbers) – Position of the point.