如何在flash AS3中对空心(?)动画片段进行碰撞检测?

时间:2010-04-19 17:05:32

标签: flash actionscript-3 collision-detection

我正在使用flash制作小型互动游戏来学习AS3,现在我遇到了一个需要帮助的问题。

我需要使用hitTestObject功能检查播放器和墙壁之间的碰撞,这通常很简单。

但是现在我制作了一个完全围绕玩家的墙壁物体,走廊和转弯,可以说是一个碰撞操场。

现在,当我使用hitTestObject函数检查玩家是否与墙壁发生碰撞时,它告诉我它总是发生碰撞,因为玩家对象位于墙对象的范围内。

所以假设我对错误是正确的: 当我在墙面物体的边界内但没有碰到那个物体的实际墙壁时,如何防止碰撞?

2 个答案:

答案 0 :(得分:1)

你需要使用一个库,我使用这个类:

package 
{
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.BlendMode;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    /**
     * Use isColliding to test for a collision between two sprites.
     *
     * @author Troy Gilbert
     * @author Alexander Schearer <aschearer@gmail.com>
     */
    public class CollisionDetection
    {
        /** Get the collision rectangle between two display objects. **/
        public static function getCollisionRect(target1:DisplayObject, target2:DisplayObject, commonParent:DisplayObjectContainer, pixelPrecise:Boolean = true, tolerance:Number = 0):Rectangle
        {
            // get bounding boxes in common parent's coordinate space
            var rect1:Rectangle = target1.getBounds(commonParent);
            var rect2:Rectangle = target2.getBounds(commonParent);
            // find the intersection of the two bounding boxes
            var intersectionRect:Rectangle = rect1.intersection(rect2);
            if (intersectionRect.size.length> 0)
            {
                if (pixelPrecise)
                {
                    // size of rect needs to integer size for bitmap data
                    intersectionRect.width = Math.ceil(intersectionRect.width);
                    intersectionRect.height = Math.ceil(intersectionRect.height);
                    // get the alpha maps for the display objects
                    var alpha1:BitmapData = getAlphaMap(target1, intersectionRect, BitmapDataChannel.RED, commonParent);
                    var alpha2:BitmapData = getAlphaMap(target2, intersectionRect, BitmapDataChannel.GREEN, commonParent);
                    // combine the alpha maps
                    alpha1.draw(alpha2, null, null, BlendMode.LIGHTEN);
                    // calculate the search color
                    var searchColor:uint;
                    if (tolerance <= 0)
                    {
                        searchColor = 0x010100;
                    }
                    else
                    {
                        if (tolerance> 1) tolerance = 1;
                        var byte:int = Math.round(tolerance * 255);
                        searchColor = (byte <<16) | (byte <<8) | 0;
                    }
                    // find color
                    var collisionRect:Rectangle = alpha1.getColorBoundsRect(searchColor, searchColor);
                    collisionRect.x += intersectionRect.x;
                    collisionRect.y += intersectionRect.y;
                    return collisionRect;
                }
                else
                {
                    return intersectionRect;
                }
            }
            else
            {
                // no intersection
                return null;
            }
        }

        /** Gets the alpha map of the display object and places it in the specified channel. **/
        private static function getAlphaMap(target:DisplayObject, rect:Rectangle, channel:uint, commonParent:DisplayObjectContainer):BitmapData
        {
            // calculate the transform for the display object relative to the common parent
            var parentXformInvert:Matrix = commonParent.transform.concatenatedMatrix.clone();
            parentXformInvert.invert();
            var targetXform:Matrix = target.transform.concatenatedMatrix.clone();
            targetXform.concat(parentXformInvert);
            // translate the target into the rect's space
            targetXform.translate(-rect.x, -rect.y);
            // draw the target and extract its alpha channel into a color channel
            var bitmapData:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
            bitmapData.draw(target, targetXform);
            var alphaChannel:BitmapData = new BitmapData(rect.width, rect.height, false, 0);
            alphaChannel.copyChannel(bitmapData, bitmapData.rect, new Point(0, 0), BitmapDataChannel.ALPHA, channel);
            return alphaChannel;
        }

        /** Get the center of the collision's bounding box. **/
        public static function getCollisionPoint(target1:DisplayObject, target2:DisplayObject, commonParent:DisplayObjectContainer, pixelPrecise:Boolean = false, tolerance:Number = 0):Point
        {
            var collisionRect:Rectangle = getCollisionRect(target1, target2, commonParent, pixelPrecise, tolerance);
            if (collisionRect != null && collisionRect.size.length> 0)
            {
                var x:Number = (collisionRect.left + collisionRect.right) / 2;
                var y:Number = (collisionRect.top + collisionRect.bottom) / 2;
                return new Point(x, y);
            }
            return null;
        }

        /** Are the two display objects colliding (overlapping)? **/
        public static function isColliding(target1:DisplayObject,
                target2:DisplayObject,
                commonParent:DisplayObjectContainer,
                pixelPrecise:Boolean = false,
                tolerance:Number = 0):Boolean
        {
            var collisionRect:Rectangle = getCollisionRect(target1, target2, commonParent, pixelPrecise, tolerance);
            if (collisionRect != null && collisionRect.size.length> 0) return true;
            else return false;
        }
    }
}

答案 1 :(得分:1)

M28提供的课程实际上是一个交集而不是碰撞课程(Grant Skinner是第一个在AS 2.0中提供一个课程的人)

你可以选择一个小项目,但要记住它没有CCD(连续碰撞检测)

话虽这么说,如果你的玩家的速度大于墙宽,你可以看到他神奇地穿过墙壁。

如果您认为您的项目更复杂,我相信您可以使用像Box2DFlash那样具有CCD的2D物理引擎

http://box2dflash.boristhebrave.com/