Проведите тест в AS3 между неправильным объектом и прямоугольником и получите верхнюю координату y перекрывающейся области.

Как я могу проверить столкновение между прямоугольником и неправильным объектом в AS3? И как мне тогда получить наименьшее значение y перекрытия (верхнего)?

Изменить
Большое спасибо за ответ, но метод checkCollision всегда возвращает false. Это мой код:

public static function checkCollision(object1:*, object2:*):Boolean{
    var object1Rect:Rectangle = object1.getRect(stage);
    var object2Rect:Rectangle = object2.getRect(stage);

    var bitmapData1:BitmapData = new BitmapData(
        object1.width, 
        object1.height, 
        true, 
        0
    );
    var bitmapData2:BitmapData = new BitmapData(
        object2.width, 
        object2.height, 
        true, 
        0
    );

    bitmapData1.draw(object1);
    bitmapData2.draw(object2);

    var bCollide:Boolean = bitmapData1.hitTest(
        new Point(object1Rect.x, object1Rect.y),
        255,
        bitmapData2,
        new Point(object2Rect.x, object2Rect.y),
        255
    );

    bitmapData1.dispose();
    bitmapData2.dispose();

    return bCollide;
}

person Jonan    schedule 13.07.2014    source источник


Ответы (1)


Если это сложная форма, используйте растровые данные, как показано ниже. Это будет работать для всех форм.

Если вам все еще нужно знать самое низкое значение Y, не забывайте, что оно может быть и на X. Там есть дополнительная функция (getHitPoint) для расчета этого, которую нужно запускать только при успешном тесте на попадание. Его можно оптимизировать, передав в него растровые данные из исходной функции, но я сохранил его отдельно, чтобы он оставался читабельным.

package kazo 
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * ...
     * @author KM
     */
    public class TestCases extends Sprite
    {

        private var rect    :Sprite;
        private var circle  :Sprite;

        public function TestCases() { }

        /**
         * Start the test case
         */
        public function start():void {
            trace('Starting test case');

            // Rectangle
            rect = new Sprite();
            // Circle
            circle = new Sprite();

            // Draw the rectangle. Center point must be TOP LEFT
            // If you're using Flash Professional, place everything at 0,0 inside the MC
            rect.graphics.beginFill(0xff0000);
            rect.graphics.drawRect(0, 0, 100, 100);
            rect.graphics.endFill();

            // Draw the circle. Center point is TOP LEFT, so the X and Y of the circle need to be equal to the radius
            circle.graphics.beginFill(0xffff00);
            circle.graphics.drawCircle(50, 50, 50);
            circle.graphics.endFill();

            // Add them
            addChild(rect);
            addChild(circle);

            // Position
            rect.x = 0;
            rect.y = 100;

            // Position
            circle.y = 400;
            circle.x = 0;

            // Frame loop
            addEventListener(Event.ENTER_FRAME, frameFunc);
        }

        /**
         * 
         * @param   e
         */
        private function frameFunc(e:Event):void {
            // move them around
            rect.y += 1;
            circle.y -= 1;
            circle.x += 1;
            rect.x += 1;

            // Check for collisions. If found, stop. Pass 'true' as the final param if you want it to draw to the screen
            if (checkCollision(rect, circle)) {
                trace(getHitPoint(rect, circle));

                removeEventListener(Event.ENTER_FRAME, frameFunc);
            }
        }

        /**
         * 
         * @param   _obj1
         * @param   _obj2
         * @param   _debug
         * @return
         */
        private function checkCollision(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Boolean {
            // Draw the first item to bitmapdata
            var bmd1:BitmapData = new BitmapData(_obj1.width, _obj1.height, true, 0);
            // ..and the second
            var bmd2:BitmapData = new BitmapData(_obj2.width, _obj2.height, true, 0);

            // Now draw them
            bmd1.draw(_obj1);
            bmd2.draw(_obj2);

            // If we're in debug, also add the bitmap to the stage so we can see where we are
            if (_debug) {
                var bmp:Bitmap = new Bitmap(bmd1);
                bmp.x = _obj1.x;
                bmp.y = _obj1.y;
                addChild(bmp);

                var bmp2:Bitmap = new Bitmap(bmd2);
                bmp2.x = _obj2.x;
                bmp2.y = _obj2.y;
                addChild(bmp2);
            }

            // Hit test including alpha channel. Obj1 X/Y, Obj2 X/Y, alpha channel
            var rtn:Boolean = bmd1.hitTest(new Point(_obj1.x, _obj1.y), 255, bmd2, new Point(_obj2.x, _obj2.y), 255);

            // Dispose the bitmap data, we dont need it anymore
            if (!_debug) {
                bmd1.dispose();
                bmd2.dispose();
            }


            // Return the boolean
            return rtn;
        }

        /**
         * This ONLY needs to be called once a collision has been confirmed. Don't run this on every frame!
         * @return
         */
        private function getHitPoint(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Point {
            var rtnPoint:Point = new Point();

            // Draw the first item to bitmapdata
            var bmd1:BitmapData = new BitmapData(_obj1.width, _obj1.height, true, 0);
            // ..and the second
            var bmd2:BitmapData = new BitmapData(_obj2.width, _obj2.height, true, 0);

            // Now draw them
            bmd1.draw(_obj1);
            bmd2.draw(_obj2);

            // Create two bitmaps
            var bmp1:Bitmap = new Bitmap(bmd1);
            var bmp2:Bitmap = new Bitmap(bmd2);

            // Position
            bmp1.x = _obj1.x;
            bmp2.x = _obj2.x;
            bmp1.y = _obj1.y;
            bmp2.y = _obj2.y;

            // Get the origins
            var bitmapOrigin:Point = new Point(_obj1.x, _obj1.y);
            var bitmapTwoOriginLocal:Point = bmp2.globalToLocal(bitmapOrigin);

            // Find all the overlapping pixels
            var overlappingPixels:Vector.<uint> = bmp2.bitmapData.getVector(new Rectangle(bitmapTwoOriginLocal.x, bitmapTwoOriginLocal.y, _obj1.width, _obj1.height));

            var i:uint = 0;
            var len:uint = overlappingPixels.length;

            // Run through them all until we find a non-zero value
            for(i; i < len; i++) {
                if(overlappingPixels[i] != 0) {
                    // Our X collision is i % _obj1.width plus whichever X value is highest
                    rtnPoint.x = (i % _obj1.width) + (bmp2.x > bmp1.x ? bmp2.x : bmp1.x);
                    // Our Y collision is i / _obj1.height plus whichever Y value is highest
                    rtnPoint.y = (uint((i + 1) / _obj1.width)) + (bmp2.y > bmp1.y ? bmp2.y : bmp1.y);

                    // If debug, draw the collision point
                    if (_debug) {
                        var test:Sprite = new Sprite();
                        test.graphics.beginFill(0x008c6f);
                        test.graphics.drawRect(rtnPoint.x , rtnPoint.y, 10, 10);
                        test.graphics.endFill();
                        addChild(test);
                    }

                    break;
                }
            }

            // Send it back
            return rtnPoint;
        }

    }

}
person Kevin McGowan    schedule 13.07.2014
comment
Я попробую это завтра, и я приму ваш ответ, если он сработает. - person Jonan; 14.07.2014
comment
По какой-то причине checkCollision() всегда возвращает false, даже если объекты добавлены на сцену и вы можете видеть, как они сталкиваются - person Jonan; 14.07.2014
comment
Попробуйте передать true в качестве последнего параметра в checkCollision, чтобы увидеть, куда движется растровое изображение. Вы уверены, что ваша центральная точка находится вверху слева? - person Kevin McGowan; 14.07.2014
comment
Когда я создаю Bitmap из BitmapData и добавляю его на сцену, ничего не меняется - person Jonan; 14.07.2014
comment
Функция имеет параметр для отладки. частная функция checkCollision(_obj1:Sprite, _obj2:Sprite, _debug:Boolean = false):Boolean {}. Передайте 3-ю переменную как истину. - person Kevin McGowan; 15.07.2014
comment
тем не менее, bitmap не отображаются. И центральные точки тестируемых объектов могут быть где угодно - person Jonan; 15.07.2014
comment
Если центральные точки не находятся вверху слева, описанное выше не будет работать. Первые две точки должны быть в левом верхнем углу. Если растровые изображения не отображаются, это также означает, что заданные точки отсутствуют, что будет связано с центральной точкой. - person Kevin McGowan; 16.07.2014
comment
Думаю, тогда я мог бы выполнить getBounds() для объектов и использовать полученные значения x и y? - person Jonan; 16.07.2014
comment
Я отредактировал свой ответ на код, который у меня есть сейчас (все еще не работает, хотя я получаю верхнее левое значение x и y) - person Jonan; 16.07.2014
comment
Все еще ничего не тянет на сцену? - person Kevin McGowan; 17.07.2014
comment
Несколько вещей не так с тем, что вы показали. Подожди. - person Kevin McGowan; 17.07.2014
comment
Итак, во-первых, избавьтесь от статического метода. Вы не можете получить доступ к этапу или добавить туда ребенка. Должно выдавать ошибки. Во-вторых, если вы хотите рисовать на сцене из функции, закомментируйте две функции удаления в растровых данных. В-третьих, предполагая предыдущее, измените последний 0 в растровых данных на цвет (я использую 0xff0000). Наконец, попробуйте использовать мою точную функцию для checkCollision. Я просто скопировал/вставил его, добавил два клипа и случайным образом переместил их X/Y, и это работает. Это не сработает, только если вы примените повороты. - person Kevin McGowan; 17.07.2014
comment
Я отредактировал, чтобы включить свои комментарии в код. Вызов этого с помощью checkCollision(obj1, obj2, true) теперь будет отображаться на экране. - person Kevin McGowan; 17.07.2014
comment
Я исправил это (не спрашивайте меня как, потому что я не знаю), и я знаю, как я могу получить верхнюю и нижнюю точку жизни (просто выполните overlappingPixels.reverse(), чтобы получить нижнюю) - но есть ли способ получить левый и правый хитпойнт? - person Jonan; 18.07.2014
comment
Я исправил небольшую ошибку в getHitPoint() (см. правку). Есть ли способ получить самое левое, самое правое и нижнее очко жизни? Если вы знаете способ, ответьте на здесь - person Jonan; 19.07.2014
comment
Вы бы сделали то же самое, что и я, для вершины, но для высоты вместо ширины. :) - person Kevin McGowan; 19.07.2014
comment
Не могли бы вы объяснить это? Боюсь, я действительно не понимаю (кстати, я уже узнал, как получить нижнюю точку, см. новый вопрос) - person Jonan; 19.07.2014
comment
Я отвечу на другой вопрос - person Kevin McGowan; 20.07.2014