flash.utils.Proxyが使えない件〜Filter型の謎

Bitmamap操作の練習にDisplacementMapFIlterを使ってみることにした。

使っていくうちに、いくつかの提携処理をクラス化出来ないかと考えた。

放射状のグラデーョンビットマップを使ったもの
格子上に二色のタイルを敷き詰めたもの

などなど

フィルターの使い方が、Spriteなどの表示オブジェクトのfiltersプロパティに渡す
という使い方なので、例えば、

var sprite:Sprite = new Sprite();
addChild(sprite);
sprite.filters = [
    new GradientRadialFilter(width, height, scaleX, scaleY),
    new GridFilter(width, height, gridWidth, gridHeight, scaleX, scaleY)
];

みたいに出来たら簡単だなと思って、クラスを書いてみたら、
「基本クラスはfinalです。」とか言われてしまう。

というわけで、継承は使えない。

まあそもそもは、DisplacementMapFilterに渡す
mapBitmapを作る部分が違うくらいなので、

var sprite:Sprite = new Sprite();
addChild(sprite);
sprite.filters = [
    new DisplacementMapFilter(
        new GradientRadialBitmap(width, height), null, 0, 0, scaleX, scaleY),
    new DisplacementMapFilter(
        new GridBitmap(width, height, gridWidth, gridHeight), null, 0, 0, scaleX, scaleY)
];

とか書けば良いのでしょうが、どうもイマイチ。。

あるいは委譲を使って、

var filterFactory:FilterFactory = new FilterFactory();
var sprite:Sprite = new Sprite();
addChild(sprite);
sprite.filters = [
    filterFactory.create(new GradientRadialFilter(width, height, scaleX, scaleY)),
    filterFactory.create(new GridFilter(width, height, gridWidth, gridHeight, scaleX, scaleY))
];

とか?

うーむ、、どれもイマイチだな。

flash.utils.Proxyを使ってみたらどうだろう。

ということで試してみた。

package jp.seagirl.filters
{
    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.display.GradientType;
    import flash.display.Sprite;
    import flash.filters.DisplacementMapFilter;
    import flash.filters.DisplacementMapFilterMode;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    public dynamic class GradientRadialFilter extends Proxy
    {
        //--------------------------------------------------------------------------
        //
        //  Constructor
        //
        //--------------------------------------------------------------------------
        
        public function GradientRadialFilter(width:Number = 0.0,
                                             height:Number = 0.0,
                                             scaleX:Number = 0.0,
                                             scaleY:Number = 0.0,
                                             mapBitmap:BitmapData = null,
                                             mapPoint:Point = null,
                                             componentX:uint = BitmapDataChannel.BLUE,
                                             componentY:uint = BitmapDataChannel.RED,
                                             mode:String = DisplacementMapFilterMode.COLOR,
                                             color:uint = 0,
                                             alpha:Number = 0.0
                                            )
        {
            if (mapBitmap == null)
                mapBitmap = createMapBitmap(width, height, [100, 255]);
                
            displacementMapFilter = new DisplacementMapFilter(mapBitmap,
                                                              mapPoint,
                                                              componentX,
                                                              componentY,
                                                              scaleX,
                                                              scaleY,
                                                              mode,
                                                              color,
                                                              alpha
                                                             );
        }
        
        //--------------------------------------------------------------------------
        //
        //  Variables
        //
        //--------------------------------------------------------------------------
        
        private var displacementMapFilter:DisplacementMapFilter;
        
        //--------------------------------------------------------------------------
        //
        //  Overridden methods
        //
        //--------------------------------------------------------------------------
        
        override flash_proxy function callProperty(methodName:*, ... args):*
        {
            return displacementMapFilter[methodName].apply(displacementMapFilter, args);
        }
        
        override flash_proxy function getProperty(name:*):*
        {
            return displacementMapFilter[name];
        }
        
        override flash_proxy function setProperty(name:*, value:*):void
        {
            displacementMapFilter[name] = value;
        }
        
        //--------------------------------------------------------------------------
        //
        //  Methods
        //
        //--------------------------------------------------------------------------
        
        private function createMapBitmap(width:Number, height:Number, ratio:Array):BitmapData
        {
            var matrix:Matrix = new Matrix();
            matrix.createGradientBox(width, height, 0, 0, 0);
            
            var map:Sprite = new Sprite();
            map.graphics.beginGradientFill(GradientType.RADIAL, [0xff0000, 0x0000ff], [1, 1], ratio, matrix);
            map.graphics.drawRect(0, 0, width, height);
            map.graphics.endFill();
            
            var mapBitmap:BitmapData = new BitmapData(width, height, true, 0);
            mapBitmap.draw(map);
            
            return mapBitmap;
        }
    }
}

で、これをfiltersに入れてみる

sprite.filters = [new GradientRadialFilter(width, height, scaleX, scaleY)];

コンパイルは普通に出来たので、実行してみる。

するとランタイムエラー

「ArgumentError: Error #2005: パラメータ 0 の型が正しくありません。正しい型は Filter です」

となって、型チェックに弾かれてしまった。

必ずProxyクラスを継承しないといけないので、この場合Filterクラスに見せることは出来ない。

これでは、Proxyする意味がない

ところで、Filterなんてクラスどこにもいないことになってるけど何者…??

実はAS3のコアな部分ではこれらが抽象クラスとして存在してたりするの?

ASは手を出せば出すほど、コアな部分のソースを読みたいと思うようになる。