Proxyクラスのこと
- 2009 年 11月 9 日
Proxyクラスはどんな時使うものか見当のつかない状態だったのだけど、便利に使えそうなケースが見つかったのでエントリー。
Proxyについてはここに説明がある。
ActionScript 3.0 言語およびコンポーネントリファレンス
これ読んでも正直なんのこっちゃって思っていた。
思いついた方法は、複数のオブジェクトのいくつかのプロパティを一斉に変更したい時、Proxyを介して変更するってもの。いろんな方法があると思いますが、Proxyを介して行うのもなかなか便利そうです。
以下のように複数の表示オブジェクトがあり、それらのプロパティを変更したいとします。
まず、表示オブジェクトを配列なりVectorなりに格納する。
var vector:Vector.<MovieClip> = new Vector.<MovieClip>(); vector.push( this.arrow0 ); vector.push( this.arrow1 ); vector.push( this.arrow2 ); vector.push( this.arrow3 ); |
これをProxyを継承したクラスに渡す。
this.proxy = new ProxyMcGroup( vector ); |
Proxyを継承したクラスではVectorを変数に代入する。
継承する時はdynamicで宣言しておいた方が、proxy.xのようにドットシンタックスでプロパティを参照してもエラーにならないのでいいと思う。
public dynamic class ProxyMcGroup extends Proxy{ private var _item:Vector.<MovieClip>; public function ProxyMcGroup( _item:Vector.<MovieClip> ){ super(); this._item = _item; } } |
Proxyを継承したクラスのsetPropertyをオーバーライトし、Vectorを繰り返し処理でプロパティを変更する。
override flash_proxy function setProperty(name:*, value:*):void{ for each( var i:MovieClip in this._item ){ i[name] = value; } } |
ひとまずこれだけで、複数オブジェクトのプロパティを一斉に変更できるようになる。
複数オブジェクトが同じプロパティを持つことを前提に、どのプロパティも変更できる(これが便利なポイント)はずです。
このままだと、setterだけなので取得が出来ない。
また例えばTweenerで動かす時はTweenerがhasOwnPropertyを使ってプロパティの有無を確認したりするので、必要に応じて拡張していく。
サンプルのは以下のようプロパティ値をDictionaryに保存するようにしたり、for…inステートメントでプロパティの参照が出来るようにしてみた。
package{ import __AS3__.vec.Vector; import flash.display.MovieClip; import flash.utils.Proxy; import flash.utils.flash_proxy; import flash.utils.Dictionary; public dynamic class ProxyMcGroup extends Proxy{ private var _item:Vector.<MovieClip>; private var _dictionary:Dictionary; private var _prop:Array; public function ProxyMcGroup( _item:Vector.<MovieClip> ){ super(); this._item = _item; this._dictionary = new Dictionary(true); this._prop = []; } override flash_proxy function callProperty(methodName:*, ...args):*{ trace( "callProperty:" + methodName + "," + args ); return; } override flash_proxy function getProperty(name:*):*{ trace( "getProperty:" + name ); return this._dictionary[name]; } override flash_proxy function setProperty(name:*, value:*):void{ trace( "setProperty:" + name + "," + value ); if( !this._dictionary.hasOwnProperty(name) ){ this._prop.push( name ); } this._dictionary[name] = value; for each( var i:MovieClip in this._item ){ i[name] = value; } } override flash_proxy function hasProperty(name:*):Boolean{ trace( "hasProperty:" + name ); return this._dictionary.hasOwnProperty(name); } override flash_proxy function deleteProperty(name:*):Boolean{ trace( "deleteProperty:" + name ) this._prop = this._prop.filter( function( item:*, index:int, array:Array ):Boolean{ if( item == name ) return false; else return true; } ); return delete _dictionary[name]; } override flash_proxy function getDescendants(name:*):*{ return; } override flash_proxy function nextNameIndex(index:int):int{ trace( "nextNameIndex:" + index ); if( index < this._prop.length){ return index + 1; } else{ return 0; } } override flash_proxy function nextName(index:int):String{ trace("nextName:" + index); return this._prop[index - 1]; } override flash_proxy function nextValue(index:int):*{ trace("nextValue:" + index); return this._dictionary[ this._prop[index - 1] ]; } } } |
動かしているところはProgressionのSerialListを使っています。
動かす前に使うプロパティに値を入れておく。
this.proxy.rotation = 0; this.proxy.alpha = 1; this.proxy.scaleX = 1; this.proxy.scaleY = 1; var comm:SerialList = new SerialList( { onComplete:function():void{ this.execute(); } }, new DoTweener( this.proxy, { rotation:360, transition:"easeInOutExpo", time:2 } ), new DoTweener( this.proxy, { alpha:0.5, transition:"easeNone", time:1 } ), new DoTweener( this.proxy, { scaleX:1, scaleY:1, _bezier:{ scaleX:0, scaleY:0 }, transition:"easeInOutExpo", time:1 } ), new DoTweener( this.proxy, { rotation:0, transition:"easeInOutExpo", time:2 } ), new DoTweener( this.proxy, { alpha:1, transition:"easeNone", time:1 } ) ); comm.execute(); |
ProxyはTweensy FXの時に久しく出てきて今回の使い方を気づいた。
思いもよらないところでつながることは良くある。何かを調べるってことは良いことだ。