代码之家  ›  专栏  ›  技术社区  ›  Gulvan

两个物体形状的测试

  •  0
  • Gulvan  · 技术社区  · 7 年前

    假设我们有一个具有任意复杂形状的Hitbox的对象和一个具有圆形/多边形作为Hitbox的对象。如何检测这两个对象的碰撞(不是边界矩形,而是实际像素)?两个对象都是不透明的精灵。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Joshua Granick    7 年前

    以下是我在ActionScript3中找到的代码片段( 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 方法二。一般的想法是先执行边界框命中检测,然后在需要更精确的东西时执行基于点的碰撞(更昂贵)。

        2
  •  0
  •   Jon Grant    7 年前

    试试这个。纹理精灵来自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;
        }
    }