Хиттест для двух форм объектов - PullRequest
0 голосов
/ 07 января 2019

Предположим, у нас есть объект с хитбоксом, имеющим произвольную сложную форму, и объект с кругом / многоугольником в качестве хитбокса. Как обнаружить столкновения этих двух объектов (не граничных прямоугольников, а реальных пикселей)? Оба объекта являются непрозрачными спрайтами.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Вот фрагмент кода, который я нашел в ActionScript 3 (https://snipplr.com/view/90435/pixel-perfect-collision-detection-as3/), который выглядит так, как будто он должен работать в OpenFL.

Haxe-версия кода может выглядеть следующим образом:

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;
}

Возможно также сначала использовать метод hitTestObject, а затем - метод hitTestPoint. Основная идея заключается в том, чтобы сначала выполнить обнаружение попадания в ограничивающую рамку, а затем выполнить основанное на точке столкновение (что обходится дороже), если вам нужно что-то более точное.

0 голосов
/ 18 января 2019

Попробуй это. Спрайты текстуры взяты из движка Flambe. По сути, ограничивающий прямоугольник столкновения, затем итерируйте по полю столкновений, проверяя каждый пиксель.

    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;
    }
}
...