Say I have two squares. One square is moved around with the cursor keys (the player), the other is stationary (a wall). Would it be possible to stop the player from entering the wall, if you don't know the wall's position or scale? Also: the player's movement may not move one pixel at a time.
Collision...
BlitzMax Forums/BlitzMax Beginners Area/Collision... Presumable you're drawing it, so you ought to know the position....
If you don't know the walls position or scal, then you might want to readpixel the corners of the players square.
And do the check before you actually move the player, so that you don't get the collision after the player is "inside" the wall.
And do the check before you actually move the player, so that you don't get the collision after the player is "inside" the wall.
lets see if this helps... and please note this is not supposed to be runable code :D
playerx:int
playery:int
objectx:int
objecty:int
size1:int
size2:int
while
cls
gosub move
gosub checkcollision
gosub draw
flip
wend
function move:
if keydown(key_left) then playerx=playerx-1
etc...
etc...
etc...
endfunction
function checkcollision:
if playerx+size1 > objectx then playerx+size1 = objectx
if playerx < objectx+size2 then playerx = objectx+size2
if playery+size1 > objecty then playery+size1 = objecty
if playery < objecty+size2 then playery = objecty+size2
endfunction
function draw:
setcolor 255,0,0
drawrect playerx,playery,size1,size1
setcolor 0,0,255
drawrect objectx,objecty,size2,size2
endfunction
turn that code into usable code and run it. You should be able to run into the object and be repelled.
playerx:int
playery:int
objectx:int
objecty:int
size1:int
size2:int
while
cls
gosub move
gosub checkcollision
gosub draw
flip
wend
function move:
if keydown(key_left) then playerx=playerx-1
etc...
etc...
etc...
endfunction
function checkcollision:
if playerx+size1 > objectx then playerx+size1 = objectx
if playerx < objectx+size2 then playerx = objectx+size2
if playery+size1 > objecty then playery+size1 = objecty
if playery < objecty+size2 then playery = objecty+size2
endfunction
function draw:
setcolor 255,0,0
drawrect playerx,playery,size1,size1
setcolor 0,0,255
drawrect objectx,objecty,size2,size2
endfunction
turn that code into usable code and run it. You should be able to run into the object and be repelled.
I apologize I ran my code after fixing it to see if it works and it doesn't seem to work after all... here's an updated code that actually runs though it has a problem.
Global playerx:Int = 50
Global playery:Int = 50
Global objectx:Int = 100
Global objecty:Int = 100
Global size1:Int
Global size2:Int
Global extra:Int
Graphics 640,480
While Not KeyHit(key_Q)
Cls
move()
checkcollision()
draw()
Flip
Wend
Function move()
If KeyDown(key_left) Then playerx=playerx-1
If KeyDown(key_right) Then playerx=playerx+1
If KeyDown(key_up) Then playery=playery-1
If KeyDown(key_down) Then playery=playery+1
EndFunction
Function checkcollision()
extra=playerx+20
If playerx+20 > objectx And playery+20 > objecty And playery < objecty+20 Then extra = objectx
extra=objectx+20
If playerx < objectx+20 And playery+20 > objecty And playery < objecty+20 Then playerx = extra
extra=playery+20
If playery+20 > objecty And playerx+20 > objectx And playerx < objectx+20 Then extra = objecty
extra=objecty+20
If playery < objecty+20 And playerx+20 > objectx And playerx < objectx+20 Then playery = extra
EndFunction
Function draw()
SetColor 255,0,0
DrawRect playerx,playery,20,20
SetColor 0,0,255
DrawRect objectx,objecty,20,20
EndFunction
Global playerx:Int = 50
Global playery:Int = 50
Global objectx:Int = 100
Global objecty:Int = 100
Global size1:Int
Global size2:Int
Global extra:Int
Graphics 640,480
While Not KeyHit(key_Q)
Cls
move()
checkcollision()
draw()
Flip
Wend
Function move()
If KeyDown(key_left) Then playerx=playerx-1
If KeyDown(key_right) Then playerx=playerx+1
If KeyDown(key_up) Then playery=playery-1
If KeyDown(key_down) Then playery=playery+1
EndFunction
Function checkcollision()
extra=playerx+20
If playerx+20 > objectx And playery+20 > objecty And playery < objecty+20 Then extra = objectx
extra=objectx+20
If playerx < objectx+20 And playery+20 > objecty And playery < objecty+20 Then playerx = extra
extra=playery+20
If playery+20 > objecty And playerx+20 > objectx And playerx < objectx+20 Then extra = objecty
extra=objecty+20
If playery < objecty+20 And playerx+20 > objectx And playerx < objectx+20 Then playery = extra
EndFunction
Function draw()
SetColor 255,0,0
DrawRect playerx,playery,20,20
SetColor 0,0,255
DrawRect objectx,objecty,20,20
EndFunction
Oops forgot about this thread. Thanks all.
I must not be thinking straight, but how would I stop the rects from overlapping in a scenario similar to the code above (knowing the position and scale of everything), only not bugged? Here's some code:
I must not be thinking straight, but how would I stop the rects from overlapping in a scenario similar to the code above (knowing the position and scale of everything), only not bugged? Here's some code:
SuperStrict Graphics(400,300,0) Local x1%=10,y1%=10,x2%=200,y2%=200 Local w1%=15,h1%=10,w2%=20,h2%=30 While Not KeyHit(KEY_ESCAPE) SetColor(255,255,255) DrawRect(x1,y1,w1,h1) SetColor(255,255,0) DrawRect(x2,y2,w2,h2) If KeyDown(KEY_UP) Then y1=y1-2 If KeyDown(KEY_DOWN) Then y1=y1+2 If KeyDown(KEY_LEFT) Then x1=x1-2 If KeyDown(KEY_RIGHT) Then x1=x1+2 If RectsOverlap(x1,y1,w1,h1,x2,y2,w2,h2) Then x1=x2-w1 EndIf Flip;Cls;ResetCollisions Wend End Function RectsOverlap%(x1%,y1%,w1%,h1%,x2%,y2%,w2%,h2%) If x1+w1>x2 And y1+h1>y2 And x1<x2+w2 And y1<y2+h2 Then Return True Else Return False EndIf End Function
SuperStrict Graphics(400,300,0) Local x1%=10,y1%=10,x2%=200,y2%=200 Local w1%=15,h1%=10,w2%=20,h2%=30 Local TmpX:Int,TmpY:Int While Not KeyHit(KEY_ESCAPE) SetColor(255,255,255) DrawRect(x1,y1,w1,h1) SetColor(255,255,0) DrawRect(x2,y2,w2,h2) TmpX = x1 TmpY = y1 If KeyDown(KEY_UP) Then TmpY=TmpY-2 If KeyDown(KEY_DOWN) Then TmpY=TmpY+2 If KeyDown(KEY_LEFT) Then TmpX=TmpX-2 If KeyDown(KEY_RIGHT) Then TmpX=TmpX+2 If Not RectsOverlap(TmpX,TmpY,w1,h1,x2,y2,w2,h2) Then x1=tmpX y1=tmpY EndIf Flip;Cls;ResetCollisions Wend End Function RectsOverlap%(x1%,y1%,w1%,h1%,x2%,y2%,w2%,h2%) If x1+w1>x2 And y1+h1>y2 And x1<x2+w2 And y1<y2+h2 Then Return True Else Return False EndIf End Function
Try that out. It checks if it collides BEFORE changing the position, rather than after. If it doesn't collide, then the move is made.
Thanks, that works, but change the moving speed to something like 7 or 13 and you get large gaps in the collision. Is there a way to remove these gaps? Move the temp rect back a pixel until it no longer collides then place the real rect there?
SuperStrict Graphics(400,300,0) Local x1%=10,y1%=10,x2%=200,y2%=200 Local w1%=15,h1%=10,w2%=20,h2%=30 Local dirup%,dirdn%,dirleft%,dirright% Local CollideCheck:CollideResultType = New CollideResultType Const MoveSpeed:Int = 10 Type CollideResultType Field X:Int,Y:Int,Collide:Byte End Type While Not KeyHit(KEY_ESCAPE) SetColor(255,255,255) DrawRect(x1,y1,w1,h1) dirup=0 dirdn=0 dirleft=0 dirright=0 SetColor(255,255,0) DrawRect(x2,y2,w2,h2) If KeyDown(KEY_UP) Then dirup=1 End If If KeyDown(KEY_DOWN) Then dirdn=1 End If If KeyDown(KEY_LEFT) Then dirleft=1 End If If KeyDown(KEY_RIGHT) Then dirright=1 End If CollideCheck = RectsOverlap(x1,y1,w1,h1,x2,y2,w2,h2,movespeed,dirup,dirdn,dirleft,dirright) x1 = CollideCheck.x y1 = CollideCheck.y Flip;Cls;ResetCollisions Wend End Function RectsOverlap:CollideResultType (x1%,y1%,w1%,h1%,x2%,y2%,w2%,h2%,move_speed%,up:Byte,down:Byte,leftt:Byte,rightt:Byte) Local Collided:CollideResultType = New CollideResultType collided.x=x1 Collided.y=y1 If Rightt If x1+w1<=x2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1+w1+move_speed >= x2 Collided.X = x2-w1 Collided.Collide = True End If End If End If If leftt If x1>=x2+w2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1-move_speed <= x2+w2 Collided.X = x2+w2 Collided.Collide = True End If End If End If If down If y1+h1<=y2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1+h1+move_speed >= y2 Collided.y = y2-h1 Collided.Collide = True End If End If End If If up If y1>=y2+y2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1-move_speed <= y2+h2 Collided.y = y2+h2 Collided.Collide = True End If End If End If If Not Collided.Collide If rightt Then Collided.X = X1 + move_speed If leftt Then Collided.X = X1-move_speed If up Then collided.Y = y1-move_speed If down Then collided.Y = y1+move_speed Collided.Collide = False End If Return Collided End Function
Probobly not the best method but it does accurate collision detection. It does partial collision checks depending on the direction of the box.
I see, thanks.
Any idea why the collision fails when moving up?
It works perfectly in the other three directions.
It works perfectly in the other three directions.
SuperStrict Graphics(400,300,0) Local x1%=10,y1%=10,x2%=200,y2%=200 Local w1%=15,h1%=10,w2%=20,h2%=30 Local dirup%,dirdn%,dirleft%,dirright% Local CollideCheck:CollideResultType = New CollideResultType Const MoveSpeed:Int = 10 Type CollideResultType Field X:Int,Y:Int,Collide:Byte End Type While Not KeyHit(KEY_ESCAPE) SetColor(255,255,255) DrawRect(x1,y1,w1,h1) dirup=0 dirdn=0 dirleft=0 dirright=0 SetColor(255,255,0) DrawRect(x2,y2,w2,h2) If KeyDown(KEY_UP) Then dirup=1 End If If KeyDown(KEY_DOWN) Then dirdn=1 End If If KeyDown(KEY_LEFT) Then dirleft=1 End If If KeyDown(KEY_RIGHT) Then dirright=1 End If CollideCheck = RectsOverlap(x1,y1,w1,h1,x2,y2,w2,h2,movespeed,dirup,dirdn,dirleft,dirright) x1 = CollideCheck.x y1 = CollideCheck.y Flip;Cls;ResetCollisions Wend End Function RectsOverlap:CollideResultType (x1%,y1%,w1%,h1%,x2%,y2%,w2%,h2%,move_speed%,up:Byte,down:Byte,leftt:Byte,rightt:Byte) Local Collided:CollideResultType = New CollideResultType collided.x=x1 Collided.y=y1 If Rightt If x1+w1<=x2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1+w1+move_speed >= x2 Collided.X = x2-w1 Collided.Collide = True End If End If End If If leftt If x1>=x2+w2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1-move_speed <= x2+w2 Collided.X = x2+w2 Collided.Collide = True End If End If End If If down If y1+h1<=y2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1+h1+move_speed >= y2 Collided.y = y2-h1 Collided.Collide = True End If End If End If If up If y1>=y2+h2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1-move_speed <= y2+h2 Collided.Y = y2+h2 Collided.Collide = True End If End If End If If Not Collided.Collide If rightt Then Collided.X = X1 + move_speed If leftt Then Collided.X = X1-move_speed If up Then collided.Y = y1-move_speed If down Then collided.Y = y1+move_speed Collided.Collide = False End If Return Collided End Function
Fixed, sorry.
Now I'm just wondering how I could do that except with mouse control. :/
SuperStrict Graphics(600,480,0) Local x1%=10,y1%=10,x2%=200,y2%=200 Local w1%=15,h1%=10,w2%=50,h2%=70 Local dirup%,dirdn%,dirleft%,dirright% Local CollideCheck:CollideResultType = New CollideResultType Local OldX:Int,OldY:Int,XDif:Int,YDif:Int Const MoveSpeed:Int = 10 Type CollideResultType Field X:Int,Y:Int,Collide:Byte End Type While Not KeyHit(KEY_ESCAPE) SetColor(255,255,255) DrawRect(x1,y1,w1,h1) dirup=0 dirdn=0 dirleft=0 dirright=0 xdif=0 ydif=0 SetColor(255,255,0) DrawRect(x2,y2,w2,h2) xdif = MouseX()-oldX If MouseX() > oldx Then dirright=1 ElseIf MouseX() < oldx dirleft=1 End If ydif = MouseY()-oldy If MouseY() > oldy Then dirdn=1 ElseIf MouseY() < oldy dirup=1 End If CollideCheck = RectsOverlap(x1,y1,w1,h1,x2,y2,w2,h2,dirup,dirdn,dirleft,dirright,xdif,ydif) x1 = CollideCheck.x y1 = CollideCheck.y OldX = x1 OldY = y1 Flip;Cls;ResetCollisions Wend End Function RectsOverlap:CollideResultType (x1%,y1%,w1%,h1%,x2%,y2%,w2%,h2%,up:Byte,down:Byte,leftt:Byte,rightt:Byte,xSpeed:Int,YSpeed:Int) Local Collided:CollideResultType = New CollideResultType collided.x=x1 Collided.y=y1 If Rightt If x1+w1<=x2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1+w1+xspeed >= x2 Collided.X = x2-w1 Collided.Collide = True End If End If End If If leftt If x1>=x2+w2 And y1+h1>=y2 And Y1 <=y2+h2 Then If x1+xspeed <= x2+w2 Collided.X = x2+w2 Collided.Collide = True End If End If End If If down If y1+h1<=y2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1+h1+yspeed >= y2 Collided.y = y2-h1 Collided.Collide = True End If End If End If If up If y1>=y2+h2 And x1+w1>=x2 And x1 <=x2+w2 Then If y1+yspeed <= y2+h2 Collided.Y = y2+h2 Collided.Collide = True End If End If End If If Not Collided.Collide If rightt Or leftt Then Collided.X = X1 + xspeed If up Or down Then collided.Y = y1+yspeed Collided.Collide = False End If Return Collided End Function
Something like that?
Ah, yes. Precisely. Thanks.