【问题标题】:how to do collision detection for hollow(?) movieclips in flash AS3?如何在 Flash AS3 中对空心(?)影片剪辑进行碰撞检测?
【发布时间】:2010-04-19 17:05:32
【问题描述】:

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

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

但现在我制作了一个完全围绕玩家的墙壁对象,带有走廊和转弯,可以说是一个碰撞游乐场。

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

所以假设我对错误是正确的: 当我在墙对象的边界内但没有接触到该对象中的实际墙时,如何防止发生碰撞?

【问题讨论】:

    标签: flash actionscript-3 collision-detection


    【解决方案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;
            }
        }
    }
    

    【讨论】:

    • 我对AS3的包和类系统不是很熟悉。您介意解释一下如何在我的项目中实现该库吗?
    • CollisionDetection.isColliding(target1,target2,commomParent,pixelPrecise, alphaTolerance);
    【解决方案2】:

    M28 提供的类实际上是 Intersection 而不是碰撞类(Grant Skinner 是第一个在 AS 2.0 中提供的类)

    您可以将它用于一个小项目,但请记住它不执行 CCD(连续碰撞检测)

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

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

    http://box2dflash.boristhebrave.com/

    【讨论】:

      猜你喜欢
      • 2014-01-31
      • 1970-01-01
      • 2018-03-29
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多