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

发布于 2024-10-26 05:45:41 字数 1889 浏览 0 评论 0原文

因此,我对一些繁重的内容进行位图处理,以尝试降低 [预渲染] 和 [渲染],根据 FlashBuilder 的分析,这两个参数相当高。我认为进展顺利,直到我意识到一旦将 MovieClip 更改为位图,您就会失去鼠标移动事件(Over、Out、Move...)的基于像素的准确性,剩下的就是位图的整个边界框,这是不太理想的。我有一款游戏,其中许多位图资源在场景中、舞台上彼此重叠,以各种方式排列,并且需要在每个资源之间移动像素精度,并且已经耗尽了我的努力来实现如何实现与正常情况一样,位图家伙的鼠标移动结果相同。

http://seadersforums.appspot.com/static/bitmaps.fla 是显示此操作的 FLA,您可以在此处查看其工作原理,http://seadersforums.appspot .com/static/bitmaps.html 。当它加载时,舞台上的两个项目都被绘制为形状,封装在影片剪辑中,如果将鼠标悬停在它们上方,它们都会发光。如果你点击舞台,紫色的家伙就会变成位图,现在,当涉及到 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 的侦听器。有没有更有效的方法来做到这一点?

So I'm Bitmaping some heavy stuff to try bring down the [pre-render] and [render] which is quite high according to FlashBuilder's profiling. I thought this was going well until I realised that as soon as you change a MovieClip to a Bitmap, you lose the pixel based accuracy of the mouse move events (Over, Out, Move...), all your left with is the entire bounding box of the Bitmap, something which is less than desirable. I've got a game where many Bitmapped assets would be on top of each other in a scene, on the stage, arranged in various ways and need to have that pixel accuracy moving between each one and have exhausted my efforts as to how to achieve the same mouse move results with the Bitmapped guys as normal.

This, http://seadersforums.appspot.com/static/bitmaps.fla , is a FLA which shows this operation, and you can see how it works here, http://seadersforums.appspot.com/static/bitmaps.html . When it loads up, both items on stage are drawn Shapes, encapsulated in MovieClips, both that get a glow, if you hover over them. If you click the stage at all, the purple guy gets turned into a Bitmap and now, his 'hit area', when it comes to MouseEvents is his whole bounding box and you can only get through to the back green item at the edge slivers.

I'm also tracing the pixel which the mouse is over, so I can clearly tell when the mouse is over a transparent area, it's 0, but how can I tell the event to forward itself on down the chain to the green MovieClip?

Below is how it's now pretty much working for me,

        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;
        }

I shut off mouseEnabled for my item, when I know it's wrong, then I search for another item that properly fits the bill and if there is one, send an Event to that and break. If that one's also wrong, it'll do the same again, but each time taking themselves out of the loop.

This does work exactly how I want it to, but I'd always prefer to keep things like globalToLocal and looping, and reading from arrays for not frequently updated methods like listeners to MOUSE_MOVE. Is there a more efficient way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

镜花水月 2024-11-02 05:45:41

在我的脑海中,您可以使用 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));

希望这有助于让我知道您是否需要任何说明。

Off the top of my head you could use the getObjectsUnderPoint method. Any display object typed class has this method. The method takes an argument of type Point, where you can pass the mouse coordinates. I believe the method returns an array of objects beneath that point, that are contained within the DisplayObject that you called the getObjectsUnderPoint method on. For example if these movieclips of yours are nested within a parent clip called Container, then you could do something like this:

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

Then for your specific scenario I'd sort the returned objects by depth to get the next one in the list (the one beneath, or whatever one I want).

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]));
   }   
}

So basically what I'm doing here is sorting through all the results and picking the one with the lowest child index to ideally get the next child closest to the surface. It's been a while since I've been into flash so I'm not 100% sure if the display list works that way in terms of child index, that is, if closer objects have a lower index value or higher. In other words, it is highly possible that a child with an index if 0 could be the child at the bottom of the list. You'll have to give it a try and just adjust the above code if that is the case. Anyway once that function runs (it's un-tested by the way, so might be type-o's and things of this nature but the concept should work) then you will have the clip you really want to access referenced by topContainer. From here you can dispatch a mouseEvent to that container.

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

Now this is what you would do if you have a listener inside of the topContainer waiting to receive it's own mouse event. That is, there is an event listener directly attached to the topContainer object as so:

topContainer.addEventListener(MouseEvent.MOUSE_DOWN, onMouse);

or, inside the topContainer class:

this.addEventListener(MouseEvent.MOUSE_DOWN, onMouse);

The reason being that we are dispatching the event directly to the topContainer reference with no event target, and with event bubbling turned off.

If on the other hand your model involves a single MouseEvent handler at the stage level or some other level, and your onMouse handler has a switch statement to do certain actions depending on the event target as so:

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

      case MyMovieClip2:
          //Do Something
      break;
   }
}

Then you're going to need to dispatch that event in a slightly different manor. You'll need to include a reference to the topContainer object as well as enable event bubbling:

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

Hope this helps let me know if you need any clarification.

似最初 2024-11-02 05:45:41

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

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

这样,如果您将鼠标悬停在图像的不透明部分上,则只能单击位图。如果未启用鼠标,则鼠标事件将发生在位图下方的对象上。

I use a trick that I found on the net somewhere but can't find anymore. Basically it's like this:

  • put the bitmap in a Sprite.
  • Make an EnterFrame handler on that sprite that
    checks the pixel that is under the
    cursor every time.
  • Use getPixel32() to find the color
    and the alpha of that pixel.
  • When the alpha component of the color
    is under a certain threshold, you set the sprite's
    mouseEnabled to false (and otherwise
    true).

This way, you can only click the bitmap if you roll over parts of the image that are non-transparent. MouseEvents will occur on objects below the bitmap if it's not mouseEnabled.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文