4

I am here, because I'm currently struggling with collision detection for my AS3 application. I am loading a bitmap, that represents a room - it has boundaries (walls) and the rest of it is transparent (the floor). I then create a sprite with a circle inside.

I would like my sprite to move within those boundaries and stop at the wall, I'm capable of implementing logics behind that, what I'm asking for is a method to detect the collision with a wall, my whole room is a bitmap, so I guessed I'll just check for the collision with this bitmap, but unfortunately it also counts the transparent parts.

I've done a google research on that, but I only found very complex system which won't work anyway. I'm doing that on learning purposes, so I would like to know how to implement it myself.

Therefore I'm asking if anyone could provide me with piece of code that would check for collision only for non-transparent parts of my bitmap? (Or should I load this png as a vector? how to do so?).

I'm also rotating my "circle", so I guess this should be also considered. I assume I should do bitmap to bitmap check rather than sprite to bitmap?

I have no working code for collisions at all, so I won't provide any.

Should I provide more information please tell me.

Thanks in advance!

@EDIT

this is code I have for my function, it belongs to Room Class.

public function detectCollisionWith(obj:Sprite):Boolean
    {
        var _bitmapData:BitmapData = new BitmapData(obj.width, obj.height, true, 0);
        _bitmapData.draw(obj);
        var _bitmap:Bitmap = new Bitmap(_bitmapData);
        if (_bitmapData.hitTest(new Point(_bitmap.x, _bitmap.y), 255, this.bitmap, new Point(this.x, this.y), 255))
            return true;
        return false;
    }
pzaj
  • 1,062
  • 1
  • 17
  • 37

3 Answers3

4

You can very easily check this when they are both bitmaps using the BitmapData hitTest().

Adobe on bitmapData hitTest():

Performs pixel-level hit detection between one bitmap image and a point, rectangle, or other bitmap image. A hit is defined as an overlap of a point or rectangle over an opaque pixel, or two overlapping opaque pixels. No stretching, rotation, or other transformation of either object is considered when the hit test is performed.


Now an example of how to implement it. If you turn your sprite into a bitmap:

var spriteBmd:BitmapData = new BitmapData( mySprite.width, mySprite.height, true, 0 );
spriteBmd.draw( mySprite ); //get the sprite asset
var spriteBitmap:Bitmap = new Bitmap( spriteBmd ); //create the bitmap to use

Then you can run the hitTest() against the two bitmaps disregarding transparent sections:

if ( spriteBitmap.bitmapData.hitTest( new Point( mySprite.x, mySprite.y ), 
     255, levelBitmap, new Point( levelBitmap.x, levelBitmap.y ), 255 ) ) {
    trace("Collision detected");
}

This checks only the opaque sections of the bitmaps for collision. You can adjust the values 255 in the if statement if you want to increase how much transparency is allowed for detection.

Bennett Keller
  • 1,724
  • 2
  • 11
  • 11
  • well, this looks pretty simple, one thing does make me confused though, why do I need to pass x and y of those bitmaps? Does that mean it only tests 1 point (pixel) and I need to loop through all points of both bitmaps? – pzaj Mar 12 '14 at 18:36
  • No you do not need to send all the points, just the x and the y of the bitmaps. The points just tell it where to start and where to end, if you passed in display objects the algorithm is going to sift through their respective boundaries. Alternatively you could just pass the points of their top left to bottom right bounds. – Bennett Keller Mar 12 '14 at 18:40
  • Alright, I'll give it a go and get back here with some results (hopefully positive). What about performance? Will it not affect it significantly for bitmaps that huge (I'll have about 5000 x 5000 "rooms" png). – pzaj Mar 12 '14 at 18:41
  • Well as far as performance, any collision test is pretty expensive. This one in particular using bitmaps is among the most expensive since it factors in transparency. So size will definitely play a factor, but since you are just checking 2 bitmaps it may not be terrible. But a heads up, there is a max size for bitmapdata, "...the maximum size for a BitmapData object is 8,191 pixels in width or height, and the total number of pixels cannot exceed 16,777,215 pixels. (So, if a BitmapData object is 8,191 pixels wide, it can only be 2,048 pixels high.)" in FP9 and earlier it's lower. – Bennett Keller Mar 12 '14 at 18:46
  • alright, so I guess I'll have to split my image to certain rooms, even better. I may then check with hitTestObject whether my sprite is within a room's boundaries and after that perform bitmaps testing. As far as fps won't drop noticeably im happy. – pzaj Mar 12 '14 at 19:07
  • can't make it work, I've added some code at the top, it is a function I call when hitTestObject == true. I call from `Room` instance passing my sprite as a parameter. I guess something with x and y is messed up :> – pzaj Mar 12 '14 at 19:15
  • Use the sprites x and y, the bitmaps x,y is set to 0 here. I should have been more explicit about that, I'll update my answer accordingly. But be weary using bitmaps like this, usually it's best just to store the bitmapData once alongside the sprite, then use the sprites x and y. My example is very simple, but I manipulate the bitmap and not the sprite in most cases. You'll need to nullify the bitmap and dispose() the bitmapData if you create it this way. – Bennett Keller Mar 12 '14 at 19:22
  • thanks for that, I added disposal of bitmap (if I nullify it before I can't dispose, should it be another way around?), I also mapped my x and y of levelbitmap using `localToGlobal` and it now works well, but I'm afraid I'll have problems when I'll "scroll" my screen now, maybe I should map sprite coords using `globalToLocal` instead? – pzaj Mar 12 '14 at 20:06
  • Personally I don't even bother with the globalToLocal localToGlobal conversion. I use getBounds() on the display object instead. And yeah switch around the dispose and null. – Bennett Keller Mar 12 '14 at 20:08
  • may I contact You another way? I came up with another problem. I remember You answered my last questions as well, so I doubt posting it here will do the difference. I'll state here briefly that it's because my "circle" on the sprite is shifted towards sprite's x and y (falls outside the sprite) to make it easily rotated - I've tried rotating with matrix, but it did not rotate around it's center, instead it randomly rotated and moved out of pos. This cut's my test bitmap unfortunately. – pzaj Mar 12 '14 at 20:16
0

did it many years ago... but if i'm not wrong you can solve the problem creating a MC with the vector shape of the wall (place it below the wall) and check the collision with it rather than with the bitmap.

Nadia
  • 247
  • 1
  • 13
  • great, that might do, but how do I get the vector of my image to be placed on mc? – pzaj Mar 12 '14 at 16:52
  • not really, it's way too complex to draw it, will take ages, along with walls I have other objects there for the final product and they all must be mapped from png. I've managed to make it work with [AirBag](http://cote.cc/w/wp-content/uploads/projects/airbag) lib, but I'll have to drop it due it's vulnerability on uncatching collisions - for no apparent reason I sometimes gets through the wall or I land on it (then there is a funny thing when I try to get off it). SO it does what I need (reads png with transparency), but won't make me bounce or stop sometimes. – pzaj Mar 12 '14 at 17:44
  • too long even if you pass form illustrator, convert the bitmap in curves, remove the transparent parts and import it in flash? – Nadia Mar 12 '14 at 17:57
  • oh, I thought to draw it programically! I have it as vector since I've made it using corel, but I have no idea what file type I should use? .svg? Can it be loaded to flash? – pzaj Mar 12 '14 at 18:05
  • You can import a vector with several formats: .ai .swf .dxf .fxg If corel can't export to these formats, you'll find for sure some converter – Nadia Mar 13 '14 at 11:15
0

Simple room? Is it simple rectangle? So, I would recommend calculate collision by checking if point in the predefined rectangle. Create Rectangle, inset it's size on radius of your circle, and check if center of the circle inside of rectangle

//Some room
var roomBounds:Rectangle = new Rectangle(0, 0, 700, 500);
const circleRadius:int = 10;
var collisionBounds: Rectangle = new Rectangle(circleRadius, circleRadius, roomBounds.width - 2*circleRadius, roomBounds.height - 2*circleRadius);

//Check if center of circle inside of collisionBounds
//For example you have point with name circlePosition
//collisionBounds.containsPoint(circlePosition)
if(!collisionBounds.contains(circleX, circleY)){
    trace("Houston! We have collision here!");
}
Nicolas Siver
  • 2,875
  • 3
  • 16
  • 25
  • unfortunately not, it's more complex room, well, it's more than one room for the complete info, but I now try to work my first room, so I can stop on Walls. – pzaj Mar 12 '14 at 16:51