Переслать MouseEvent в прозрачном растровом изображении в базовый MovieClip - PullRequest
0 голосов
/ 24 марта 2011

Так что я расточаю некоторые тяжелые вещи, чтобы попытаться снизить [pre-render] и [render], что довольно высоко согласно профилированию FlashBuilder.Я думал , что все шло хорошо, пока я не понял, что как только вы меняете MovieClip на растровое изображение, вы теряете основанную на пикселях точность событий перемещения мыши (Over, Out, Move ...), всеслева от вас находится вся ограничивающая рамка растрового изображения, что является нежелательным.У меня есть игра, в которой многие растровые изображения будут располагаться друг над другом на сцене, на сцене, располагаться по-разному, и мне нужно, чтобы пиксельная точность перемещалась между каждым, и мои усилия были исчерпаны, как достичьто же самое движение мыши приводит к ребятам с растровым изображением как обычно.

Это, http://seadersforums.appspot.com/static/bitmaps.fla, FLA, который показывает эту операцию, и вы можете увидеть, как она работает здесь, http://seadersforums.appspot.com/static/bitmaps.html,Когда он загружается, оба элемента на сцене рисуются фигурами, инкапсулированными в мувиклипы, которые светятся, если вы наводите курсор на них.Если вы щелкнете по сцене вообще, фиолетовый парень превратится в растровое изображение, и теперь его «область попадания», когда дело доходит до MouseEvents, - это его ограничивающий прямоугольник, и вы можете получить доступ только к зеленому элементу сзади на краях ленты.

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

Ниже показано, как он теперь работает для меня:

        var bitmap:Bitmap = this['bitmap'];
        var shouldMouseOver:Boolean = bitmap.bitmapData.getPixel(event.localX - bitmap.x, event.localY - bitmap.y);
        if(shouldMouseOver)
        {
            this.mouseOver();
        }
        else {
            this.mouseEnabled = false;
            var point:Point = new Point(event.stageX, event.stageY);
            for each(var other:DisplayObject in _topContainer.getObjectsUnderPoint(_topContainer.globalToLocal(point)))
            {
                if(other.mouseEnabled)
                {
                    point = other.globalToLocal(point);
                    other.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_MOVE, false, false, point.x, point.y));
                    break;
                }
            }
            this.mouseEnabled = true;
        }

Я отключаю mouseEnabled для своего предмета, когда я знаю, что это неправильно, тогда я ищудругой предмет, который соответствует требованиям, и если таковой имеется, отправьте событие на него и прервитесь.Если этот человек тоже не прав, он будет делать то же самое снова, но каждый раз вынимая себя из цикла.

Это работает именно так, как я хочу, но я всегда предпочел бы сохранить такие вещи, какglobalToLocal и looping, а также чтение из массивов для не часто обновляемых методов, таких как слушатели MOUSE_MOVE.Есть ли более эффективный способ сделать это?

Ответы [ 2 ]

0 голосов
/ 24 марта 2011

Я использую трюк, который я где-то нашел в сети, но больше не могу найти. В основном это так:

  • положить растровое изображение в Sprite.
  • Создайте обработчик EnterFrame для этого спрайта, который проверяет пиксель, который находится под курсор каждый раз.
  • Используйте getPixel32(), чтобы найти цвет и альфа этого пикселя.
  • Когда альфа-компонент цвета ниже определенного порога, вы устанавливаете спрайт mouseEnabled в false (и в противном случае правда).

Таким образом, вы можете щелкнуть растровое изображение только в том случае, если вы наведете на непрозрачные части изображения. MouseEvents будет происходить на объектах ниже растрового изображения, если оно не mouseEnabled.

0 голосов
/ 24 марта 2011

В верхней части моей головы вы можете использовать метод getObjectsUnderPoint.Любой типизированный экранный объект имеет этот метод.Метод принимает аргумент типа Point, где вы можете передать координаты мыши.Я полагаю, что метод возвращает массив объектов ниже этой точки, которые содержатся в DisplayObject, для которого вы вызвали метод getObjectsUnderPoint.Например, если ваши видеоклипы вложены в родительский клип с именем Container, вы можете сделать что-то вроде этого:

var pt:Point = new Point(10, 20);
var objects:Array = container.getObjectsUnderPoint(pt);

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

var i:int = 0;
var topContainer:DisplayObject;
var lastIndex:int = 0;
for(i; i < objects.length; ++i){
   if(topContainer:DisplayObject){
       if(container.getChildIndex(DisplayObject(objects[i])) < lastIndex){
            lastIndex = container.getChildIndex(DisplayObject(objects[i]));
       }
   }else{
       topContainer = DisplayObject(objects[i]);
       lastIndex = container.getChildIndex(DisplayObject(objects[i]));
   }   
}

Итак, в основном я делаю здесь сортировку по всем результатам и выбираю тот, у которого самый низкий дочерний индекс, дов идеале получить следующий ребенок ближе к поверхности.Прошло много времени с тех пор, как я увлекся флэш-памятью, поэтому я не уверен на 100%, работает ли список отображения таким образом с точки зрения дочернего индекса, то есть, если у более близких объектов значение индекса ниже или выше.Другими словами, весьма вероятно, что дочерний элемент с индексом, если 0, может быть дочерним элементом в нижней части списка.Вам придется попробовать и просто настроить приведенный выше код, если это так.В любом случае, как только эта функция запустится (кстати, она не проверена, так что, может быть, это типа и тому подобное, но концепция должна работать), тогда у вас будет клип, к которому вы действительно хотите обратиться, на который ссылается topContainer.Отсюда вы можете отправить mouseEvent в этот контейнер.

topContainer.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN, false, false, MOUSE_POSITION_X, MOUSE_POSITION_Y));

Теперь это то, что вы будете делать, если внутри topContainer есть слушатель, ожидающий получения своего собственного события мыши.То есть имеется прослушиватель событий, непосредственно подключенный к объекту topContainer, например:

topContainer.addEventListener(MouseEvent.MOUSE_DOWN, onMouse);

или внутри класса topContainer:

this.addEventListener(MouseEvent.MOUSE_DOWN, onMouse);

Причина в том, что мы отправляемсобытие непосредственно на ссылку topContainer без цели события и с отключенным всплывающим событием.

Если, с другой стороны, ваша модель использует один обработчик MouseEvent на уровне этапа или каком-либо другом уровне, а ваш обработчик onMouse имеетоператор switch для выполнения определенных действий в зависимости от цели события, например:

function onMouse(e:MouseEvent):void
{
   switch(e.currentTarget){
      case MyMovieClip1:
          //Do Something
      break;

      case MyMovieClip2:
          //Do Something
      break;
   }
}

Затем вам нужно будет отправить это событие в несколько ином поместье.Вам нужно будет включить ссылку на объект topContainer, а также включить всплывающее окно события:

someRelativeClip.dispatchEvent(new MouseEvent(MouseEvent.MOUSE_DOWN, true, false, MOUSE_POSITION_X, MOUSE_POSITION_Y, topContainer));

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

...