The equation of a line
The line you probably know from school is , where is the slope and is where the line crosses the -axis. It has one flaw for games: a vertical line has no slope, so it can’t be written that way. The general equation of a line covers every line:
For a line through two points and , one choice of coefficients is
The vector is the line’s normal vector. It points straight out of the line, perpendicular to it.
Drag the two points below and watch the coefficients follow. Whenever the line isn’t vertical, the slope form can be read straight off them, and . Now line the points up vertically: becomes , the slope form has nothing to divide by, and carries on as if nothing happened.
type Line = { a: number; b: number; c: number };
function lineThrough(p1: Point, p2: Point): Line {
return { a: p2.y - p1.y, b: p1.x - p2.x, c: p2.x * p1.y - p1.x * p2.y };
}// A line is an object like { a: 1, b: -2, c: 5 }, for x - 2y + 5 = 0.
function lineThrough(p1, p2) {
return { a: p2.y - p1.y, b: p1.x - p2.x, c: p2.x * p1.y - p1.x * p2.y };
}@dataclass
class Line:
a: float
b: float
c: float
def line_through(p1: Point, p2: Point) -> Line:
return Line(p2.y - p1.y, p1.x - p2.x, p2.x * p1.y - p1.x * p2.y)lineThrough- time O(1) space O(1)
Which side of a line a point is on
Put any point into the left-hand side of the equation. For a point on the line, you get , which is what the equation says. For a point off the line, you get a number whose sign tells you which side of the line the point is on: positive on the side the normal vector points to, negative on the other. Every chapter from here on leans on this one number.
// ax + by + c for the point: 0 on the line, and its sign says which side.
function side(p: Point, line: Line): number {
return line.a * p.x + line.b * p.y + line.c;
}// ax + by + c for the point: 0 on the line, and its sign says which side.
function side(p, line) {
return line.a * p.x + line.b * p.y + line.c;
}def side(p: Point, line: Line) -> float:
"""ax + by + c for the point: 0 on the line, and its sign says which side."""
return line.a * p.x + line.b * p.y + line.cside- time O(1) space O(1)
The sign is useful on its own, too: it tells you which side of a wall the player is on.
Distance from a point to a line
The size of that number grows with the distance from the line, multiplied by the length of the normal vector, . Divide that length out and you have the distance:
Drag across the line and watch the sign flip, and the distance shrink to on the line itself.
function distanceToLine(p: Point, line: Line): number {
return Math.abs(side(p, line)) / Math.hypot(line.a, line.b);
}function distanceToLine(p, line) {
return Math.abs(side(p, line)) / Math.hypot(line.a, line.b);
}def distance_to_line(p: Point, line: Line) -> float:
return abs(side(p, line)) / math.hypot(line.a, line.b)distanceToLine- time O(1) space O(1)
Circle vs line
A circle touches a line when its centre is at most away from it. With the squaring trick, that’s : no root, and no division.
function circleLineCollide(c: Circle, line: Line): boolean {
return side(c, line) ** 2 <= c.r ** 2 * (line.a ** 2 + line.b ** 2);
}function circleLineCollide(c, line) {
return side(c, line) ** 2 <= c.r ** 2 * (line.a ** 2 + line.b ** 2);
}def circle_line_collide(c: Circle, line: Line) -> bool:
return side(c, line) ** 2 <= c.r ** 2 * (line.a ** 2 + line.b ** 2)circleLineCollide- time O(1) space O(1)
This line never ends. Walls and platforms do, which is what the next chapter is about.
Comments
No comments yet. Questions and corrections are welcome.