将透明位图中的MouseEvent转发到底层MovieClip

时间:2011-03-24 08:40:52

标签: flash actionscript-3 bitmap

因此,根据FlashBuilder的分析,我正在尝试使用一些重要的东西来尝试降低[预渲染]和[渲染]。我想到这种情况一直顺利,直到我意识到只要将MovieClip更改为Bitmap,就会失去鼠标移动事件(Over,Out,Move ...)的基于像素的精确度,你剩下的就是Bitmap的整个边界框,这是不太理想的。我有一个游戏,其中许多Bitmapped资产将在场景中,在舞台上,以各种方式排列,并且需要在每个之间移动像素精度并且已经用尽我的努力以实现如何实现同样的鼠标移动结果与Bitmapped人一样正常。

这个http://seadersforums.appspot.com/static/bitmaps.fla是一个显示此操作的FLA,您可以在此处查看它的工作原理http://seadersforums.appspot.com/static/bitmaps.html。当它加载时,舞台上的两个项目都被绘制为Shapes,封装在MovieClip中,如果将鼠标悬停在它们上面,它们都会发光。如果你完全点击舞台,紫色的家伙会变成一个位图,现在,他的“命中区域”,当涉及到MouseEvents时,他的整个边界框就是你只能穿过边缘条纹的背面绿色项目

我也在跟踪鼠标所在的像素,所以我可以清楚地看出鼠标何时在透明区域上方,它是0,但我怎么能告诉事件将自己从链上转发到绿色的MovieClip?

以下是它现在对我有用的方式,

        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和循环之类的东西,并且从数组中读取不经常更新的方法,比如MOUSE_MOVE的监听器。有没有更有效的方法来做到这一点?

2 个答案:

答案 0 :(得分:0)

在我的脑海中,您可以使用getObjectsUnderPoint方法。任何显示对象类型类都有此方法。该方法采用Point类型的参数,您可以在其中传递鼠标坐标。我相信该方法返回该点下方的一个对象数组,这些对象包含在您调用getObjectsUnderPoint方法的DisplayObject中。例如,如果您的这些影片剪辑嵌套在名为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]));
   }   
}

所以基本上我在这里做的是整理所有结果并选择具有最低子索引的结果,以理想地让下一个孩子最接近表面。自从我进入flash以来已经有一段时间了,所以我不能100%确定显示列表是否按照子索引的方式工作,也就是说,如果更近的对象具有更低的索引值或更高。换句话说,索引为0的子项很可能是列表底部的子项。你必须尝试一下,如果是这样的话就调整上面的代码。无论如何,一旦该函数运行(它没有经过测试,因此可能是type-o和这种性质的东西,但概念应该有效)然后你将拥有你真正想要访问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));

希望如果您需要任何澄清,这有助于我了解。

答案 1 :(得分:0)

我使用了我在网上找到的技巧,但找不到了。基本上就是这样:

  • 将位图放在Sprite中。
  • 在该精灵上创建一个EnterFrame处理程序 检查下面的像素 光标每一次。
  • 使用getPixel32()查找颜色 和那个像素的alpha。
  • 当颜色的alpha分量 在某个阈值之下,你设置了精灵 mouseEnabled为false(否则为 真)。

这样,如果您滚动图像中不透明的部分,则只能单击位图。如果位图不是mouseEnabled,MouseEvents将出现在位图下面的对象上。

相关问题