Collision detection between rectangle and line segment

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
darkfrei
Party member
Posts: 1168
Joined: Sat Feb 08, 2020 11:09 pm

Collision detection between rectangle and line segment

Post by darkfrei »

Hi all!

Here is a way how to detect collision between rectangle and line.
Here the line is not love line, but the object with

Code: Select all

objLine = {
x=x, y=y, w=w, h=h, line=line
}
Here the x and y are coordinates of top and left positions of both points of the line segment.

Code: Select all

local function newObjLine (line)
	local x1, y1, x2, y2 = line[1], line[2], line[3], line[4] -- two points of love line
	local x, y = math.min (x1, x2), math.min (y1, y2)
	local w, h = math.max (x1, x2) - x, math.max (y1, y2) - y
	local objLine = {
		line = {x1-x, y1-y, x2-x, y2-y},
		x=x, y=y, w=w, h=h -- bounding box of the line's object
	}
	return objLine
end
After that, we can check if here is no collision just with AABB collision detection:

Code: Select all

local function isRoughCollision(a, b) -- a and b are objects with x, y, w, h as bounding boxes
  return a.x < b.x+b.w and a.y < b.y+b.h and 
         b.x < a.x+a.w and b.y < a.y+a.h
end
(Also after several tweaks you can use the bump.lua to detect this rough collision detection.)

After that, there is an easy way to detect if the all 4 points of rectangle are on the same side of line (it means no collision too)^

Code: Select all

local function psm (ax, ay, bx, by) -- pseudoScalarMutiplication
	return ax*by-ay*bx -- returns positive or negative area of two vectors
end

local function isFineCollision(obj, objLine)
	local line = objLine.line
	local x, y = objLine.x, objLine.y
-- points of line:
	local x1, y1 = x+line[1], y+line[2]
	local x2, y2 = x+line[3], y+line[4]
-- 4 vertices of rectangle:
	local p1x, p1y = obj.x, obj.y
	local p2x, p2y = obj.x+obj.w, obj.y
	local p3x, p3y = obj.x+obj.w, obj.y+obj.h
	local p4x, p4y = obj.x, obj.y+obj.h

	local v1 = psm (x2-x1, y2-y1, p1x-x1, p1y-y1)
	local v2 = psm (x2-x1, y2-y1, p2x-x1, p2y-y1)
	local v3 = psm (x2-x1, y2-y1, p3x-x1, p3y-y1)
	local v4 = psm (x2-x1, y2-y1, p4x-x1, p4y-y1)

	if math.min (v1, v2, v3, v4) > 0 then -- all positive
		-- no collision
	elseif math.max (v1, v2, v3, v4) < 0 then -- all negative
		-- no collision
	else
		return true -- collision
	end
end
So, the example code:

Code: Select all

local line = {100, 200, 300, 100}
local rectangle = {x=200, y=140, w=20, h=20}
local objLine = newObjLine (line)
if isRoughCollision(rectangle, objLine) and isFineCollision(rectangle, objLine) then
	print ('collision')
else
	print ('no collision')
end
Don't forget to add the push-pop block to the love.draw:

Code: Select all

function love.draw()
	love.graphics.push()
		love.graphics.translate(objLine.x, objLine.y)
		love.graphics.line (objLine.line)
	love.graphics.pop()
end
Attachments
rectangle-to-line-collision-detection.lua
(1.69 KiB) Downloaded 110 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

Users browsing this forum: No registered users and 20 guests