PDA

Просмотр полной версии : Алгоритмы Как это - MOUSE_OUT сработал, а hitTestPoint возвращает true


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

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

Минималистический пример:

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. Просто контролируйте момент драга. Что-то вроде этого:
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 не скажу, мне он не подходит.
Ну, вот давайте упростим до минимума:


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, кажется, сработал! По крайней мере, отловить не удается.