Page 1 of 1

Programming collisions with ZoomSprite3D()

Posted: Tue Sep 27, 2005 2:48 pm
by DriakTravo
What would be the best way to determine a collision between a regular sprite and a 3d one that has been zoomed or rotated.?

Posted: Wed Sep 28, 2005 1:40 am
by kenmo
If you want pixel-perfect collision, that would be difficult. If you just want rotated box collision, I could post some code for you.

Posted: Wed Sep 28, 2005 1:51 am
by kenmo
Eh here it is anyway.

Code: Select all

; PureBasic Rotated Box Collision Checker by kenmo
; Based on http://www.ragestorm.net/tutorial?id=22

Structure Vector2D
   x.f
   y.f
EndStructure

Structure RotRect
   C.Vector2D
   S.Vector2D
   Ang.f
   Color.l
EndStructure

Procedure AddVectors2D(*v1.Vector2D,*v2.Vector2D)
   *v1\x+*v2\x : *v1\y+*v2\y
EndProcedure

Procedure SubVectors2D(*v1.Vector2D,*v2.Vector2D)
   *v1\x-*v2\x : *v1\y-*v2\y
EndProcedure

Procedure RotateVector2DClockwise(*v.Vector2D,ang.f)
   t.f : cosa.f=Cos(ang) : sina.f=Sin(ang)
   t=*v\x : *v\x=t*cosa+*v\y*sina : *v\y=-t*sina+*v\y*cosa
EndProcedure

Procedure CopyVector2D(*v1.Vector2D,*v2.Vector2D)
   *v1\x=*v2\x : *v1\y=*v2\y
EndProcedure

Procedure.l RotRectsCollision(*rr1.RotRect,*rr2.RotRect)

   A.Vector2D : B.Vector2D
   C.Vector2D
   BL.Vector2D : TR.Vector2D

   ang.f=*rr1\ang-*rr2\ang

   cosa.f=Cos(ang)

   sina.f=Sin(ang)

   t.f : x.f : af.f
   dx.f
   ext1.f : ext2.f

   CopyVector2D(C,*rr2\C)
   SubVectors2D(C,*rr1\C)

   RotateVector2DClockwise(C,*rr2\ang)

   CopyVector2D(BL,C) : CopyVector2D(TR,C)
   SubVectors2D(BL,*rr2\S)
   AddVectors2D(TR,*rr2\S)

   A\x=-(*rr1\S\y)*sina : B\x=A\x : t=(*rr1\S\x)*cosa : A\x+t : B\x-t
   A\y=(*rr1\S\y)*cosa : B\y=A\y : t=(*rr1\S\x)*sina : A\y+t : B\y-t

   t=sina*cosa

   If t<0.0

      t=A\x : A\x=B\x : B\x=t
      t=A\y : A\y=B\y : B\y=t

   EndIf

   If sina<0.0 : B\x=-B\x : B\y=-B\y : EndIf

   If B\x>TR\x Or B\x>-BL\x : ProcedureReturn 0 : EndIf

   If t=0.0
      ext1=A\y : ext2=-ext1
   Else
      x=BL\x-A\x : af=TR\x-A\x
      ext1=A\y
      If af*x>0.0
         dx=A\x
         If x<0.0
            dx-B\x : ext1-B\y : x=af
         Else
            dx+B\x : ext1+B\y
         EndIf
         ext1*x : ext1/dx : ext1+A\y
      EndIf
      x=BL\x+A\x : af=TR\x+A\x
      ext2=-A\y
      If af*x>0.0
         dx=-A\x
         If x<0.0
            dx-B\x : ext2-B\y : x=af
         Else
            dx+B\x : ext2+B\y
         EndIf
         ext2*x : ext2/dx : ext2-A\y
      EndIf
   EndIf

   tmp.l=(ext1<BL\y And ext2<BL\y) : res.l=0
   If ((ext1<BL\y And ext2<BL\y) Or (ext1>TR\y And ext2>TR\y))=0
      res.l=1
   EndIf
   ProcedureReturn res
EndProcedure

Procedure RotatePoint(*Point.Vector2D,Ang.f)
   nx.f : ny.f
   sina.f=Sin(ang) : cosa.f=Cos(ang)
   nx=*Point\x*cosa-*Point\y*sina : ny=*Point\y*cosa+*Point\x*sina
   *Point\x=nx : *Point\y=ny
EndProcedure

If InitSprite()=0 Or InitKeyboard()=0 Or InitMouse()=0 : MessageRequester("Error","Couldn't initialized!",#MB_ICONHAND) : End : EndIf

MessageRequester("Info","Rotated Rectangle Collision demo by kenmo"+Chr(10)+FormatDate("Compiled %mm/%dd/%yyyy, %hh:%ii",Date()),#MB_ICONINFORMATION)
If OpenScreen(640,480,16,"")=0
   MessageRequester("Error","Couldn't initialize screen!",#MB_ICONHAND) : End : 
EndIf
SetFrameRate(60)

Rects.l=2
Dim RR.RotRect(Rects-1)
RR(0)\S\x=25 : RR(0)\S\y=25
RR(0)\C\x=320 : RR(0)\C\y=100
RR(0)\Color=RGB(192,0,0)
RR(1)\S\x=Random(50)+10 : RR(1)\S\y=Random(50)+10 : RR(1)\Ang=Random(359)*3.14159265/180.0
RR(1)\C\x=320 : RR(1)\C\y=240
RR(1)\Color=RGB(0,0,192)
Autorotate.b=1
Dialogs.b=6 : Dim Dialog.s(Dialogs-1) : DialogFlag.b : DialogTime.l : DialogN.l
Dialog(0)="Move the red rectangle with the mouse."
Dialog(1)="Left-click and drag to resize it."
Dialog(2)="Right-click and drag left/right to rotate it."
Dialog(3)="Press Space to randomize center rectangle."
Dialog(4)="Press Enter to toggle Auto-rotate."
Dialog(5)="Press Escape to exit."

Dim Vec.Vector2D(3)

Repeat
   ClearScreen(21,21,21) : ExamineKeyboard() : ExamineMouse()
   Gosub control
   Gosub render
   FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
End

control:
If KeyboardPushed(#PB_Key_Space)
   RR(1)\S\x=Random(50)+10 : RR(1)\S\y=Random(50)+10 : RR(1)\Ang=Random(359)*3.14159265/180.0
EndIf
If KeyboardReleased(#PB_Key_Return)
   Autorotate=1-Autorotate
EndIf
If Autorotate
   RR(1)\Ang+3.14159265/360.0
EndIf
If MouseButton(1)
   RR(0)\S\x+MouseDeltaX() : If RR(0)\S\x<=0.0 : RR(0)\S\x=1.0 : EndIf
   RR(0)\S\y+MouseDeltaY() : If RR(0)\S\y<=0.0 : RR(0)\S\y=1.0 : EndIf
ElseIf MouseButton(2)
   RR(0)\Ang+MouseDeltaX()/90.0
Else
   RR(0)\C\x+MouseDeltaX() : RR(0)\C\y+MouseDeltaY()
EndIf
Return

render:
If StartDrawing(ScreenOutput())
   DrawingMode(5) : Locate(0,0)
   If RotRectsCollision(RR(0),RR(1))
      FrontColor(36,229,36) : DrawText(">:O 'Hey man, you're colliding!'")
   Else
      FrontColor(247,247,247) : DrawText(">:( 'No collisions here.'")
   EndIf
   If Date()-dialogtime>(1+DialogFlag*2) : DialogFlag=1-DialogFlag : DialogTime=Date() : If DialogFlag=0 : DialogN+1 : If DialogN=Dialogs : DialogN=0 : EndIf : EndIf : EndIf
   FrontColor(247,247,247) : Locate(0,460)
   If DialogFlag
      DrawText(">:O '"+Dialog(DialogN)+"'")
   Else
      DrawText(">:(")
   EndIf
   For tmp=0 To Rects-1
      TmpX=RR(tmp)\C\x : TmpY=RR(tmp)\C\y : TmpW=RR(tmp)\S\x : TmpH=RR(tmp)\S\y : TmpA.f=RR(tmp)\Ang
      Vec(0)\x=-TmpW : Vec(0)\y=TmpH : RotatePoint(Vec(0),TmpA) : Vec(0)\x+TmpX : Vec(0)\y+TmpY
      Vec(1)\x=TmpW : Vec(1)\y=TmpH : RotatePoint(Vec(1),TmpA) : Vec(1)\x+TmpX : Vec(1)\y+TmpY
      Vec(2)\x=TmpW : Vec(2)\y=-TmpH : RotatePoint(Vec(2),TmpA) : Vec(2)\x+TmpX : Vec(2)\y+TmpY
      Vec(3)\x=-TmpW : Vec(3)\y=-TmpH : RotatePoint(Vec(3),TmpA) : Vec(3)\x+TmpX : Vec(3)\y+TmpY
      LineXY(Vec(0)\x,Vec(0)\y,Vec(1)\x,Vec(1)\y,RR(tmp)\Color)
      LineXY(Vec(1)\x,Vec(1)\y,Vec(2)\x,Vec(2)\y)
      LineXY(Vec(2)\x,Vec(2)\y,Vec(3)\x,Vec(3)\y)
      LineXY(Vec(3)\x,Vec(3)\y,Vec(0)\x,Vec(0)\y)
   Next tmp
   StopDrawing()
EndIf
Return

Posted: Wed Sep 28, 2005 9:48 am
by Psychophanta
Nice Kenmo.
However, perhaps it is an unnecessary work; isn't this implemented in DX9 stuff?
I need collision detection for 3D and 2D sprites for my projects, but should be made by hardware (DX9 compatible VGAs) because of a speed matter.
Lets hope PB 4.00 and after includes advanced collision detection... I'm impatient for that and many other DX9 stuff. Else, maybe my only hope is Sprite3DReal lib by S. Moebius, or other lib which support DX9 or after.

Posted: Wed Sep 28, 2005 2:47 pm
by DriakTravo
Thanks for that awsome demo! It helped a little bit but my program would be alot better if I could figure out how to do pixel by pixel collisions. The only way that works so far is if I draw just the rotated/zoomed sprite on the screen by itself and use GrabSprite() to make a regular sprite out of it but doing that each frame eats up the framerate like crazy.

Posted: Thu Sep 29, 2005 12:03 am
by MadMax
@ TriacDavo, That's the system I use, but I don't notice any significan't drop in speed.

Posted: Thu Sep 29, 2005 1:04 am
by DriakTravo
hrm... would you mind giving a code snip of display and grabbing of the sprite?