News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

Pixel Perfect (rotated/scaled) Collision

Started by kevin, May 29, 2006, 01:38:10 PM

Previous topic - Next topic

kevin

  While PlayBASIC has included vector based engine since 2003/2004, but we've finally implemented a traditional pixel level collisions.   In case your unsure, Pixel Perfect Collision  lets you detect collision between sprites on a per pixel basis. So if any pixel overlaps a collision is registered. It doesn't matter if the sprites are scaled, rotated, inverted whatever. The collision engine in PlayBasic can handle it for you.

 To expand upon this, I'm also looking adding controls to detect collisions between vector shapes (rects/circles/lines/polygons) and sprites on a per pixel basis. So pixel perfect collisions can be combined with vector collisions.

  (login required)
 
 Atm, the collision has handled through a temp test command which compares two sprites.  Pretty simple.  That will no doubt vanish and to be handled via the sprite collision engine..  

 

PlayBASIC Code: [Select]
   w=100
h=100
LoadImage "ship.bmp",1
ScaleImage 1,w,h,1
PrepareFXImage 1


Spr =NewSprite(450,150,1)
Spr2 =NewSprite(400,200,1)

SpriteDrawMode spr,2
RotateSprite spr,45
CenterSpriteHandle spr

SpriteDrawMode spr2,2
ScaleSpriteXY spr2,2,3
CenterSpriteHandle spr2
RotateSprite spr2,10

Do

Cls RGB(100,100,100)
SpriteDrawMode spr2,2

PositionSprite spr,MouseX(),MouseY()

TurnSprite spr,(-1*LeftKey())+(1*RightKey())
TurnSprite spr2,0.25

result=CompareSpritePixels(spr,spr2)
If result
SpriteDrawMode spr2,2+4096
CenterText 400,50,"Sprites Hit"
EndIf

DrawAllSprites


Sync
Loop
End




Ian Price

Excellent news and something that I've been waiting for. :)

I don't mind a reduction in speed - the benefits of pixel-perfect collisions far outweigh a speed-loss (unless it's really significant).
I came. I saw. I played some Nintendo.

kevin


Ian Price

Well for a start it saves having to fart around using vectors/shapes! :P

Your new animation tool may well help on that score, but I've never personally liked that idea - maybe it's because throughout my coding history, I've had access to pixel perfect collision and have been spoiled by it's ease of use and it's accuracy whn it's needed.

You perhaps prefer your method, and that's fair enough, but I prefer mine. I've never particularly liked bounding box collision either for games that need a bit more accuracy.

My JetPak remake could have done with pixel perfect collision, given that even true vector/shape collision info wasn't really available at the time of the comp.
I came. I saw. I played some Nintendo.

kevin

#4
Vector to Pixel Collision

  I've made few changes to the how this is implemented.  The most notable is that you can set an accuracy value. Which scales the span comparisons.  So you can reproduce the overhead when segment overlap but setting the accuracy value bellow 1,  For more accuracy set it higher that 1.      The more accuracy the slower and more cache memory is used.   Just so your aware setting it two 2 say, creates 4 times the pixel comparisons.    

 Anyway, i've also implemented the base segment to image comparisons routines.  So you can now check a vector shape for impacts against the pixels of a rotated, scaled sprite.  See BoxHitSpritePixels bellow.



PlayBASIC Code: [Select]
   LoadImage "ship.bmp",1
PrepareFXImage 1

Spr =NewSprite(450,150,1)
SpriteDrawMode spr,2+4096
SpriteAlphaAddColour spr,RGB(255,0,255)
RotateSprite spr,45
CenterSpriteHandle spr
SpriteCollisionMode Spr,1


max=10
Dim Sprites(MAx)

For lp=1 To max
Spr2 =NewSprite(Rnd(800),Rnd(600),1)
SpriteDrawMode spr2,2
SpriteCollisionMode Spr2,1
; SpriteCollisionDebug Spr2,True
CenterSpriteHandle spr2
ScaleSprite Spr2,RndRange(3,3)
RotateSprite spr2,10
Sprites(lp)=spr2
Next

PositionSprite sprites(1),400,300

Do

Cls RGB(100,100,100)

PositionSprite spr,MouseX(),MouseY()
TurnSprite spr,(-1*LeftKey())+(1*RightKey())

For lp=1 To max
Spr2=Sprites(lp)
SpriteDrawMode spr2,2
SpriteAlphaAddColour spr2,$00ff00
TurnSprite spr2,0.55
If CompareSpritePixels(spr,spr2,0.50)
SpriteDrawMode spr2,2+4096
EndIf
Next

rX1=MouseX()
rY1=MouseY()
rX2=rX1+200
rY2=rY1+200

LockBuffer
For lp=1 To max
Spr2=Sprites(lp)
If BoxHitSpritePixels(rx1,ry1,rx2,ry2,spr2,1)
SpriteDrawMode spr2,2+4096
SpriteAlphaAddColour spr2,$0000ff
EndIf
Next
UnLockBuffer

BoxC rx1,ry1,rx2,ry2,False,$255

DrawAllSprites

Sync
Loop
End






kevin

#5
Ellipse to Sprite Pixels Collision  

    This piccy shows that you can check if a ellipse intersects a sprites pixels.  Rect are already implemented but i still have Dot / Quad & shape to do and probably a line/ray to sprite intersection also.  But we'll see.

thaaks

We are nearly there, Houston...  :P

Looks and sounds great! Pixel perfect and shape collision as a mixture is certainly an outstanding feature.

What about the new VM? Any plans when you'll start on that beast?

Cheers,
Tommy

kevin

QuoteAny plans when you'll start on that beast

     With any luck, before the end of time.  While there's always more than a few tidbits on the 'wouldn't it be cool list',  this is pretty much it for PB VM in it's current state.  I'm not even sure i'll spend any time implementing these test commands into the existing collision frame work.  Which means, it might take 2 lines of code resolve a sprite collision. Heaven forbid..

kevin

#8
   Triangle to Sprite Pixels Collision

 Added Triangle to sprite method, which will cover quads also.



PlayBASIC Code: [Select]
   LoadImage "ship.bmp",1
PrepareFXImage 1

Spr =NewSprite(450,150,1)
SpriteDrawMode spr,2+4096
SpriteAlphaAddColour spr,RGB(255,0,255)
RotateSprite spr,45
CenterSpriteHandle spr
SpriteCollisionMode Spr,1

w=getimagewidth(1)
h=getimageheight(1)

max=100
Dim Sprites(MAx)

For lp=1 To max
Spr2 =NewSprite(Rnd(800),Rnd(600),1)
SpriteDrawMode spr2,2
SpriteImageUV spr2,0,6,6
SpriteImageUV spr2,1,w-6,6
SpriteImageUV spr2,2,w-6,h-6
SpriteImageUV spr2,3,6,h-6

SpriteCollisionMode Spr2,1
; SpriteCollisionDebug Spr2,True

CenterSpriteHandle spr2
RotateSprite spr2,10
Sprites(lp)=spr2
Next

PositionSprite sprites(1),400,300

Do
Cls RGB(100,100,100)

PositionSprite spr,MouseX(),MouseY()
TurnSprite spr,(-1*LeftKey())+(1*RightKey())

For lp=1 To max
Spr2=Sprites(lp)
SpriteDrawMode spr2,2
SpriteAlphaAddColour spr2,$00ff00
TurnSprite spr2,0.55
If CompareSpritePixels(spr,spr2,0.50)
SpriteDrawMode spr2,2+4096
EndIf
Next

mX=MouseX()
mY=MouseY()



x1=mx
y1=my

x2=x1+250
y2=y1+30
x3=x1+90
y3=y1+240



TriC x1,y1,x2,y2,x3,y3,$1abb55

LockBuffer
For lp=1 To max
Spr2=Sprites(lp)
If TriangleHitSpritePixels(x1,y1,x2,y2,x3,y3,spr2,0.5)
SpriteDrawMode spr2,2+4096
SpriteAlphaAddColour spr2,$ffff00
EndIf
Next
UnLockBuffer





DrawAllSprites

Sync
Loop
End







kevin

#9
Quads to Sprite Pixel Collisions

Added compare Quad (poylgon) to sprite pixels collision method..

kevin

#10
and now you test if point hits a sprites pixels using PointHitSpritePixels(x,y,sprite,accuracy#)

kevin

#11
  Line To Sprite Pixel

   Here's another screenie.  This one is testing the latest  LineHitSpritePixels() command.  While it can detect if an Intersection occurs, it can't return the first  point/normal of intersection.  That's not so easy..

  Also added PointHitSpritePixels().  So you can detect if a pixel overlaps a rotated/scale sprites pixels



PlayBASIC Code: [Select]
   LoadImage "ship.bmp",1
PrepareFXImage 1

Spr =NewSprite(450,150,1)
SpriteDrawMode spr,2+4096
SpriteAlphaAddColour spr,RGB(255,0,255)
RotateSprite spr,45
CenterSpriteHandle spr
SpriteCollisionMode Spr,1

w=GetImageWidth(1)
h=GetImageHeight(1)

max=100
Dim Sprites(MAx)

p=6

For lp=1 To max
Spr2 =NewSprite(Rnd(800),Rnd(600),1)
SpriteDrawMode spr2,2
SpriteImageUV spr2,0,p,p
SpriteImageUV spr2,1,w-p,p
SpriteImageUV spr2,2,w-p,h-p
SpriteImageUV spr2,3,p,h-p

SpriteCollisionMode Spr2,1
CenterSpriteHandle spr2
; ScaleSprite Spr2,RndRange(1,3)
RotateSprite spr2,10
Sprites(lp)=spr2
Next

PositionSprite sprites(1),400,300

Do
Cls RGB(100,100,100)

; PositionSprite spr,MouseX(),MouseY()
TurnSprite spr,(-1*LeftKey())+(1*RightKey())

For lp=1 To max
Spr2=Sprites(lp)
SpriteDrawMode spr2,2
SpriteAlphaAddColour spr2,$00ff00
TurnSprite spr2,0.55
If CompareSpritePixels(spr,spr2,0.50)
SpriteDrawMode spr2,2+4096
EndIf
Next

mX=MouseX()
mY=MouseY()


Dot mx,my

LockBuffer
For lp=1 To max
Spr2=Sprites(lp)
If PointHitSpritePixels(mx,my,spr2,0.5)
SpriteDrawMode spr2,2+4096
SpriteAlphaAddColour spr2,$ffff00
EndIf
Next
UnLockBuffer



Line lastx,lasty,mx,my

LockBuffer
For lp=1 To max
Spr2=Sprites(lp)
If LineHitSpritePixels(lastx,lasty,mx,my,spr2,1)
SpriteDrawMode spr2,2+4096
SpriteAlphaAddColour spr2,$00ffff
EndIf
Next
UnLockBuffer

If MouseButton()=2
lastx=mx
lasty=my
EndIf

DrawAllSprites

Sync
Loop
End







kevin

Line To Sprite Pixel Cont.

 Had a few unexpected issues with LineHitSpritePixels() command. BUt it's fixed now.

kevin

#13
Convex / Concave & Complex Polygon Shape  to Sprite Pixel Collisions

  This pic shows the most recent (and most difficult)  intersection, that being comparing polygon shapes to sprite pixels. Speed wise it's ok, already. Even though implementation is still in it infancy, so there's certainly some room for some fine tuning.   But, it's certainly doable... :)

kevin

#14
The above example.

PlayBASIC Code: [Select]
   LoadImage "ship.bmp",1
PrepareFXImage 1

Spr =NewSprite(450,150,1)
SpriteDrawMode spr,2+4096
SpriteAlphaAddColour spr,RGB(255,0,255)
RotateSprite spr,45
CenterSpriteHandle spr
SpriteCollisionMode Spr,1

w=GetImageWidth(1)
h=GetImageHeight(1)

max=25
Dim Sprites(MAx)

p=6

For lp=1 To max
Spr2 =NewSprite(Rnd(800),Rnd(600),1)
SpriteDrawMode spr2,2
SpriteImageUV spr2,0,p,p
SpriteImageUV spr2,1,w-p,p
SpriteImageUV spr2,2,w-p,h-p
SpriteImageUV spr2,3,p,h-p
; spritetransparent spr2,off

SpriteCollisionMode Spr2,1
CenterSpriteHandle spr2
ScaleSprite Spr2,RndRange#(1,2)
RotateSprite spr2,10
Sprites(lp)=spr2
Next

PositionSprite sprites(1),400,300


TestSHape=NewConvexShape(150,4)
TestSHape2=NewConvexShape(100,5)
MergeShape TestShape2,TestShape

gfxmmx on

Do
Cls RGB(100,100,100)

; PositionSprite spr,MouseX(),MouseY()
TurnSprite spr,(-1*LeftKey())+(1*RightKey())

For lp=1 To max
Spr2=Sprites(lp)
SpriteDrawMode spr2,2
SpriteAlphaAddColour spr2,$00ff00
TurnSprite spr2,(LP/10.0)*0.55
If CompareSpritePixels(spr,spr2,0.5)
SpriteDrawMode spr2,2+4096
EndIf
Next

mX=MouseX()
mY=MouseY()


; mx=300
my=300



LockBuffer
For lp=1 To max
Spr2=Sprites(lp)
If ShapeHitSpritePixels(TestShape,mx,my,0,1,1,spr2)
SpriteDrawMode spr2,2+8192
SpriteAlphaAddColour spr2,$0000ff
EndIf
Next
UnLockBuffer


drawshape testshape,mx,my,2



If MouseButton()=2
lastx=mx
lasty=my
EndIf

DrawAllSprites



Sync

Loop
End