1

私は AS3 プロジェクトに取り組んでおり、近い将来に多くのリファクタリングが必要になる特に壊れやすい部分に苦労しています。個別のクラスを個別に単体テストするだけでは、遭遇しているすべての問題を把握できるわけではありません。たとえば、透明なオーバーレイでマウス イベントを無効にするのを忘れて、ボタンのすべてのクリックをブロックすることがあります。したがって、実際のユーザー入力をシミュレートするテストを作成しようとしています。

MouseEvent をステージの正しい位置に手動で送信しようとしました。

stage.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, true, 380, 490, stage));

ステージにはクリック イベント ハンドラーがないため、イベントが階層を介して実際に処理するボタンに伝達されることを期待していました (マウスを物理的にクリックしたときと同様)。しかし、そうではありません。

ボタンでイベントをディスパッチできることはわかっていますが、オブジェクトが何らかの形で遮られているかどうかは検出されません。マウス イベントをシミュレートして、階層全体に適切に伝達する方法はありますか?

編集: Flashの伝播動作を再実装することで、なんとかそれを行うことができました:

編集 2: いくつかのシェイプを含むスプライトのように、クリック ハンドラーを含む部分的に透明なオーバーレイがある場合、以前のソリューションは機能しませんでした。問題は、問題のオブジェクトがその時点で完全に透過的であっても、hitTestPoint メソッドが true を返すことです。したがって、実際のピクセル値を確認するように変更しました。

private function clickObject(obj:DisplayObject) : void 
{
    var relPos:Point = new Point(obj.width / 2, obj.height / 2);
    var globalPos:Point = obj.localToGlobal(relPos);

    simulateClick(obj.stage, globalPos);
}

private function simulateClick(obj:InteractiveObject, globalPos:Point) : Boolean 
{
    // first, check if we have any children that would rather handle the event
    var container:DisplayObjectContainer = obj as DisplayObjectContainer;
    if (container != null) 
    {
        if (container.mouseChildren)
        {
            for (var i:int = 0; i < container.numChildren; ++i) 
            {
                var child:DisplayObject = container.getChildAt(i);
                var interactive:InteractiveObject = child as InteractiveObject;
                if (interactive != null) 
                {
                    if (simulateClick(interactive, globalPos)) 
                    {
                        // if we have found a handler in the children, we are done
                        return true;
                    }
                }
            }
        }
    }

    if (!obj.mouseEnabled) {
        return false;
    }

    if (obj.hitTestPoint(globalPos.x, globalPos.y)) 
    {
        var localPos:Point = obj.globalToLocal(globalPos);

        // check if object is visible at the clicked location
        var pixel:BitmapData = new BitmapData(1, 1);
        pixel.draw(obj, new Matrix(1, 0, 0, 1, -localPos.x, -localPos.y));
        var color:uint = pixel.getPixel32(0, 0);
        if ((pixel.getPixel32(0, 0) & 0xff000000) != 0)
        {
            // if yes, dispatch the click event
            var e:MouseEvent = new MouseEvent(MouseEvent.CLICK, true, true, localPos.x, localPos.y, obj);
            obj.dispatchEvent(e);
            return true;
        }
    }

    return false;
}

残念ながら、カバーされていないケースが少なくとも 1 つあります。それは、オブジェクトが別のオブジェクトのマスクである場合です。表示階層のどこでもマスクになる可能性があるため、これを確認する方法がわかりません。これを見つけるには、ツリー全体を走査し、すべての表示オブジェクトをチェックする必要があります。

だから、私の質問は残っています:これを行う簡単な方法はありませんか?

4

2 に答える 2

2

AS3 のイベントにも問題がありました。最善の方法は、イベントをディスパッチしている同じオブジェクトに eventListeners を追加することです。あなたの場合、.addEventListener をステージに追加し、関数を子クリップの関数として送信します。例えば:

    stage.addEventListener(MouseEvent.CLICK, object.object.clicked);

これが役立つことを願っています。私は過去にこの方法を使用して成功しました。

于 2012-12-11T16:53:54.607 に答える
1

stage.getObjectsUnderPoint(new Point(pointerX、pointerY));を使用できます。関数、オブジェクトを含むYou配列を返します。オーバーレイオブジェクトを削除するよりも、配列の最後のインスタンスを最も深いDisplayObjectにする必要があります。

注:最後のインスタンスはグラフィックなどである可能性があるため、親オブジェクトをループして最も近いInteractiveObjectを見つける必要があります。また、親オブジェクトはmouseChildren=falseまたはmouseEnabled=falseを持つことができることを忘れないでください

于 2012-12-11T12:49:49.040 に答える