collision:
Point to Rect


A point collides with a rectangle when the point's coordinates fall within the rectangle's four sides, also called the rectangle's "bounds", or in games they are often called "hitboxes". We know when a point is inside of a rectangle by comparing the point's coordinates with each side of the rectangle. Only when all four comparisons are true do we know that the point has collided with the rectangle.

 

No Collision

 

PICO-8 Collision Function

function point_rect_collision( p, r )
  return p.x >= r.x and
         p.x <= r.x+r.w and
         p.y >= r.y and
         p.y <= r.y+r.h
end
 

Comparing Coordinates

First, we need an easy way to store the coordinates of a point and the sides of a rectangle on the screen. We can do that with 2 tables that store separate X, Y, width, and height variables. Those tables (named pfor point and r for rectangle) are what the above function expects.

They would be created like this: 

--create object tables
p = { x=10, y=20 }
r = { x=30, y=40, w=10, h=10 }

Now we have a point, starting at coordinates X and Y, and a rectangle at coordinates X and Y, and with a width of w and a height of h. To get the value of point 1's x, we use p.x. (See Table Shorthand)

--get value out of point table
print( p.x )  --prints 10

We also need to be able to get the sides of the rectangle, so we can compare them with the point.

--get sides of rectangle table
print( r.x )      --left side
print( r.x+r.w )  --right side
print( r.y )      --top side
print( r.y+r.h )  --bottom side

Next, we want to compare the point's X with the rectangle's left and right sides, and the point's Y with the rectangle's top and bottom sides. In expanded form, this check can be written as:

--compare x
if p.x >= r.x then print("right of left side") end
if p.x <= r.x+r.w then print("left of right side") end

--compare y
if p.y >= p.y then print("below top side") end
if p.y <= p.y then print("above bottom side") end

We can do all of those checks at the same time using the and operator:

--compare point with 4 sides
if  p.x >= r.x
and p.x <= r.x+r.w
and p.y >= r.y 
and p.y <= r.y+r.h then
	print("point is inside rectangle")
end

Understanding an Expanded Version

Now that we have a point with coordinates, as well as a rectangle with coordinates and dimensions, and we know how to compare the point to all 4 sides of the rectangle, we can put it all together into an expanded function like this:

--expanded example
function point_rect_collision( p, r )
	if  p.x >= r.x
	and p.x <= r.x+r.w
	and p.y >= r.y 
	and p.y <= r.y+r.h then   
		return true
	else
		return false
	end
end

This function has parameters (p,r) and it is expecting those to be objects with X and Y keys, and the r to also have W and H keys. 

The function has 1 if statement that compares the point with each side of the rectangle. The and operator is used to make sure that all four of those checks are true before running the code inside: return true, which will send the value true back to where this function was called.

If any one of those checks are false, then the code after else will run instead, which will return the value false.

You can call this function in two ways to catch the returned true or false result:

--catch result in variable
is_colliding = point_rect_collision( p, r )

if is_colliding then
	print("collided!")
end

--directly inside of if statement
if point_rect_collision( p, r ) then
	print("collided!")
end

Note that these examples use the same argument names and parameter names just for the convenience of this tutorial, but to make the difference clear, this is how the parameters of the function still uses (p,r) but the arguments when calling the function could be any object table such as:

bullet = { x=10, y=20 }
enemy = { x=30, y=40, w=8, h=8 }

if point_rect_collision( bullet, enemy ) then
	print("collided!")
end

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


Understanding the Simplified Version

We can simplify and condense the expanded version down to a single line:

function point_rect_collision( p, r )
  return p.x >= r.x and p.x <= r.x+r.w and p.y >= r.y and p.y <= r.y+r.h 
end

(This is the same function as under the interactive demo, but we removed the new lines.)

This works the exact same way as the expanded version because the comparisons of the point to each side of the rectangle will result in either true or false the same way it does in an if statement. So we don't need the if statement at all.

The expanded function boils down to "if all checks true, return true, and if any are false, return false" which is an unnecessary step to explicitly return true or false since what we want to return is the same as the final result of the four comparisons.

So we can just return the result of the comparisons immediately in a single step and it does the same thing.



Point to Rectangle Collision can be used in a variety of games whenever you have something as small as a single pixel and another thing any size larger. A classic game that would use this is Duck Hunt, where the "gun" is a single point on the screen that you could move around with the arrow keys or the mouse instead of the actual NES hardware.

The duck sprite would be the rectangle which we drew here but the rectangle hitbox would be invisible to the player in the actual game. The point that we check collision with would be the center point of the reticle.


Another classic game example is Contra, and so this is true for many shooting games where the bullets are small enough to consider them points, and you want to check collision of the bullets with enemies or other game objects. Note that we could draw the bullets as larger sprites but still use point to rectangle collision on them where the point is the center of the sprite. Again, the red rectangle around the enemy would not be visible in the actual game.


A third example is when you have a cursor that freely moves around the screen, either controlled by the mouse or just arrow keys. You may want the cursor to interact with buttons in a menu, or select units in a strategy game.

Notice that we drew the mouse with a single red pixel at the point. All of the red indicators in this example would be invisible in the actual game. This demonstrates that even when using a larger sprite such as a mouse cursor icon, in code, we consider it as just a single point at the tip that we use to check collision.




39

9 Apr 2025

Font