[ActionScript 3.0] ビットマップの非透明部分のみでマウスイベントを受け取る方法

[ActionScript 3.0] ビットマップの非透明部分のみでマウスイベントを受け取る方法

マウスイベントの当たり判定で、非透明部分のみに対して反応するようにしました。

マウスイベントの当たり判定を調べるメソッド

インスタンスと座標との当たり判定を調べるには、hitTestPointというメソッドが使えます。

hitTestPointメソッド

hitTestPointメソッドの使い方は以下の通りです。

hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean

第1引数(x:Number)
このオブジェクトの検査の基準となる x 座標です。
第2引数(y:Number)
このオブジェクトの検査の基準となる y 座標です。
第3引数(shapeFlag:Boolean)
オブジェクトの実際のピクセルと比較して検査する場合は true、境界ボックスと比較して検査する場合は false。省略時は false。
戻り値(Boolean)
指定されたポイントと表示オブジェクトが重複または交差する場合は true、そうでなければ false。

hitTestPointメソッドを使った場合、第3引数の shapeFlag で検査対象を指定できますが、この方法はシェイプデータの場合なら対処できますが、ビットマップデータの場合は、値を ture にしたとしても、透過部分も含めて交差判定の対象になります。

シェイプデータ

ビットマップデータ

これに対処するために、BitmapDataクラスの hitTestメソッドを使います。

BitmapDataクラスのhitTestメソッド

BitmapDataクラスの hitTestメソッドを使うと、不透明とみなされるアルファチャンネルの最小値を指定できます。
hitTestメソッドの使い方は以下の通りです。

hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean

第1引数(firstPoint:Point)
任意の座標空間における BitmapData イメージの左上隅の位置です。同じ座標空間を使って secondBitmapPoint パラメータが定義されます。
第2引数(firstAlphaThreshold:uint)
このヒットテストで不透明とみなされるアルファチャンネルの最小値です。
第3引数(secondObject:Object)
Rectangle、Point、Bitmap、または BitmapData オブジェクトです。
第4引数(secondBitmapDataPoint:Point)
2 番目の BitmapData オブジェクト内のピクセル位置を定義するポイントです。このパラメータは、secondObject の値が BitmapData オブジェクトである場合にのみ使用します。
第5引数(secondAlphaThreshold:uint)
2 番目の BitmapData オブジェクト内で不透明であるとみなされるアルファチャンネルの最小値です。このパラメータは、secondObject の値が BitmapData オブジェクトで、両方の BitmapData オブジェクトが透明である場合にのみ使用します。
戻り値(Boolean)
ヒットが発生する場合は true、そうでない場合は false です。

アルファチャンネルの最小値を0にすることで、完全に透明なものはヒットエリアの範囲外であると判断させることができます。

BitmapData.hitTest(new Point(0,0), 0, new Point(x,y))

ビットマップの非透明部分を判定できるカスタムクラスの作成

さて、ここからが本題です。
ビットマップデータの非透明部分を判定するためには、上記で説明した hitTestPointメソッドを元にカスタムクラスを作成します。

hitTestPointメソッドのオーバーライド

もう少しコードを整理にするために、Spriteクラスを継承した CustomChildクラスを作って、hitTestPointメソッドをオーバーライドしました。
CustomChildクラスに BitmapData を指定して、hitTestPointメソッド内で BitmapDataクラスの hitTestメソッドによる当たり判定の結果を返してます。

これによって、ビットマップの非透明部分のみでマウスイベントを受け取る事ができます。

Main

private var _bitmap:BitmapData;
private var _matrix:Matrix;
private var _mapPoint:Point;
private var _mousePoint:Point;

public function CustomChild(bitmap:BitmapData) {
    _bitmap = bitmap;

    _matrix = new Matrix;
    _matrix.tx = -Math.round(bitmap.width / 2);
    _matrix.ty = -Math.round(bitmap.height / 2);

    _mapPoint = new Point(_matrix.tx, _matrix.ty);
    _mousePoint = new Point(0, 0);

    this.graphics.clear();
    this.graphics.beginBitmapFill(_bitmap, _matrix, false, true);
    this.graphics.drawRect(_matrix.tx, _matrix.ty, _bitmap.width, _bitmap.height);
    this.graphics.endFill();
}

hitTestPoint

/**
 * 表示オブジェクトを評価して、x および y パラメーターで指定されたポイントと重複または交差するかどうかを調べます。
 * @param    x    このオブジェクトの検査の基準となる x 座標です。
 * @param    y    このオブジェクトの検査の基準となる y 座標です。
 * @param    shapeFlag    オブジェクトの実際のピクセルと比較して検査する場合は true、境界ボックスと比較して検査する場合は false です。
 * @return    指定されたポイントと表示オブジェクトが重複または交差する場合は true、そうでなければ false です。
 */
override public function hitTestPoint(x:Number, y:Number, shapeFlag:Boolean = false):Boolean {
    if (shapeFlag && _bitmap != null && parent != null) {
        _mousePoint.x = x;
        _mousePoint.y = y;
        var p:Point = globalToLocal(_mousePoint);
        return _bitmap.hitTest(_mapPoint, 0, p);
    } else {
        return super.hitTestPoint(x, y, shapeFlag);
    }
}

サンプル

ソースコードはFlashエリア上を右クリックで [View Source] からどうぞ。