collision:
Line to Point


A line segment collides with a point when the point lies directly on the line, but instead of checking if the point intersects with every possible position along the line, we can calculate the distance from the point to the line using vectors, then verify the point falls within the line segment's boundaries to know if they touch or overlap.

 

No Collision

 

PICO-8 Collision Function

function line_point_collision(l,p)
	return abs((l.x2-l.x1)*(l.y1-p.y)-(l.x1-p.x)*(l.y2-l.y1))<.1and p.x>=min(l.x1,l.x2)and p.x<=max(l.x1,l.x2)and p.y>=min(l.y1,l.y2)and p.y<=max(l.y1,l.y2)
end
 

Storing Line and Point Data

First, we need to store the coordinates of a line segment and a point. A line segment needs two endpoints, so we'll use 4 coordinates (x1,y1) and (x2,y2). A point just needs its position (x,y). We can store these as tables:

--create a line segment and point as object tables
line = { x1=10, y1=20, x2=50, y2=80 }
point = { x=30, y=50 }

Now we have a line segment from point (10,20) to (50,80), and a point at (30,50). To access these values, we use the dot notation (See Table Shorthand).

--get values out of line and point tables
print( line.x1 )  -- 10
print( point.x )  -- 30

The Mathematical Approach

To check if a point lies on a line segment, we need to verify two things:

1. The point lies somewhere on the infinite line that extends through the line segment

2. The point falls within the bounds of our finite line segment

If both of those are true, then the point is intersecting with the line.


For the first check, we use the cross product formula to get the distance from the point to the line. If a point lies exactly on a line, the cross product of vectors will be zero or nearly zero:

--check if point lies on infinite line
distance = abs((line.x2-line.x1)*(line.y1-point.y)-(line.x1-point.x)*(line.y2-line.y1))
if distance < 0.1 then 
    print("point is on the line")
end

For the second check, we verify the point is within the bounding rectangle of our line segment:

--check if point is within line segment bounds
if  point.x >= min(line.x1, line.x2) 
and point.x <= max(line.x1, line.x2)
and point.y >= min(line.y1, line.y2) 
and point.y <= max(line.y1, line.y2) then
    print("point is within bounds")
end

Understanding an Expanded Version

Here's how we can write this as a complete function with clear steps:

--expanded example
function line_point_collision( line, point )
    --calculate distance from point to infinite line
    local distance = abs((line.x2-line.x1)*(line.y1-point.y)-(line.x1-point.x)*(line.y2-line.y1))

    --check if point is close enough to the line
    local on_line = distance < 0.1

    --check if point is within line segment bounds
    local in_x_bounds = point.x >= min(line.x1, line.x2) and point.x <= max(line.x1, line.x2)
    local in_y_bounds = point.y >= min(line.y1, line.y2) and point.y <= max(line.y1, line.y2)

    if on_line and in_x_bounds and in_y_bounds then
        return true
    else
        return false
    end
end

This function has parameters (line, point) and expects the line to have x1,y1,x2,y2 coordinates and the point to have x,y coordinates.

The function first calculates how far the point is from the infinite line using the cross product formula. Then it checks if this distance is small enough (less than 0.1) to consider the point "on" the line. Finally, it verifies the point falls within the actual line segment bounds.


You can call this function two ways to detect collisions:

--catch result in variable
is_colliding = line_point_collision( line, point )

if is_colliding then
    print("collision detected!")
end

--directly inside of if statement
if line_point_collision( line, point ) then
    print("collision detected!")
end

Example with different object names:

wall = { x1=80, y1=50, x2=80, y2=100 }
bullet = { x=10, y=50 }

if line_point_collision( wall, bullet ) then
    print("bullet hit wall!")
end

(See more examples below in When to Use this?)


Understanding the Simplified Version

We can condense the expanded version into just these 3 lines shown at the top:

function line_point_collision(line, point)
  return abs((line.x2-line.x1)*(line.y1-point.y)-(line.x1-point.x)*(line.y2-line.y1)) < 0.1
         and point.x >= min(line.x1, line.x2) and point.x <= max(line.x1, line.x2)
         and point.y >= min(line.y1, line.y2) and point.y <= max(line.y1, line.y2)
end

This works the same way because all our conditions are combined with and operators. The function returns true only when the point is close enough to the line AND within the x bounds AND within the y bounds. If any of those conditions fails, the whole expression becomes false.

The 0.1 tolerance accounts for floating point precision issues - in pixel-perfect games, you might use an even smaller value or check for exact equality if working with integers.



Line-to-Point Collision is useful when you need to detect if projectiles, characters, or other game objects intersect with line-based boundaries, walls, or barriers in your game. This is also perfect for games with laser beams, light rays, or any visual effects that are drawn as thin lines but need precise collision detection with game objects represented as points or small sprites.


Electroplankton; tadpole points and leaf lines

Electroplankton may be a more obscure example than our others. It is a Nintendo DS game for making music through manipulating visual scenes such as this physics-based minigame where a tadpole shoots out of the left leaf, and bounces down between the other leaves. When they collide, they create a sound. Here is an example of this game made in PICO-8 using actual points and lines:



Retro-Racer (mockup)

In this example, the collision could be simplified to points on either side of the car (shown as blue) and lines as the road edges. This collision would be used to check if either edge of the car is at the edge of the road. 


road_left = { x1=50, y1=40, x2=10, y2=127 }
car_left= { x=50, y=100}

if line_point_collision( road_left, car_left ) then
    --bump, slow car, damage car, move right
end



60

21 Aug 2025

Font