Here are a lot of static collision detection routines its got a whole slew of primitives so feel free to dive in here and use whatever you find useful. These are just the routines though as there is too many to show an example of how the work but they are all tested and work rather well. They all return true / false in the event of a collision or lack thereof. To speed them up a little make sure that your primitives have their vertices arranged in clockwise order. Some of the routines (with triangle and quads etc.) are dependent on other routines (line intersections mostly)
sub point2point(x0,y0, x1,y1)
if (x0 = x1) and (y0 = y1) return 1
return 0
end sub
sub point2circle(x0,y0, x1,y1,r)
if (abs(x0-x1)^2 + abs(y0-y1)^2 < r^2) return 1
return 0
end sub
sub point2line(x0,y0, x1,y1,x2,y2)
if ((x1-x0)*(y2-y0) - (x2-x0)*(y1-y0) = 0) return 1
return 0
end sub
sub point2segment(x0,y0, x1,y1,x2,y2)
if ((x1-x0)*(y2-y0) - (x2-x0)*(y1-y0) = 0) then // Crossproduct
if (x0 > x1) and (x0 < x2) return 1 // Boolean logic
if (x0 > x2) and (x0 < x1) return 1 // Boolean logic
endif
return 0
end sub
sub point2box(x0,y0, x1,y1,x2,y2)
if (x0 > x1) and (x0 < x2) then
if (y0 > y1) and (y0 < y2) return 1
if (y0 > y2) and (y0 < y1) return 1
elsif (x0 > x2) and (x0 < x1) then
if (y0 > y1) and (y0 < y2) return 1
if (y0 > y2) and (y0 < y1) return 1
endif
return 0
end sub
sub point2tri(x0,y0, x1,y1,x2,y2,x3,y3)
if ((x1-x0)*(y3-y0)-(x3-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y1-y0)-(x1-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y2-y0)-(x2-x0)*(y3-y0) < 0) then
return 1
endif
endif
endif
if ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y3-y0)-(x3-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y1-y0)-(x1-x0)*(y3-y0) < 0) then
return 1
endif
endif
endif
return 0
end sub
sub point2quad(x0,y0, x1,y1,x2,y2,x3,y3,x4,y4)
if ((x1-x0)*(y4-y0)-(x4-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y1-y0)-(x1-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y2-y0)-(x2-x0)*(y3-y0) < 0) then
if ((x4-x0)*(y3-y0)-(x3-x0)*(y4-y0) < 0) then
return 1
endif
endif
endif
endif
if ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y3-y0)-(x3-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y4-y0)-(x4-x0)*(y3-y0) < 0) then
if ((x4-x0)*(y1-y0)-(x1-x0)*(y4-y0) < 0) then
return 1
endif
endif
endif
endif
return 0
end sub
sub line2point(x0,y0,x1,y1, x2,y2)
local dx,dy,cl
dx = x1 - x0
dy = y1 - y0
cl = ((x2-x0)*dx + (y2-y0)*dy) / (dx*dx + dy*dy)
xi = (x0 + cl*dx)
yi = (y0 + cl*dy)
dx = x2 - xi
dy = y2 - yi
if (abs(dx)^2 + abs(dy)^2 <= 1) return 1
return 0
end sub
sub line2circle(x0,y0,x1,y1, x2,y2,r2)
local dx,dy,cl
dx = x1 - x0
dy = y1 - y0
cl = ((x2-x0)*dx + (y2-y0)*dy) / (dx*dx + dy*dy)
xi = x0 + cl*dx
yi = y0 + cl*dy
if ((x2-xi)^2 + (y2-yi)^2 < r2^2) return 1
return 0
end sub
sub line2line(x0,y0,x1,y1, x2,y2,x3,y3)
local a1,a2,c1,c2
a1 = (y1-y0) / (x1-x0)
a2 = (y3-y2) / (x3-x2)
di = 1 / (a2 - a1)
c1 = y0 - a1*x0
c2 = y2 - a2*x2
xi = (c1 - c2) * di
yi = (a2*c1 - a1*c2) * di
end sub
sub line2segment(x0,y0,x1,y1, x2,y2,x3,y3)
local a1,a2,c1,c2
a1 = (y1-y0) / (x1-x0)
a2 = (y3-y2) / int(x3-x2)
di = 1 / (a2 - a1)
c1 = y0 - a1*x0
c2 = y2 - a2*x2
xi = (c1 - c2) * di
yi = (a2*c1 - a1*c2) * di
if (xi > x2) and (xi < x3) then
if (yi > y2) and (yi < y3) return 1
if (yi > y3) and (yi < y2) return 1
endif
if (xi > x3) and (xi < x2) then
if (yi > y2) and (yi < y3) return 1
if (yi > y3) and (yi < y2) return 1
endif
return 0
end sub
sub line2box(x0,y0,x1,y1, x2,y2,x3,y3)
if (line2segment(x0,y0,x1,y1, x2,y2,x3,y3) = 1) return 1
if (line2segment(x0,y0,x1,y1, x3,y2,x2,y3) = 1) return 1
return 0
end sub
sub line2tri(x0,y0,x1,y1, x2,y2,x3,y3,x4,y4)
if (line2segment(x0,y0,x1,y1, x2,y2,x3,y3) = 1) return 1
if (line2segment(x0,y0,x1,y1, x3,y3,x4,y4) = 1) return 1
if (line2segment(x0,y0,x1,y1, x4,y4,x2,y2) = 1) return 1
return 0
end sub
sub line2quad(x0,y0,x1,y1, x2,y2,x3,y3,x4,y4,x5,y5)
if (line2segment(x0,y0,x1,y1, x2,y2,x4,y4) = 1) return 1
if (line2segment(x0,y0,x1,y1, x3,y3,x5,y5) = 1) return 1
return 0
end sub
sub circle2point(x0,y0,r0, x1,y1)
if (abs(x0-x1)^2 + abs(y0-y1)^2 < r0^2) return 1
return 0
end sub
sub circle2circle(x0,y0,r0, x1,y1,r1)
if (abs(x0-x1)^2 + abs(y0-y1)^2 < (r0+r1)^2) return 1
return 0
end sub
sub circle2line(x0,y0,r0, x1,y1,x2,y2)
local dx,dy,cl
dx = x2 - x1
dy = y2 - y1
cl = ((x0-x1)*dx + (y0-y1)*dy) / (dx*dx + dy*dy)
xi = x1 + cl*dx
yi = y1 + cl*dy
if ((x0-xi)^2 + (y0-yi)^2 < r0^2) return 1
return 0
end sub
sub circle2segment(x0,y0,r0, x1,y1,x2,y2)
local dx,dy,cl
dx = x2-x1
dy = y2-y1
cl = ((x0-x1)*dx + (y0-y1)*dy) / (abs(dx)^2 + abs(dy)^2)
if (cl < 0.0) then
cl = 0.0
elsif (cl > 1.0) then
cl = 1.0
endif
xi = x1 + cl*dx
yi = y1 + cl*dy
if (abs(x0 - xi)^2 + abs(y0 - yi)^2 <= r0^2) return 1
return 0
end sub
sub circle2box(x0,y0,r0, x1,y1,x2,y2, z0,z1,z2)
local s2c
if (x0 < x1) then
s2c = abs(x0-x1)^2
elsif (x0 > x2) then
s2c = abs(x0-x2)^2
endif
if (y0 < y1) then
s2c = abs(y0-y1)^2 + s2c
elsif (y0 > y2) then
s2c = abs(y0-y2)^2 + s2c
endif
if (s2c <= r0^2) return 1
return 0
end sub
sub circle2tri(x0,y0,r0, x1,y1,x2,y2,x3,y3)
if (circle2segment(x0,y0,r0, x1,y1,x2,y2) = 1) return 1
if (circle2segment(x0,y0,r0, x2,y2,x3,y3) = 1) return 1
if (circle2segment(x0,y0,r0, x3,y3,x1,y1) = 1) return 1
if ((x1-x0)*(y3-y0)-(x3-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y1-y0)-(x1-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y2-y0)-(x2-x0)*(y3-y0) < 0) then
return 1
endif
endif
endif
if ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y3-y0)-(x3-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y1-y0)-(x1-x0)*(y3-y0) < 0) then
return 1
endif
endif
endif
return 0
end sub
sub circle2quad(x0,y0,r0, x1,y1,x2,y2,x3,y3,x4,y4)
if (circle2segment(x0,y0,r0, x1,y1,x2,y2) = 1) return 1
if (circle2segment(x0,y0,r0, x2,y2,x3,y3) = 1) return 1
if (circle2segment(x0,y0,r0, x3,y3,x4,y4) = 1) return 1
if (circle2segment(x0,y0,r0, x4,y4,x1,y1) = 1) return 1
if ((x1-x0)*(y4-y0)-(x4-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y1-y0)-(x1-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y2-y0)-(x2-x0)*(y3-y0) < 0) then
if ((x4-x0)*(y3-y0)-(x3-x0)*(y4-y0) < 0) then
return 1
endif
endif
endif
endif
if ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0) < 0) then
if ((x2-x0)*(y3-y0)-(x3-x0)*(y2-y0) < 0) then
if ((x3-x0)*(y4-y0)-(x4-x0)*(y3-y0) < 0) then
if ((x4-x0)*(y1-y0)-(x1-x0)*(y4-y0) < 0) then
return 1
endif
endif
endif
endif
end sub
sub segment2point(x0,y0,x1,y1, x2,y2)
local dx,dy,cl
dx = x1 - x0
dy = y1 - y0
cl = ((x2-x0)*dx + (y2-y0)*dy) / (dx*dx + dy*dy)
xi = (x0 + cl*dx)
yi = (y0 + cl*dy)
dx = x2 - xi
dy = y2 - yi
if (abs(dx)^2 + abs(dy)^2 <= 1) then
if (xi >= x0) and (xi <= x1) return 1
if (xi >= x1) and (xi <= x2) return 1
endif
return 0
end sub
sub segment2circle(x0,y0,x1,y1, x2,y2,r2)
local dx,dy,cl
dx = x1-x0
dy = y1-y0
cl = ((x2-x0)*dx + (y2-y0)*dy) / (abs(dx)^2 + abs(dy)^2)
if (cl < 0.0) then
cl = 0.0
elsif (cl > 1.0) then
cl = 1.0
endif
xi = x0 + cl*dx
yi = y0 + cl*dy
if (abs(x2 - xi)^2 + abs(y2 - yi)^2 <= r2^2) return 1
return 0
end sub
sub segment2line(x0,y0,x1,y1, x2,y2,x3,y3)
local denom, nume_a, nume_b
denom = ((y3 - y2)*(x1 - x0)) - ((x3 - x2)*(y1 - y0))
nume_a = ((x3 - x2)*(y0 - y2)) - ((y3 - y2)*(x0 - x2))
nume_b = ((x1 - x0)*(y0 - y2)) - ((y1 - y0)*(x0 - x2))
if (denom = 0.0) then
if (nume_a = 0.0) and (nume_b = 0.0) return 0
return 0
endif
local ua, ub
ua = nume_a / denom
ub = nume_b / denom
if (ua >= 0.0) and (ua <= 1.0) then
xi = x0 + ua*(x1 - x0)
yi = y0 + ua*(y1 - y0)
return 1
endif
return 0
end sub
sub segment2segment(x0,y0,x1,y1, x2,y2,x3,y3)
local denom, nume_a, nume_b
denom = ((y3 - y2)*(x1 - x0)) - ((x3 - x2)*(y1 - y0))
nume_a = ((x3 - x2)*(y0 - y2)) - ((y3 - y2)*(x0 - x2))
nume_b = ((x1 - x0)*(y0 - y2)) - ((y1 - y0)*(x0 - x2))
if (denom = 0.0) then
if (nume_a = 0.0) and (nume_b = 0.0) return 0
return 0
endif
local ua, ub
ua = nume_a / denom
ub = nume_b / denom
if (ua >= 0.0) and (ua <= 1.0) and (ub >= 0.0) and (ub <= 1.0) then
xi = x0 + ua*(x1 - x0)
yi = y0 + ua*(y1 - y0)
return 1
endif
return 0
end sub
sub segment2box(x0,y0,x1,y1, x2,y2,x3,y3)
if (segment2segment(x0,y0,x1,y1, x2,y2,x3,y2) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x3,y2,x3,y3) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x3,y3,x2,y3) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x2,y3,x2,y2) = 1) return 1
return 0
end sub
sub segment2tri(x0,y0,x1,y1, x2,y2,x3,y3,x4,y4)
if (segment2segment(x0,y0,x1,y1, x2,y2,x3,y3) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x3,y3,x4,y4) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x4,y4,x2,y2) = 1) return 1
return 0
end sub
sub segment2quad(x0,y0,x1,y1, x2,y2,x3,y3,x4,y4,x5,y5)
if (segment2segment(x0,y0,x1,y1, x2,y2,x3,y3) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x3,y3,x4,y4) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x4,y4,x5,y5) = 1) return 1
if (segment2segment(x0,y0,x1,y1, x5,y5,x2,y2) = 1) return 1
return 0
end sub
sub box2point(x0,y0,x1,y1, x2,y2)
if (x2 >= x0) and (x2 <= x1) then
if (y2 >= y0) and (y2 <= y1) return 1
if (y2 >= y1) and (y2 <= y0) return 1
elsif (x2 >= x1) and (x2 <= x0) then
if (y2 >= y0) and (y2 <= y1) return 1
if (y2 >= y1) and (y2 <= y0) return 1
endif
return 0
end sub
sub box2circle(x0,y0,x1,y1, x2,y2,r2)
local s2c
if (x2 < x0) then
s2c = abs(x2-x0)^2
elsif (x2 > x1) then
s2c = abs(x2-x1)^2
endif
if (y2 < y0) then
s2c = abs(y2-y0)^2 + s2c
elsif (y2 > y1) then
s2c = abs(y2-y1)^2 + s2c
endif
if (s2c <= r2^2) return 1
s2c = 0
if (x2 > x0) then
s2c = abs(x2-x0)^2
elsif (x2 < x1) then
s2c = abs(x2-x1)^2
endif
if (y2 > y0) then
s2c = abs(y2-y0)^2 + s2c
elsif (y2 < y1) then
s2c = abs(y2-y1)^2 + s2c
endif
if (s2c <= r2^2) return 1
return 0
end sub
sub box2line(x0,y0,x1,y1, x2,y2,x3,y3) end sub
sub box2segment(x0,y0,x1,y1, x2,y2,x3,y3) end sub
sub box2box(x0,y0,x1,y1, x2,y2,x3,y3)
if (x0 < x2) and (x0 < x3) and (x1 < x2) and (x1 < x3) return 0
if (x0 > x2) and (x0 > x3) and (x1 > x2) and (x1 > x3) return 0
if (y0 < y2) and (y0 < y3) and (y1 < y2) and (y1 < y3) return 0
if (y0 > y2) and (y0 > y3) and (y1 > y2) and (y1 > y3) return 0
if (x2 < x0) and (x2 < x1) and (x3 < x0) and (x3 < x1) return 0
if (x2 > x0) and (x2 > x1) and (x3 > x0) and (x3 > x1) return 0
if (y2 < y0) and (y2 < y1) and (y3 < y0) and (y3 < y1) return 0
if (y2 > y0) and (y2 > y1) and (y3 > y0) and (y3 > y1) return 0
return 1
end sub
// eof
Edit I think I got the sliding feature working now but its still having trouble with acute angles if the circle starts really close to the edge
open window 640, 512
window origin "cc"
px =-100
py = 100
x1 =-100
y1 =-100
x2 = 100
y2 = 100
x3 = 100
y3 =-100
r = 30.0
epsilon = 1.0
bounce = 0.001
while (0 = 0)
wait 0.01
c = peek("port1")
if (and(c, 16) <> 0) dy = dy - 1
if (and(c, 32) <> 0) dx = dx + 1
if (and(c, 64) <> 0) dy = dy + 1
if (and(c,128) <> 0) dx = dx - 1
c = peek("port2")
if (and(c, 16) <> 0) py = py - 1
if (and(c, 32) <> 0) px = px + 1
if (and(c, 64) <> 0) py = py + 1
if (and(c,128) <> 0) px = px - 1
nx = px + dx
ny = py + dy
setdispbuf draw
draw = 1 - draw
setdrawbuf draw
clear window
triangle x1,y1 to x2,y2 to x3,y3
circle px,py,r
x = nx
y = ny
curtime = 1.0
newtime = circ2seg(px,py,nx,ny,r, x1,y1,x2,y2)
if (newtime < curtime) then
curtime = newtime
xb = ix
yb = iy
endif
newtime = circ2seg(px,py,nx,ny,r, x2,y2,x3,y3)
if (newtime < curtime) then
curtime = newtime
xb = ix
yb = iy
endif
newtime = circ2seg(px,py,nx,ny,r, x3,y3,x1,y1)
if (newtime < curtime) then
curtime = newtime
xb = ix
yb = iy
endif
if (curtime < 1.0) then
xa = px + curtime*(nx-px)
ya = py + curtime*(ny-py)
fill box xa-2,ya-2 to xa+2,ya+2
fill box xb-2,yb-2 to xb+2,yb+2
// normalise x1,y1,x2,y2
A = r / sqrt((xb-xa)*(xb-xa) + (yb-ya)*(yb-ya))
B = A*(yb-ya)
C = A*(xb-xa)
ax = xa - B
ay = ya + C
bx = xa + B
by = ya - C
setrgb 1, 000, 255, 000
line ax,ay to bx,by
setrgb 1, 255, 255, 255
cl = ((nx-ax)*(bx-ax) + (ny-ay)*(by-ay)) / ((bx-ax)*(bx-ax) + (by-ay)*(by-ay))
vx = ax + cl*(bx-ax)
vy = ay + cl*(by-ay)
circle vx,vy,r
endif
nx = px + curtime*dx
ny = py + curtime*dy
line px,py to nx,ny
circle nx,ny,r
wend
sub circ2seg(px,py,nx,ny,r, x1,y1,x2,y2)
local denoma,denomb, nume_a,nume_b,nume_c,nume_d, A,B,C,D, t,nt
t = 1.0
r = r + epsilon
// normalise x1,y1,x2,y2
A = r / sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
B = A*(y2-y1)
C = A*(x2-x1)
ax = px + B
ay = py - C
bx = nx + B
by = ny - C
// project ray onto line x1,y1,x2,y2
denomb = 1 / ((y2-y1)*(bx-ax) - (x2-x1)*(by-ay))
nume_d = denomb*((x2-x1)*(ay-y1) - (y2-y1)*(ax-x1))
if (nume_d < 0.0) return t
nume_c = denomb*((bx-ax)*(ay-y1) - (by-ay)*(ax-x1))
if (nume_c < 0.0) then
// project ray onto circle x1,y1,r
A = (nx-px)*(nx-px) + (ny-py)*(ny-py)
B = (nx-px)*(px-x1) + (ny-py)*(py-y1)
C = (px-x1)*(px-x1) + (py-y1)*(py-y1) - r*r
D = (B+B)*(B+B) - (A+A)*(C+C)
if (D >= 0) then
ix = x1
iy = y1
return (-(B+B) - sqrt(D)) / (A+A)
endif
elsif (nume_c > 1.0) then
// project ray onto circle x2,y2,r
A = (nx-px)*(nx-px) + (ny-py)*(ny-py)
B = (nx-px)*(px-x2) + (ny-py)*(py-y2)
C = (px-x2)*(px-x2) + (py-y2)*(py-y2) - r*r
D = (B+B)*(B+B) - (A+A)*(C+C)
if (D >= 0) then
ix = x2
iy = y2
return (-(B+B) - sqrt(D)) / (A+A)
endif
else
ix = x1 + nume_c*(x2-x1)
iy = y1 + nume_c*(y2-y1)
return nume_d
endif
return t
end sub