CollideImage Function?
BlitzMax Forums/BlitzMax Beginners Area/CollideImage Function?
| ||
hey i was wondering if anyone knew how to use collideimage on rotated images as its puzzled me a bit, thanks alot :D |
| ||
bump |
| ||
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 |
| ||
I would really appreciate it if someone could explain the collision functions. |
| ||
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: |
| ||
What exactly does CollideImage return though? |
| ||
These collisions aren't pixelperfect, right? |
| ||
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 |
| ||
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 |
| ||
Indeed! Works if you add 'AutoMidHandle True' before creating the images...One for the bug reports then... |
| ||
er... isn't this really hard work? Whatever happened to normal collisions? |
| ||
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... |
| ||
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 |
| ||
and here is a fixed version of Fredborg's (what's with the nic???) test (was not calling rotate b4 collideimage testing) : |
| ||
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 |
| ||
Thank you for the helper functions. Aren't collisions now really slow? Sorry if it's a silly question. |
| ||
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. |
| ||
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? |
| ||
Maybe what is really slow is how long it will take you guys to figure out how fast my collision system is. |
| ||
hehe |
| ||
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? |
| ||
Do you mind if I stick those "helper functions" in my module'o'random functions that I may or may not be uploading eventually? |
| ||
clear as mud... |
| ||
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. |
| ||
Damnit i just wrote some clever coding to wrap those.. someone here beat me to it though you gets ^.^ nice work as always! |
| ||
So does CollideImage actually render pixels to some kind of buffer in order to check for collisions? |
| ||
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 |
| ||
AngelDaniel, no it doesnt do any actual rendering. |
| ||
denzilquixode : Thanks for the example. I think I can just about figure it out from there :) |
| ||
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 |
| ||
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? |
| ||
Argh Its not working.. It ignores the friggin collision |
| ||
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? |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
They aren't slower. they are just quad tests and now pixel perfect test which is only done through collision layer. |
| ||
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 |
| ||
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. |