Каков предпочтительный способ обнаружения переворачивания / разворачивания мыши во Flash с AS3
Предположим, у нас есть сцена с двумя квадратами, вот так:
Предположим, что мы хотим, чтобы желтый квадрат был изначально скрыт, и нам бы хотелось, чтобы курсор мыши находился внутри границ красного квадрата - желтый квадрат был виден и до тех пор, пока курсор мыши отсутствует из границ красного квадрата - что желтый квадрат будет скрыт.
Интуитивный подход - написать что-то вроде этого:
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;
}
}
}