Hello,
I am currently writing an algorythm for sliding non tile based collision for unrotated rectangles.
Here is my testing code:
CONSTANT maxBox = 5
TYPE coord
x AS float
y AS float
z AS float
ENDTYPE
TYPE cBox
xl AS int // smaller
xr AS int // greater
yd AS int // lower
yu AS int // higher
zf AS int // more near
zb AS int // more far
frict AS float
exist AS int
ENDTYPE
GLOBAL box[] AS cBox
drawSimulation()
FUNCTION drawSimulation:
LOCAL mx% , my% , b1% , b2%
LOCAL l1S AS coord , l1E AS coord , get AS coord
DIM box[10]
FOR i = 0 TO maxBox - 2 // fill Boxes ( 2D only for simulation )
box[i].xl = 50 * i
box[i].xr = 50 + 50 * i
box[i].yd = -50
box[i].yu = 50
box[i].zf = 50
box[i].zb = 125
box[i].exist = 1
sortCube( i )
NEXT
box[4].xl = 125
box[4].xr = 175
box[4].yd = -50
box[4].yu = 50
box[4].zf = 125
box[4].zb = 175
box[4].exist = 1
X_MAKE2D
WHILE TRUE
FOR i = 0 TO maxBox - 1
DrawCube(i)
NEXT
MOUSESTATE mx , my , b1 , b2
l1S.x = mx ; l1S.z = my
l1E.x = mx - 10 ; l1E.z = my - 10
l1E.y = 0 ; l1S.y = 0
DRAWLINE l1S.x , l1S.z , l1E.x , l1E.z , RGB( 122 , 122 , 122 )
get = checkinters( l1S , l1E )
SHOWSCREEN
WEND
ENDFUNCTION
FUNCTION checkinters AS coord: l1S AS coord , l1E AS coord
LOCAL cPnt AS coord , temp AS coord , tempE AS coord , cpNear AS coord , smDist# AS float , iSm AS int , l1EO AS coord , l1SO AS coord
l1SO = l1S
l1EO = l1E
FOR iG = 0 TO 1 // goes through two times, to make shure that all collisions apply correctly after the collision vector has been altered
FOR i = 0 TO maxBox - 1
iSm = -1 ; smDist = 50000.0
l1S = l1SO
IF box[i].exist = 1
FOR i2 = 0 TO 3
IF i2 = 0
temp.x = box[i].xl ; temp.z = box[i].zf ; tempE.x = box[i].xr ; tempE.z = box[i].zf // face along zfront ( 0 )
ENDIF
IF i2 = 1
temp.x = box[i].xl ; temp.z = box[i].zf ; tempE.x = box[i].xl ; tempE.z = box[i].zb // face along xl ( 1 )
ENDIF
IF i2 = 2
temp.x = box[i].xr ; temp.z = box[i].zb ; tempE.x = box[i].xl ; tempE.z = box[i].zb // face along zb ( 2 )
ENDIF
IF i2 = 3
temp.x = box[i].xr ; temp.z = box[i].zb ; tempE.x = box[i].xr ; tempE.z = box[i].zf // face along xr ( 3 )
ENDIF
cPnt = intersection( l1S , l1E , temp , tempE )
IF cPnt.x > -1
IF SQR( ( cPnt.x - l1SO.x ) * ( cPnt.x - l1SO.x ) + ( cPnt.z - l1SO.z ) * ( cPnt.z - l1SO.z ) ) < smDist
// also check if cut point is not between two near faces of different boxes
IF pointbetweenFaces( cPnt , i2 , i ) = 0
smDist = SQR( ( cPnt.x - l1SO.x ) * ( cPnt.x - l1SO.x ) + ( cPnt.z - l1SO.z ) * ( cPnt.z - l1SO.z ) ) ; cpNear = cPnt ; iSm = i2
ENDIF
ENDIF
ENDIF
NEXT
IF iSm = 0 OR iSm = 2 // here transformation of movement has to be calculated and applyed for line inters checking with the next rectangle ( by using the collision point with the smallest distance TO players old position )
l1E.z = cpNear.z // block z ( sides 0 and 2 )
ENDIF
IF iSm = 1 OR iSm = 3
l1E.x = cpNear.x // block x ( sides 1 and 3 )
ENDIF
ENDIF
NEXT
NEXT
DRAWLINE l1S.x , l1S.z , l1E.x , l1E.z , RGB(255 , 0 , 0 )
l1E.x = l1E.x - l1EO.x
l1E.z = l1E.z - l1EO.z
RETURN l1E
ENDFUNCTION
FUNCTION pointbetweenFaces: point AS coord , side AS int , boxCh // checks if the point is in a space which adjacts with another cubes face.
LOCAL fChS AS coord , fChE AS coord , fTChS AS coord , fTChE AS coord
IF side = 0
fTChS.z = box[boxCh].zf
ENDIF
IF side = 1
fTChS.x = box[boxCh].xl
ENDIF
IF side = 2
fTChS.z = box[boxCh].zb
ENDIF
IF side = 3
fTChS.x = box[boxCh].xr
ENDIF
FOR i = 0 TO maxBox - 1
IF i <> boxCh AND box[i].exist = 1
IF side = 0 // get opposite face of another object to the checked faces direction
fChS.x = box[i].xl ; fChS.y = box[i].yd ; fChS.z = box[i].zb
fChE.x = box[i].xr ; fChE.y = box[i].yu ; fChE.z = box[i].zb
IF ABS( fChS.z - fTChS.z ) <= 25
IF point.x > fChS.x AND point.x < fChE.x AND point.y >= fChS.y AND point.y <= fChE.y
RETURN 1
ENDIF
ENDIF
ENDIF
IF side = 1
fChS.x = box[i].xr ; fChS.y = box[i].yd ; fChS.z = box[i].zf
fChE.x = box[i].xr ; fChE.y = box[i].yu ; fChE.z = box[i].zb
IF ABS( fChS.x - fTChS.x ) <= 25
IF point.z > fChS.z AND point.z < fChE.z AND point.y >= fChS.y AND point.y <= fChE.y
RETURN 1
ENDIF
ENDIF
ENDIF
IF side = 2
fChS.x = box[i].xl ; fChS.y = box[i].yd ; fChS.z = box[i].zf
fChE.x = box[i].xr ; fChE.y = box[i].yu ; fChE.z = box[i].zf
IF ABS( fChS.z - fTChS.z ) <= 25
IF point.x > fChS.x AND point.x < fChE.x AND point.y >= fChS.y AND point.y <= fChE.y
RETURN 1
ENDIF
ENDIF
ENDIF
IF side = 3
fChS.x = box[i].xl ; fChS.y = box[i].yd ; fChS.z = box[i].zf
fChE.x = box[i].xl ; fChE.y = box[i].yu ; fChE.z = box[i].zb
IF ABS( fChS.x - fTChS.x ) <= 25
IF point.z > fChS.z AND point.z < fChE.z AND point.y >= fChS.y AND point.y <= fChE.y
RETURN 1
ENDIF
ENDIF
ENDIF
ENDIF
NEXT
RETURN 0
ENDFUNCTION
FUNCTION intersection AS coord: l1S AS coord , l1E AS coord , l2S AS coord , l2E AS coord // standart line line intersection point function
LOCAL x1 AS float , y1 AS float , x2 AS float , y2 AS float , x3 AS float , y3 AS float , x4 AS float , y4 AS float , d AS float , pre AS float
LOCAL post AS float , x AS float , y AS float
LOCAL fail AS coord , ret AS coord
fail.x = -1 ; fail.z = -1 ; fail.y = -1 // assumes that coordinates are always positive values!
x1 = l1S.x ; x2 = l1E.x ; x3 = l2S.x ; x4 = l2E.x
y1 = l1S.z ; y2 = l1E.z ; y3 = l2S.z ; y4 = l2E.z // I will use z for y in the later game, y collision is a whole other story.
d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
IF d = 0 THEN RETURN fail
pre = (x1*y2 - y1*x2) ; post = (x3*y4 - y3*x4)
x = ( pre * (x3 - x4) - (x1 - x2) * post ) / d
y = ( pre * (y3 - y4) - (y1 - y2) * post ) / d
IF ( x < MIN(x1, x2) OR x > MAX(x1, x2) OR x < MIN(x3, x4) OR x > MAX(x3, x4) ) THEN RETURN fail
IF ( y < MIN(y1, y2) OR y > MAX(y1, y2) OR y < MIN(y3, y4) OR y > MAX(y3, y4) ) THEN RETURN fail
ret.x = x ; ret.z = y
RETURN ret
ENDFUNCTION
FUNCTION sortCube: i AS int
IF box[i].xl > box[i].xr THEN SWAP box[i].xl , box[i].xr
IF box[i].zf > box[i].zb THEN SWAP box[i].zf , box[i].zb
IF box[i].yd > box[i].yu THEN SWAP box[i].yd , box[i].yu
ENDFUNCTION
FUNCTION DrawCube: i AS int
DRAWLINE box[i].xl , box[i].zf , box[i].xr , box[i].zf , RGB( 122 , 255 , 55 + i * 20 )
DRAWLINE box[i].xl , box[i].zf , box[i].xl , box[i].zb , RGB( 122 , 255 , 55 + i * 20 )
DRAWLINE box[i].xr , box[i].zb , box[i].xl , box[i].zb , RGB( 122 , 255 , 55 + i * 20 )
DRAWLINE box[i].xr , box[i].zb , box[i].xr , box[i].zf , RGB( 122 , 255 , 55 + i * 20 )
ENDFUNCTION
My Problem is, that this won´t work when the vector starts inside or at the very edge of the cube.
So the Player will run through walls sometimes.