Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   [Алгоритмы] Как это - MOUSE_OUT сработал, а hitTestPoint возвращает true (http://www.flasher.ru/forum/showthread.php?t=211973)

Bred45 18.12.2015 14:55

Как это - MOUSE_OUT сработал, а hitTestPoint возвращает true
 
Вот упрощенный вариант.
На сцене клип mc с двумя кадрами.
По MOUSE_OVER и MOUSE_OUT - прыгает с кадра на кадр.
При перетаскивании - мышь слетает с клипа и он "моргает".
Чтобы этого избежать - отключаю слушатели на время таскания.
При MOUSE_UP возвращаю их на место, но нужно перевести клип в нужный кадр.
И тут использую hitTestPoint, чтобы проверить, над клипом мышь или нет.
Если нет - прыгаю на первый кадр.

Так вот: если резко потащить клип и бросить его - можно отловить ситуацию, когда hitTestPoint вернет true и клип не сбросится в деактивированное состояние. По идее, если MOUSE_UP сработало над клипом, должен был включиться обработчик MOUSE_OUT и сбросить клип, но trace показывает, что событие уже произошло ДО этого.

Минималистический пример:
Код AS3:

import flash.events.MouseEvent;
import flash.geom.Point;
 
var dltY:Number;
 
mc.buttonMode = true;
 
mc.addEventListener(MouseEvent.MOUSE_OVER, mOver);
mc.addEventListener(MouseEvent.MOUSE_OUT, mOut);
 
mc.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
 
 
function mOver(e:MouseEvent){
        mc.gotoAndStop(2);
}
 
function mOut(e:MouseEvent){
        mc.gotoAndStop(1);
}
 
function mDown(e:MouseEvent){
        mc.removeEventListener(MouseEvent.MOUSE_OVER, mOver);
        mc.removeEventListener(MouseEvent.MOUSE_OUT, mOut);
 
        stage.addEventListener(MouseEvent.MOUSE_MOVE, mMove);
        stage.addEventListener(MouseEvent.MOUSE_UP, mUp);
 
        dltY = mouseY - mc.y;
}
 
function mMove(e:MouseEvent){
        mc.y = mouseY - dltY;
        e.updateAfterEvent();
}
 
function mUp(e:MouseEvent){
        mc.addEventListener(MouseEvent.MOUSE_OVER, mOver);
        mc.addEventListener(MouseEvent.MOUSE_OUT, mOut);
 
        stage.removeEventListener(MouseEvent.MOUSE_MOVE, mMove);
        stage.removeEventListener(MouseEvent.MOUSE_UP, mUp);
        checkHit();
}
 
function checkHit(){
 
        if(!mc.hitTestPoint(stage.mouseX, stage.mouseY)){
                mc.gotoAndStop(1);
        }
}


samana 18.12.2015 16:31

Думаю не нужен здесь hitPoint. Просто контролируйте момент драга. Что-то вроде этого:
Код AS3:

import flash.events.MouseEvent;
 
mc.stop();
var _isDrag=false;
 
// DRAG
mc.addEventListener(MouseEvent.MOUSE_DOWN, mcMouseDown)
 
function  mcMouseDown(e:MouseEvent):void
{
        stage.addEventListener(MouseEvent.MOUSE_MOVE, stageMouseMove);
        stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
        _isDrag=true;
}
 
function stageMouseUp(e:MouseEvent):void
{
        stage.removeEventListener(MouseEvent.MOUSE_MOVE, stageMouseMove);
        stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUp);
        _isDrag=false;
}
 
function stageMouseMove(e:MouseEvent):void
{
        mc.x=stage.mouseX;
        mc.y=stage.mouseY;
}
 
//OVER OUT
mc.addEventListener(MouseEvent.ROLL_OVER, mcRollOver);
mc.addEventListener(MouseEvent.ROLL_OUT, mcRollOut);
 
function mcRollOver(e:MouseEvent):void
{
        mc.gotoAndStop(2);
}
 
function mcRollOut(e:MouseEvent):void
{
        if(!_isDrag) mc.gotoAndStop(1);
}


Bred45 18.12.2015 17:04

Спасибо. Ваш пример вообще не сбрасывает клип на 1-ый кадр при отпускании мыши в случае привязки клипа не по центру. А если по центру - то все равно глюк отлавливает при резком переносе.

Не знаю, как сюда ссылку на видео добавить... видимо, нельзя.

Рискну. Там всего 300 килобайт.
https://yadi . sk/i/S3tqcPe3mKSX9

faraday 18.12.2015 23:07

флеш так же слушает мув, и так же выполняет hitTest для того чтобы диспатчить over и out. и делает он это раньше вашего слушателя move. то есть если мышка переместилась за такт больше чем размер объекта и вышла за его пределы. флеш диспатчит аут, перед тем как ваш мув должен его сдвинуть. но пример все равно не понятный, если использовать startDrag проблемы нет? еще попробуйте в move смотреть координаты передаваемые с событием. может оно не успевает всплыть и обновить mouseX стейджа

Bred45 19.12.2015 17:19

Про startDrag не скажу, мне он не подходит.
Ну, вот давайте упростим до минимума:

Код AS3:

import flash.events.MouseEvent;
 
mc.stop();
mc.addEventListener(MouseEvent.ROLL_OUT, mcRollOut);
function mcRollOut(e:MouseEvent):void
{
        trace("mcRollOut", e.stageX, e.stageY)
        if(mc.hitTestPoint(e.stageX, e.stageY)){
                trace("внутри", e.stageX, e.stageY)
        }
}

Все тот две двухкадровый клип с привязкой по центру размером 100х100 лежит в точке (200,200);
Вопрос - будет ли выполняться traсe?
Ответ - да, при медленном движении мыши.
Вот вывод при движении мыши вниз.
Код:

mcRollOut 209 250
внутри 209 250

А вот при движении вверх:
Код:

mcRollOut 194 149
mcRollOut 191 147
mcRollOut 185 148

149 - это максимальная величина (и для меня это ожидаемо).
По координате х - ситуация похожая.

Почему срабатывает mcRollOut в точке 228 250, если эта точка все еще принадлежит прямоугольнику?

Wolsh 19.12.2015 23:33

Как 250 принадлежит прямоугольнику, если он размером 100 с привязкой по центру в координате 200?
Первый пиксель то это не "1", а "0". Соответственно 100-й пиксель прямоугольника имеет stage-координату 249.
Подумайте об этом так: если бы Вы захотели прямо вплотную к этому прямоугольнику расположить второй прямоугольник - какую координату Вы ему зададите, 250 или 251?
Ответ - 250. И это уже НЕ принадлежит первому.

Bred45 20.12.2015 20:44

Wolsh, спасибо, я предполагал это. Но почему тогда срабатывает hitTestPoint?

Мне hitTestPoint нужен, потому что у меня движение ограничено, скажем, по y, как в моем первом примере.
Т.е. мышь при отпускании кнопки слетит с клипа с большой долей вероятности. Можно событие CLICK подключить (и по нему активировать кнопку принудительно), но это не решает проблему полностью. Как вообще избежать этого глюка? Дайте идею, пожалуйста.

Wolsh 21.12.2015 00:27

Ну, вообще, первое что приходит в голову это использовать MOUSE_UP от клипа, а не от стейджа.
А чтобы ловить отпускание мыши вне клипа, подписаться на RELEASE_OUTSIDE опять же от клипа.
Но я не гарантирую, что это защитит "от шумахера", надо протестировать.

Добавлено через 8 минут
Использование хиттеста вообще не должно приходить в голову, особенно при быстром движении, так как код исполняется ДО отрисовки и будет глючить по определению. Попросту говоря, хиттест проверяет совпадение с объектом, отрисованным в прошлом кадре.

Добавлено через 15 минут
Еще один вариант - разобраться с последовательностью событий. Например, при ROLL_OUT можно проверять свойство MouseEvent#button - нажата ли кнопка, или отпущена.

Bred45 21.12.2015 10:37

Wolsh, большое спасибо за идеи, буду пробовать.

RELEASE_OUTSIDE спас ситуацию. Я тестировал в CS6, где плеер ограничивается версией 11.2 и это событие было недоступно.
Во FD со свежей версией плеера все работает.
Wolsh, спасибо и за подсказку по хиттесту. Не знал, что он работает с отрисовкой.

Добавлено через 2 часа 4 минуты
Кажется, я поторопился радоваться. В проекте глюк повторился. Трейсы показывают, что MOUSE_UP, сработал после ROLL_OUT, хотя оба события привязаны к клипу, что я понять уже никак не могу.

Попробую Ваш второй вариант...

Добавлено через 2 часа 39 минут
Второй вариант с событием e.buttonDown, кажется, сработал! По крайней мере, отловить не удается.


Часовой пояс GMT +4, время: 21:33.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.