CollideImage Function?

BlitzMax Forums/BlitzMax Beginners Area/CollideImage Function?

SSS(Posted 2004) [#1]
hey i was wondering if anyone knew how to use collideimage on rotated images as its puzzled me a bit, thanks alot :D


SSS(Posted 2004) [#2]
bump


Muttley(Posted 2004) [#3]
I'm having difficulty working out how to using either of the collide functions at all.

Has anyone got any example code which uses these? There's none in the samples included with Max it seems.

Cheers

Muttley


Robert(Posted 2004) [#4]
I would really appreciate it if someone could explain the collision functions.


fredborg(Posted 2004) [#5]
Collisions are based on 'layers' which is quite different from how other versions of Blitz does it.

Basically you do it like this:
1 - Write everything you want your image to collide with to a collision layer.
2 - Check the image against the collision layer.

It's quite simple.

Here's a small example:



Robert(Posted 2004) [#6]
What exactly does CollideImage return though?


Grisu(Posted 2004) [#7]
These collisions aren't pixelperfect, right?


Muttley(Posted 2004) [#8]
I'm not sure if it's the example code, but when I was running it with just 2 objects they were sometimes going red even when they weren't even close. And sometimes they didn't go red at all, even if they were sitting on top of one another. :?

Muttley


Muttley(Posted 2004) [#9]
Ah, seems to be the rotation that's screwing things up. If you comment out that it works perfectly.

So the question is, why does the rotation screw it up? ;)

Muttley


fredborg(Posted 2004) [#10]
Indeed! Works if you add 'AutoMidHandle True' before creating the images...One for the bug reports then...


flying willy(Posted 2004) [#11]
er... isn't this really hard work?

Whatever happened to normal collisions?


AntonyWells(Posted 2004) [#12]
It's not that simple when you're using 3d hardware to blit images.
Rotation/Scale means the default image data usually has little bearing on the actual visual data being seen.

I dunno why they didn't make it more functional from the get go, but I guess they don't have it considering we have the source. As long as the core functionality is there...


BlitzSupport(Posted 2004) [#13]
Like Antony says, the images can now be arbitrarily scaled and rotated, so pixel-perfect collision detection (which Max2D does) isn't a trivial matter.

As this isn't properly documented yet, I'll post what Mark sent to me, as it should help others get going in the meantime:


The basic idea is that the collidemask and writemask parameters are bitmasks
(eg: 1,2,4,8,16 etc) giving you up to 32 'layers' to write/collide to/with. For
example, you could use the following layers:

background=0, monsters=1, pickups=2, player=3.

The bitmasks for these would be 1,2,4,8 respectively (bitmask=1 Shl layer).

Using a bitmask instead of just a layer number allows you to specify
multiple layers, eg: bitmask 3 would mean both layer 0 and layer 1.

CollideImage simultaneously writes an image to 0-32 layers (depending
on the writemask) and checks for collisions with 0-32 layers (depending
on the collidemask).

By 'writes an image', all it really does internally is store the image,
and current rot/scale etc. However, you can think of it as physically
'writing' the image.

For collision detection, CollideImage returns an array of objects for
each collision detected. These objects were provided by previous
CollideImage calls, and are by default Null. For complex games, they
could be an 'Entity' object or some such.

However, since an array is True if it has any objects in it, you can
just use 'If CollideImage( blah,...)' for quick and easy detection.

...

Here's a little demo. Place in 'firepaint' dir:



Strict

Graphics 640,480

Local img=LoadImage( "player.png" )
MidHandleImage img

Local rot#=0

While Not KeyHit( KEY_ESCAPE )

Cls

ResetCollisions

Local mx=MouseX(),my=MouseY()

'draw spinny ship in centre
rot:+.1
SetRotation rot
DrawImage img,320,240
CollideImage img,320,240,0,0,1   'writes image to collision layer 0,
doesn't collide with any layers

SetRotation 0
DrawImage img,mx,my
Local colls:Object[]=CollideImage( img,mx,my,0,1,0 ) 'collides image
with collision layer 0, doesn't write to any layers

If colls
DrawText "BANG!",0,0
EndIf

Flip

FlushMem
Wend



skidracer(Posted 2004) [#14]
and here is a fixed version of Fredborg's (what's with the nic???) test (was not calling rotate b4 collideimage testing) :



skidracer(Posted 2004) [#15]
here's some helper functions for those not wanting to deal with the complexities of layers:
Function ImagesCollide(image1,x1,y1,frame1,image2,x2,y2,frame2)
	ResetCollisions
	CollideImage image1,x1,y1,frame1,0,1
	Return CollideImage(image2,x2,y2,frame2,1,0)
End Function

Function ImagesCollide2(image1,x1,y1,frame1,rot1,scale1,image2,x2,y2,frame2,rot2,scale2)
	ResetCollisions
	SetRotation rot1
	SetScale scale1
	CollideImage image1,x1,y1,frame1,0,1
	SetRotation rot2
	SetScale scale2
	Return CollideImage(image2,x2,y2,frame2,1,0)
End Function



flying willy(Posted 2004) [#16]
Thank you for the helper functions.

Aren't collisions now really slow? Sorry if it's a silly question.


Hotcakes(Posted 2004) [#17]
Pixel perfect image collision was always very slow, but it's probably a little worse now with all this extra stuff to take into account.


ImaginaryHuman(Posted 2004) [#18]
There is such a thing in OpenGL called Bitmaps which are 1-bit images, which could perhaps be used in a similar way to masks, and surely they would be drawn pretty quick, maybe they can be all drawn onscreen first or maybe to the depth buffer or the stencil buffer or something, and use some kind of other feature to do something particular if the values are higher or lower or something, and binary divide it, to get image collision? Then after that draw the real color images?


skidracer(Posted 2004) [#19]
Maybe what is really slow is how long it will take you guys to figure out how fast my collision system is.


LarsG(Posted 2004) [#20]
hehe


Robert(Posted 2004) [#21]
I have looked through the source in Max2D.bmx but I still don't quite follow how the system works internally. Could you enlighten us skidracer?


Diordna(Posted 2004) [#22]
Do you mind if I stick those "helper functions" in my module'o'random functions that I may or may not be uploading eventually?


RiK(Posted 2004) [#23]
clear as mud...


RiK(Posted 2004) [#24]
Could someone perhaps provide an example, or a modification of Marks example above which illustrates a more real-world case?

i.e.
Lets say I have a one list of player bullets which I need to test against another list of enemy sprites, resulting the identity of the specific bullet/alien which collided.

Sorry if I'm being thick here but compared to the old Blitz collisions this is making no sense to me at all.


Damien Sturdy(Posted 2004) [#25]
Damnit i just wrote some clever coding to wrap those.. someone here beat me to it though you gets ^.^ nice work as always!


ImaginaryHuman(Posted 2004) [#26]
So does CollideImage actually render pixels to some kind of buffer in order to check for collisions?


taxlerendiosk(Posted 2004) [#27]
i.e. Lets say I have a one list of player bullets which I need to test against another list of enemy sprites, resulting the identity of the specific bullet/alien which collided.


Here's my attempt, bare in mind I'm not 100% sure of it all yet. Assuming bullet-to-alien collisions are the only ones you're interested in (not bullet-to-bullet etc):

Type TAlien
  Global AlienImage:TImage
  Global AlienList:TList
  Field X:Int
  Field Y:Int
  ...
End Type

Type TBullet
  Global BulletImage:TImage
  Global BulletList:TList
  Field X:Int
  Field Y:Int
  ...
End Type

'...

Const ALIEN_LAYER = 1 ' Collision layer used for aliens

Function DoCollisions()

  ResetCollisions ALIEN_LAYER

  For A:TAlien = EachIn TAlien.AlienList
    CollideImage(TAlien.AlienImage, A.X, A.Y, 0, 0, ALIEN_LAYER, A)
  Next

  Local AliensCollided:Object[]

  For B:TBullet = EachIn TBullet.BulletList
    AliensCollided = CollideImage(TBullet.BulletImage, B.X, B.Y, 0, ALIEN_LAYER, 0, Null)
    For i = 0 To Len(AliensCollided)-1
      A:TAlien = TAlien(AliensCollided[i])
      ' Alien = A
      ' Bullet = B
    Next
  Next
 
End Function



Damien Sturdy(Posted 2004) [#28]
AngelDaniel, no it doesnt do any actual rendering.


RiK(Posted 2004) [#29]
denzilquixode :

Thanks for the example. I think I can just about figure it out from there :)


Matt McFarland(Posted 2005) [#30]
I dont get it..

First of all, with if you assign an image to a certain layer, when do you do it?

Do you do it in the Type's create function?

Also where do you check for collisions? In a type? Or in the main loop?

If you assign them all to the same layer, how does it detect if they are colliding? Dont they only collide if a layer collides with a different layer?

If I were to shoot an alien with a layer 1 missile to a layer 0 alien how do you check for that?

Why doesnt this make sense? lol


Matt McFarland(Posted 2005) [#31]
Ok, so I get the collision detection part.. And it responds right by changing the ball, but how do I get it to destroy the block? Do the collection in the block instead of the ball?


Matt McFarland(Posted 2005) [#32]
Argh Its not working..

It ignores the friggin collision


Matt McFarland(Posted 2005) [#33]
How does it identify what object it last hit?

Lets say I make a group of blocks and assign them a layer of 0.

Lets say the ball hits something in 0 layer.. How does this ball know which unit in the block list it hit? How?


skidracer(Posted 2005) [#34]
from Denzil's code above

  For B:TBullet = EachIn TBullet.BulletList
    AliensCollided = CollideImage(TBullet.BulletImage, B.X, B.Y, 0, ALIEN_LAYER, 0, Null)
    For i = 0 To Len(AliensCollided)-1
      A:TAlien = TAlien(AliensCollided[i])
      ' Alien = A
      ' Bullet = B
    Next
  Next


Translated into english

for every bullet check to see if where I am next going to draw the bullet will collide with any aliens (or in your case blocks)

AliensCollided is an array which is not evident from the code snippet because it is non strict.

in strict BlitzMax you will need something like

Local blocksCollided:Object[]

to be the variable you use to receive result of CollideImage.

I would personally replace the for next loop with the following:

For myblock:TBlock=eachin blocksCollided()
block.Kill
next

which brings us to the interesting point of how block can delete itself, hopefully it is a member of a blocklist or in an array so your Kill method simply needs to remove it from there.


Matt McFarland(Posted 2005) [#35]
IT's in a blocklist.. But I just reversed the process to get it to work.

I put the ball at the top of the update list and made it in the collision layer, and if anything collides with the ball then it kills itself.


JazzieB(Posted 2005) [#36]
Although this layer stuff may have its uses (I've not tried them yet), you can use the old Blitz3D way of checking two images - ImagesCollide() and ImagesCollide2(). The first is the same as Blitz3D, the second has additional parameters for rotation and scale.

These may be slower than using layers, but I haven't checked. Perhaps someone else has and can enlighten the rest of us.


Dreamora(Posted 2005) [#37]
They aren't slower. they are just quad tests and now pixel perfect test which is only done through collision layer.


JazzieB(Posted 2005) [#38]
They're not quad tests, they ARE pixel perfect tests. Even the docs say this and it doesn't take long to test it...

Graphics 640,480

Global box:TImage=CreateImage(64,64)
Global circle:TImage=CreateImage(64,64)

SetColor 255,0,0
DrawRect 0,0,64,64
GrabImage box,0,0

Cls
SetColor 0,255,0
DrawOval 0,0,64,64
GrabImage circle,0,0

SetColor 255,255,255

While Not KeyHit(key_escape)
	Local mx:Int=MouseX(),my:Int=MouseY()
	Cls
	DrawImage box,288,208
	DrawImage circle,mx-32,my-32
	If ImagesCollide(box,288,208,0,circle,mx-32,my-32,0) Then DrawText "Collision",10,10
	Flip;FlushMem
Wend



tonyg(Posted 2005) [#39]
James suggested that a native 'rectsoverlap' was needed...
rectsoverlap
and it would have been nice to have imagerectoverlap but, it seems, they were never added.
Maybe in the next release.... maybe?
<edit> I know it's easy to roll-your-own.