Fast Collisions Using Pixels colors

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
Roland_Yonaba
Inner party member
Posts: 1563
Joined: Tue Jun 21, 2011 6:08 pm
Location: Ouagadougou (Burkina Faso)
Contact:

Fast Collisions Using Pixels colors

Post by Roland_Yonaba »

Hi all,

Well, I didn't really know where to post it, then I chose this section.
Maybe a lot of you might have heard about collisions using pixels colors.
I've used this, and it works fine...But in most of the cases, it generally ends up making your game going sloooow...
So, if you want something similar, but fast, here you are.

First, you load the image and convert it to a kind of 'binary' table of strings...
0 for pixels whose alphavalue is 0, and 1 for the others.

Code: Select all

-- First, let's load our sprite
function love.graphics.loadSprite(s)
	local s = love.image.newImageData(s)
	local w,h = s:getWidth(),s:getHeight()  -- gets image width and height
	local batch = {} -- Converts the sprite into a sort of binary table...0 matches pixels with transparency
		for y = 0,h-1 do batch[y+1] = ''
			for x = 0,w-1 do
			local _,_,_,a = s:getPixel(x,y)
			batch[y+1] = ((a == 0) and batch[y+1]..'0' or batch[y+1]..'1')
			end
		end
		
		return { -- Returns a custom structure
					map = batch,  -- the 'binary' sprite
					x = 0, y = 0,   -- screen coordinates 
					width = w,  -- width
					height = h, -- height
					img = love.graphics.newImage(s),   -- userdata sprite image
					printMap = function()   -- a function for printing the 'binary' sprite
									for k,v in ipairs(batch) do
										print(v)
									end
								end
					
								
				}

end

Now comes the good stuff..
We first check for a simple box collision between objects 1 and 2. In case these objects are not touching each other, there's no worth making the rest of the calculations, so we return false.
But in case the two objects are touching each other, we just computes the coordinates, the width and height of the 'overlapping' area, and we just cout out from the 'binary' representation of the two objects the corresponding values. If they matches string '2', there is definitely a collision..

Code: Select all

-- Simple box collision check
local function simpleCollide(o1,o2)
	return ((o1.x + o1.width > o2.x) and (o1.x < o2.x + o2.width) and (o1.y + o1.height > o2.y) and (o1.y < o2.y + o2.height))
end

-- The fast pixel collision check function
local function fastCollide(o1,o2)		
		
		-- If there is no box collision, no need to continue
	if not simpleCollide(o1,o2) then 
		return false 
	end

	-- Calculate the left,right,up,down coordinates of the two sprites overlapping area

	local Left,Right,Up,Down
	local cLeft,cRight,cUp,cDown
	
	o1.x = math.floor(o1.x)
	o1.y = math.floor(o1.y)
	o2.x = math.floor(o2.x)
	o2.y = math.floor(o2.y)	
	
		if o1.x > o2.x then 
			cLeft = o1.x 
			Left = 1
			Right = o1.x-o2.x + 1
		else 
			cLeft = o2.x
			Left = o2.x-o1.x + 1
			Right = 1
		end
	
		if o1.y > o2.y then 
			cUp = o1.y 
			Up = 1
			Down = o1.y-o2.y + 1
		else
			cUp = o2.y 
			Up = o2.y-o1.y + 1
			Down = 1
		end
	
		if (o1.x + o1.width) > (o2.x + o2.width) then 
			cRight = (o2.x + o2.width)
		else
			cRight = (o1.x + o1.width) 
		end
		
		if (o1.y + o1.height) > (o2.y + o2.height) then 
			cDown = (o2.y + o2.height) 
		else
			cDown = (o1.y + o1.height)
		end
	
	local overLap_width = cRight-cLeft
	local overLap_height = cDown-cUp	
	
	-- Cuts the corresponding string into the sprites 'binary' tables
	-- Collision if effective when the resulting string matches '2'
	for i = 0, overLap_height-1 do
		local o_1 = tonumber(o1.map[i+Up]:sub(Left, Left+overLap_width)) or 0
		local o_2 = tonumber(o2.map[i+Down]:sub(Right, Right+overLap_width)) or 0
			if tostring(o_1+o_2):match '2' then return true end
	end
	
	return false	-- Otherwise, no collision

end

Usage example:

Code: Select all

local obj1 = love.graphics.loadSprite('picture1path')
local obj2 = love.graphics.loadSprite('picture2path')

function love.draw()
...
if fastCollide(obj1,obj2) then ...  end
...
end
 
Here you are...Pretty easy, isn't it ?
Thanks for reading!
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 40 guests