4

给定舞台坐标 (x,y),我想让我的 flash 应用程序的行为就像用户在位置 (x,y) 上单击一样。也就是说,像

function simulateClick(x:Number, y:Number):void{
    var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, x, y)
    stage.dispatchEvent(e);
}

我发现很多页面都在谈论这种事情,它们都给出了与上述类似的解决方案。但是,这并不等同于用户点击 (x,y)。有两个问题:

首先是e.stageX和e.stageY都是0,我不能直接设置。文档说它们是在设置 e.localX 和 e.localY 时计算的,但是当我在 dispatchEvent 之前设置 e.localX 时不会发生这种情况,也不会在事件侦听器中发生这种情况。

我可以用这样的东西重写我所有的事件监听器:

var p:Point = e.target.localToGlobal(new Point(e.localX, e.localY));

这是唯一的选择吗?

第二个问题是我的事件侦听器注册了舞台的孩子,而不是舞台本身。所以我需要找出调用 dispatchEvent 的目标。显然,Flash 能够确定目标应该是什么,即哪个对象拥有在位置 (x,y) 处可见的最高像素,因为它在用户实际点击时这样做。有没有一种简单的方法来获取这些信息,或者我应该编写自己的递归函数来做同样的事情?我目前正在使用 DisplayObjectContainer.getObjectsUnderPoint,但它并不完全正确。

我在 FlashDevelop 中写作,如果这有什么不同的话。

4

3 回答 3

1

e.stageX/Y为我正确填充...getObjectsUnderPoint()似乎也可以正常工作。我假设传递给的 x/y 值simulateClick是全局坐标?

编辑:正如评论中所指出的,必须在 InteractiveObject 实例上调度鼠标事件......相应地修改了代码。

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;

public function simulateClick(x:Number, y:Number):void
{
    var objects:Array = stage.getObjectsUnderPoint(new Point(x, y));

    var target:DisplayObject;
    while(target = objects.pop())
    {
        if(target is InteractiveObject)
        {
            break;
        }
    }

    if(target !== null)
    {
        var local:Point = target.globalToLocal(new Point(x, y));

        var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, false, local.x, local.y);
        target.dispatchEvent(e);
    }
}

public function addedToStage():void
{
    var parent:Sprite = new Sprite();
    stage.addChild(parent);

    var child:Sprite = new Sprite();
    child.name = 'child 1';
    child.graphics.beginFill(0xff0000, 1);
    child.graphics.drawRect(0, 0, 200, 200);
    child.graphics.endFill();

    var child2:Sprite = new Sprite();
    child2.name = 'child 2';
    child2.graphics.beginFill(0xff00ff, 1);
    child2.graphics.drawRect(0, 0, 100, 100);
    child2.graphics.endFill();
    child2.x = 150;
    child2.y = 150;

    var bmpData:BitmapData = new BitmapData(80, 80, false, 0x00ff00);
    var bmp:Bitmap = new Bitmap(bmpData);
    bmp.name = 'bitmap';

    child2.addChild(bmp);

    parent.addChild(child);
    parent.addChild(child2);

    child2.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void
    {
        trace('target: ' + e.target.name);
        trace('localX: ' + e.localX);
        trace('localY: ' + e.localY);
        trace('stageX: ' + e.stageX);
        trace('stageY: ' + e.stageY);
    });

    simulateClick(190, 190);
}

输出:

target: child 2
localX: 40
localY: 40
stageX: 190
stageY: 190
于 2012-10-02T00:18:30.677 回答
0

对于问题 1:创建 MouseEvent(为其分配本地 x,y)后,您应该能够直接引用 e.stageX 并将其设置为您想要的,然后再调度事件。它只是 MouseEvent 实例的一个属性。对于#2,currentTarget 始终是鼠标下方最上面的东西,而 target 是发送事件的东西——假设事件是真正由鼠标交互发送的。在您的情况下,您可以将目标设置为您调度事件的任何对象,并任意设置 currentTarget。真正的问题是,这是否是目前处理鼠标下方内容的最有效方法?答案是,可能不是。最好使用 MOUSE_OVER 事件来密切关注鼠标现在所在的位置,将它存储为一个变量,当您想调用它时可以使用它,并且不要尝试一直迭代整个显示链(因为 Flash 本身的执行速度比您在循环中执行的速度要快得多)。如果您将 mouseOver 放在舞台上,并且只检查 currentTarget,那么您将在它更改的每一帧上获得鼠标下最上面的项目。

您应该知道(为了防止一些明显的讨厌的脚本),某些动作不能由动作脚本动态生成的鼠标事件触发。其中包括打开文件引用和全屏显示。

于 2012-10-02T00:16:01.077 回答
0

我也遇到过这个问题,有点头疼。在我的情况下,我正在创建事件,执行一些复杂的计算,但即使我已经设置了局部坐标,我也无法检索全局坐标。

实际上,在我的情况下,解决方案非常明显...... 只有在事件被调度之后才会填充全局坐标,否则事件如何知道如何将本地转换为全局?

这是另一个陷阱,除了不检查用于调度事件的对象是否为 InteractiveObject 之外

我发布这个是因为其他人可能会因为这两个陷阱而面临这个问题。一个简单易读的快速答案。

于 2015-10-30T18:54:33.107 回答