【问题标题】:How to check if mouse is over a MovieClip?如何检查鼠标是否在 MovieClip 上?
【发布时间】:2012-08-26 19:30:21
【问题描述】:

不涉及侦听器。问题是,我可以使用 MOUSE_OVERMOUSE_OUT 侦听器,但是如果您将鼠标快速拖到 MovieClip 上够了,这些监听器之一可能没有被激活。我试了好几次了。

【问题讨论】:

  • 正如一些评论者所指出的,最佳解决方案(性能、简单性、准确性等)直接取决于您正在处理的对象类型及其行为:它们的形状是否不规则?你能把形状近似成圆形或矩形吗?它们的形状会改变吗?如何?您的形状数量是否有限/减少?...它们在移动吗?彼此独立?它们是否以某种方式重叠?等等等等……
  • 每个对象有单独的监听器吗?

标签: actionscript-3 mouseover movieclip


【解决方案1】:

mouseOver 和 mouseOut 我从来没有遇到过问题。

但你可以使用 hitTestPoint:

function detectMouseOver(d:DisplayObject):Boolean
{
    var mousePoint:Point = d.localToGlobal(new Point(d.mouseX,d.mouseY));
    return d.hitTestPoint(mousePoint.x,mousePoint.y,true);
}

如果您确定该属性可用并从您调用的位置设置,您也可以使用 stage.mouseX 和 stage.mouseY(而不是 localToGlobal)。

我没有测试过代码,但我认为它应该可以工作。

(编辑)

但是,如果您想绝对确定鼠标是否经过了某个对象 - 即使您走得如此之快以至于完全跳过它,您也必须检查两帧鼠标点之间的点。

这样就可以了,例如:

d.addEventListener(Event.ENTER_FRAME, checkMouseOver);

var lastPoint:Point;
const MAX_DIST:Number = 10;

function checkMouseOver(e:Event):void
{
    var isOver:Boolean = false;

    var d:DisplayObject = e.currentTarget as DisplayObject;
    var thisPoint:Point = d.localToGlobal(new Point(d.mouseX,d.mouseY))

    if (lastPoint)
    while (Point.distance(thisPoint,lastPoint) > MAX_DIST)
    {
        var diff:Point = thisPoint.subtract(lastPoint);
        diff.normalize(MAX_DIST);
        lastPoint = lastPoint.add(diff);

        if (d.hitTestPoint(lastPoint.x,lastPoint.y,true))
        {
            isOver = true;
            break;
        }
    }
    if (d.hitTestPoint(thisPoint.x,thisPoint.y,true))
    isOver = true;

    lastPoint = thisPoint;

    //do whatever you want with isOver here
}

您可以记住最后一个状态是否结束,并在 isOver != wasOver 时发送自定义事件。如果您在 while 循环中执行此操作,您将获得高度准确的鼠标悬停检测。

但我敢打赌,shapeFlag = true 的 hitTestPoint 会占用大量 CPU,尤其是在一帧中大量使用的情况下。因此,在这种情况下,您可能希望将此 MAX_DIST 设置得尽可能高。

【讨论】:

  • 或者是的,hitTest 点是我没想到的另一种方式。 :)
  • 优点是像素检测,如果你需要的话。最佳解决方案实际上取决于此检测应该用于/开启什么。
【解决方案2】:

那就用数学吧。

if(mouseX>mc.x-(mc.width/2) && mouseX<mc.x+(mc.width/2) && mouseY>mc.y-(mc.height/2) && mouseY<mc.y+(mc.height/2)){
     hovered = true;
     //do stuff..
}else{
     if(hovered){
           hovered=false;
           //do rollout stuff..
     }
}

请注意,它取决于影片剪辑的注册点...在这种情况下,注册点位于影片剪辑的中间。

另一种方法是hitTestObject() 内置函数shapeFlag = true;

【讨论】:

  • 这仅在形状为矩形时有效。另外,您能更具体地了解一下这个hitTestObject() 函数吗?
【解决方案3】:

如果鼠标“足够快”地经过,那么操作系统可能一开始就没有为屏幕的那部分发送任何鼠标事件到 Flash。移动鼠标的速度快于其分辨率可以触发(或操作系统可以处理)将产生您所见证的效果(事实是,屏幕的该部分没有处理任何鼠标事件),否则 MOUSE_OVER 肯定会触发(如果鼠标确实在影片剪辑上产生了至少一个移动事件)。

但是,由于各种操作系统或浏览器的安全限制,如果鼠标离开舞台区域(离开 Flash),可能不会触发 MOUSE_OUT 事件。

要解决此问题,请为 stage::flash.events.Event.DEACTIVATEstage::flash.events.Event.MOUSE_LEAVE 注册侦听器,在每个 Sprite/MovieClip 中您也正在侦听 MOUSE_OUT,重复使用相同的处理函数。

mouseLeave 事件(由舞台触发)是专门为您的问题创建的:“当指针移出舞台区域时由舞台对象调度。如果按下鼠标按钮,则不会调度该事件。”如果它触发,你应该像 MOUSE_OUT 一样处理任何处于 MOUSE_OVER “状态”的影片剪辑(假设你有这样的状态)。如果鼠标按钮在离开舞台区域时被按下,用户可能会在某个时候释放它,而 DEACTIVATE 将在舞台上触发。

【讨论】:

    【解决方案4】:

    您还可以监听舞台鼠标移动并检查鼠标下的剪辑:

    stage.addEventListener(MouseEvent.MOUSE_MOVE , onMouseMove);
    function onMouseMove(e:MouseEvent):void {
        trace(stage.getObjectsUnderPoint(new Point(e.stageX , e.stageY)));
    }
    

    并检查您的 MovieClip 是否在数组中。

    【讨论】:

      猜你喜欢
      • 2011-05-28
      • 1970-01-01
      • 2016-03-26
      • 2016-07-22
      • 1970-01-01
      • 2014-09-20
      • 2010-11-19
      • 1970-01-01
      相关资源
      最近更新 更多