Fast Collisions Using Pixels colors
Posted: Sun Aug 07, 2011 7:17 pm
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.
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..
Usage example:
Here you are...Pretty easy, isn't it ?
Thanks for reading!
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
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
Thanks for reading!