1

Suppose we have an object with hitbox having an arbitrary complex shape and an object with circle/polygon as a hitbox. How to detect the collisions of these two objects (not the boundary rectangles, but the actual pixels)? Both objects are opaque Sprites.

Gulvan
  • 305
  • 2
  • 12

2 Answers2

2

Here is a snippet of code I found in ActionScript 3 (https://snipplr.com/view/90435/pixel-perfect-collision-detection-as3/) that looks like it should work in OpenFL.

A Haxe version of the code might look like this:

public function objectsHit (mc1:DisplayObject, mc2:DisplayObject):Bool {

    var mc1bounds = mc1.getBounds (this);
    var mc2bounds = mc2.getBounds (this);
    var allintersections = (mc2bounds.intersection(mc1bounds));

    for (xval in allintersections.x...(allintersections.x + allintersections.width)) {
        for (yval in allintersections.y...(allintersections.y + allintersections.height)) {
            if (mc2.hitTestPoint (xval, yval, true) && mc1.hitTestPoint (xval, yval, true)) {
                return true;
            }
        }
    }

    return false;
}

It might also be possible to use the hitTestObject method first, then to use the hitTestPoint method second. The general idea is to perform bounding box hit detection first, then to perform point-based collision (which is more expensive) if you need something more exact.

Joshua Granick
  • 1,017
  • 6
  • 6
1

Try this. The texture sprites are from the Flambe engine. Essentially the bounding box of the collision, then iterate through the collision box checking each pixel.

    static public function pixelPerfect(sprite1:SpriteContainer, sprite2:SpriteContainer):Bool
    {
        var collisionRect:Rectangle;

        for (texture1 in sprite1.textures)
        {
            for (texture2 in sprite2.textures)
            {
                collisionRect = CollisionUtil.collisionRect(texture1, texture2);
                if (collisionRect == null) continue;

                if (pixelCollision(texture1, collisionRect) && pixelCollision(texture2, collisionRect))
                {
                    return true;
                }
            }
        }

        return false;
    }

static public function pixelCollision(sprite:TextureSprite, collisionRect:Rectangle) 
    {
        var localRectPt:Point = sprite.globalToLocal(collisionRect.x, collisionRect.y);
        localRectPt.x /= Main.GLOBAL_SCALE;
        localRectPt.y /= Main.GLOBAL_SCALE;

        var scaledRect:Rectangle = collisionRect.clone();
        scaledRect.width /= Main.GLOBAL_SCALE;
        scaledRect.height /= Main.GLOBAL_SCALE;

        var PIXEL_DATA_LENGTH:Int = 4;
        var PIXELS_TO_SKIP:Int = 5;
        var resolution:Int = PIXEL_DATA_LENGTH * PIXELS_TO_SKIP;
        var alphaOffset:Int = 3;
        var bytes:Bytes;
        try{
            bytes = sprite.symbol.atlas.readPixels(Math.round(localRectPt.x), Math.round(localRectPt.y), Math.round(scaledRect.width), Math.round(scaledRect.height));
            var n:Int = bytes.length;
            var i:Int = 0;
            while(i+3<n)
            {
                if (bytes.get(i + alphaOffset) > 0)
                {
                    return true;
                }

                i += resolution;
            }
        }
        catch (e:Dynamic)
        {
            Log.trace(e);
        }

        bytes = null;

        return false;
    }
}
Jon Grant
  • 49
  • 5
  • Is there any way to do it without Flambe? I suppose I must use Bitmap and its BitmapData, right? Sprites do not seem to have such properties as texture – Gulvan Jan 20 '19 at 21:53