Каков предпочтительный способ обнаружения переворачивания / разворачивания мыши во Flash с AS3

Предположим, у нас есть сцена с двумя квадратами, вот так:Наш пример Flash-сцена

Предположим, что мы хотим, чтобы желтый квадрат был изначально скрыт, и нам бы хотелось, чтобы курсор мыши находился внутри границ красного квадрата - желтый квадрат был виден и до тех пор, пока курсор мыши отсутствует из границ красного квадрата - что желтый квадрат будет скрыт.

Интуитивный подход - написать что-то вроде этого:

inSqr.visible = false;
outSqr.addEventListener (MouseEvent.ROLL_OVER,sqrOver);
outSqr.addEventListener (MouseEvent.ROLL_OUT,sqrOut);

function sqrOver(e:MouseEvent) {
    inSqr.visible = true;
}

function sqrOut (e:MouseEvent) {
    inSqr.visible = false;
}

Однако с этим кодом - всякий раз, когда вы перемещаете курсор мыши в пределах желтого квадрата - он, очевидно, считается как ROLL_OUT для КРАСНОГО квадрата - таким образом, запускается функция sqrOut - исчезает желтый квадрат, и как только желтый квадрат его нет - курсор снова внезапно оказывается в границах КРАСНОГО квадрата - поэтому вызывается функция sqrOver - возвращая видимость желтого квадрата - запускает sqrOut и так далее, и так далее, создавая таким образом "мерцающий" желтый квадрат, когда курсор мыши находится над ним: желтый квадрат исчезает и появляется снова и снова снова и снова.

Возможное "исправление" для этого состоит в том, чтобы удалить слушателя для события разворачивания красного цвета, когда курсор находится внутри желтого (если он находится внутри желтого, он также обязательно находится внутри красного), и вернуть его, когда он отсутствует, добавив это в код выше:

 inSqr.addEventListener (MouseEvent.ROLL_OVER,insqrOver);
 inSqr.addEventListener (MouseEvent.ROLL_OUT,insqrOut);
 function insqrOver(e:MouseEvent) {
     if (outSqr.hasEventListener (MouseEvent.ROLL_OUT)) {
         outSqr.removeEventListener(MouseEvent.ROLL_OUT,sqrOut);
     }
     inSqr.visible = true;
 }
 function insqrOut(e:MouseEvent) {
     if (!outSqr.hasEventListener (MouseEvent.ROLL_OUT)) {
         outSqr.addEventListener(MouseEvent.ROLL_OUT,sqrOut);
     }
 }

Это работает. Но это громоздко. Вы должны сделать это для каждого объекта внутри границ красного квадрата, что приводит к длинному коду и множеству слушателей событий, а также к непрерывной регистрации и отмене регистрации слушателей.


Несколько лет назад кто-то предложил мне эту технику:

 outSqr.addEventListener (Event.ENTER_FRAME,hoverCheck);

 function hoverCheck (e:Event) {
     if (e.currentTarget.hitTestPoint(stage.mouseX,stage.mouseY,true)) {
         inSqr.visible = true;
     }
     else {
         inSqr.visible = false;
     }
 }

Это простой короткий код, который работает. Но если вашему проекту на самом деле не нужно использовать событие ENTER_FRAME, это создает ненужные накладные расходы и циклы ЦП повторного запуска теста на попадание. Кроме того, если красный квадрат покрывает всю сцену (имеет те же размеры, что и сцена) - это создает проблемы (это не работает).


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

3 ответа

Решение

Поместите желтый квадрат внутри красного квадрата.

outSqr.addChild(inSqr);

Это решит ваши проблемы красиво и просто. Просто убедитесь, что outSqr является экземпляром Sprite или же MovieClip учебный класс.

Я не знаю, поможет ли это в вашем случае, но вы также можете отключить действия мыши в inSqr, тогда вы можете навести курсор на желтый квадрат, который не вызывает ROLL_OUT

inSqr.mouseEnabled = false

..то вы можете просто использовать это:

inSqr.visible = false;
outSqr.addEventListener (MouseEvent.ROLL_OVER,sqrOver);
outSqr.addEventListener (MouseEvent.ROLL_OUT,sqrOut);

function sqrOver(e:MouseEvent) {
    inSqr.visible = true;
}

function sqrOut (e:MouseEvent) {
    inSqr.visible = false;
}

самое простое решение, которое я могу себе представить:

package {
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    public class FlashTest extends Sprite {
        private var inner:Sprite;
        private var outer:Sprite;
        public function FlashTest() {
            outer = giveRect(200, 200, 0xff0000);
            addChild(outer);
            inner = giveRect(50, 50, 0xffff00);
            addChild(inner);
            inner.x = inner.y = 75;
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);       
        }

        private function giveRect(w:int, h:int, color:int):Sprite{
            var spr:Sprite =  new Sprite();
            spr.graphics.beginFill(color);
            spr.graphics.drawRect(0, 0, w, h);
            spr.graphics.endFill();
            return spr;            
        }

        private function onMove(e:MouseEvent):void{
            inner.visible = stage.mouseX > outer.x &&
                            stage.mouseX < outer.x + outer.width &&
                            stage.mouseY > outer.y &&
                            stage.mouseY < outer.y + outer.height;
        }
    }
}
Другие вопросы по тегам