[AS]文字列のURLエンコードとデコード

文字列をURLエンコードする場合は、flash.utils.escapeMultiByte()。
URLエンコードされた文字列をデコードする場合は、flash.utils.unescapeMultiByte()。

//フレームアクション
var str:String = "/hoge/moge/hage/toge/img.jpg";
str = escapeMultiByte(str)
trace(str);//出力:%2Fhoge%2Fmoge%2Fhage%2Ftoge%2Fimg%2Ejpg
str = unescapeMultiByte(str)
trace(str);//出力:/hoge/moge/hage/toge/img.jpg

参考:[AS3] URLエンコード / F-Site

[AS]画像をゆっくり動かす方法

偉い人に教えてもらったテクニック。

通常ゆっくり動かすときに1px以下だとカクカクした動きになります。

package  {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	/**
	 * ...
	 * @author 393

	 */
	public class Test extends Sprite{
		private var bm:Bitmap;
		//ライブラリに画像を用意し、クラス名Bmpでリンケージ。
		//画像サイズは400×300
		
		public function Test() {
			var bmd:BitmapData = new Bmp(0, 0);
			bm = new Bitmap(bmd);
			addChild(bm);
			
			addEventListener(Event.ENTER_FRAME , enterFrameHandler);
		}
		private function enterFrameHandler(e:Event):void {
			//かくかくと動く
			bm.x += 0.08;
			bm.y += 0.08;
		}
	}
}

スムーズに動かしたいときは、beginBitmapFill()を使えばOK。

package  {
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	/**
	 * ...
	 * @author 393
	 */

	//ライブラリに画像を用意し、クラス名Bmpでリンケージ。
	//画像サイズは400×300
	
	public class Main extends Sprite{
		
		private var matrix:Matrix = new Matrix();
		private var bmp:BitmapData;
		private var sp:Sprite;
		private var mx:Number = 0;
		private var my:Number = 0;
		private var w:Number;
		private var h:Number;
		
		public function Main() {
			bmp = new Bmp(0, 0);
			sp = new Sprite();
			addChild(sp);
			buttonMode = true;
			this.addEventListener(Event.ENTER_FRAME , xEnterFrame);
		}
		function xEnterFrame (e:Event):void {
			mx += 0.05
			my += 0.05
			matrix.tx = mx;
			matrix.ty = my;
			sp.graphics.clear();
			//smoothプロパティをtrueにするのがポイント
			sp.graphics.beginBitmapFill(bmp, matrix,false,true);
			sp.graphics.drawRect(mx, my, 400, 300);
			sp.graphics.endFill();
		}
	}
}

このときのポイントは、beginBitmapFill()の第3引数のsmoothをtrueにするということ。
(デフォルトはfalse)
falseのままだと、先のサンプルと同じくカクカクした動きとなります。

もっと簡単にできる方法を追加しました。
[AS]画像をゆっくり動かす方法 その2

[AS]ArgumentError: Error #2015: BitmapData が無効です。エラーの謎

エラー:ArgumentError: Error #2015: BitmapData が無効です。
書籍:ActionScript3.0エラーアーカイブスによると、このエラーの主な原因は、

1.BitmapDataインスタンスの幅または高さが制限範囲(1~8191px)を超えている。
2.BitmapDataインスタンスのピクセルの総数が1677215pxを超えている。

ということらしいのですが、じゃあこれはどういうことだ?ということがおきたのでメモ。

//フレームアクション
for(var i:uint = 0; i < 11; i++){//i < 10のときは実行可能
	var bmd:BitmapData = new BitmapData(4000, 4000,true,0x11FFCC00);
}

これを実行するの上記エラーになります。
(ちなみにfor文を10回繰り返しではエラーにならない。11回でエラーになる)

これは主な原因の1,2も満たしていないのでその他の原因ということでしょうか。
憶測として、BitmapDataは全体でのピクセル数の制限があるのでは?ということで、
上記の場合は、4000×4000×11 = 176000000ピクセルとなります。
このくらいが限界なのかと、ためしに、以下のように書き換えてみると同じようにエラー
(2000×8000×11 = 176000000 でピクセル総数は同じ)

for(var i:uint = 0; i < 11; i++){//i < 10のときは実行可能
	var bmd:BitmapData = new BitmapData(2000, 8000,true,0x11FFCC00);
}

うんうん、予想通り。
じゃあ、これもエラーだよねと、以下のようにすると、(1000×1000×176=176000000)
これは想定外にOK・・・

for(var i:uint = 0; i < 176; i++){//i<700くらいでやっとエラーになる。
	var bmd:BitmapData = new BitmapData(1000, 1000,true,0x11FFCC00);
}

繰り返し数を700回くらいにするとやっとエラーになります。

うーん、どういうことなんだろう。。。

これで現実的に困ったのはEnterFrameの処理でBitmapDataを生成しまくってたら、この現象になってしまったということ。
具体的には、BitmapData作って、BitmapにあててaddChildして、一定時間がたったら、そのBitmapをremoveChildして~の繰り返しをしてたのだけど、しばらく動かしているとこのエラーが発生。
一応解決策は、BitmapをremoveChildする際に、BitmapData.dispose()してあげれば大丈夫な感じだったけど、原因がはっきりしないのが、なんだか気持ち悪い。。。

※コメント欄で教えてもらいました。

[AS][?]FLV読み込み時のonMetaDataを取得するタイミングがわからない

ちょっと気持ち悪いのでメモ

◆現象◆
簡単なFLVプレイヤーでインターフェースは再生ボタンと、頭出しボタン。
FLVPlaybackではなく、Videoオブジェクトによる自作。
この記事にかいてあるLoadMovieクラスの拡張版のような感じ。
(実際はもっとごちゃごちゃしてるのであとで時間ができたら簡略版を作って検証・記載する、つもり)
NetStream.clientにて、onMetaDataを取得するようにしてある。
NetStream.play(“xxx.flv”)で、MetaDataが取得は問題ないのだけど、頭だしボタンを押したときもMetaDataが取得される場合がある。
(読み込むFLVファイルによっては、頭出ししてもMetaDataが取得されない場合がある)
頭出しの処理は、NetStream.seek(0);

seek(0)から再生させたときにonMetaDataを取得するということなのか?
(seek(0)のタイミングではなくって、そこから再生させたら、みたいな感じ)
flvファイルによって、上記条件でMetaDataを取得したり、しなかったりという感じが???なのです。
原因よくわからんのでとりあえず例外処理書いたけど、なんか気持ち悪い。

[AS]クロージャのイイ感じの使用用途

クロージャとは、functionの中にfunctionを書くような書き方。(だと思う)
フレームに書いたらこんな感じ。

//フレームアクション
function test(){
	var func:Function  = new Function();
	func = function(){
		trace("func内this : " + this);//出力:func内this : [object global]
	}
	trace("test内this : " + this);//出力:test内this : [object MainTimeline]
	func();
}
test();

これ使うと関数内のthisが何を示すか混乱するのよ。(私にとっては、ね)。
なので、あまり使わないようにしてたけど、便利そうな使い方を教わったのでご紹介。

たとえば、フェードイン処理とフェードアウト処理について。
以下のように書くことですっきりまとまる。

package {
	public class Main extends Sprite {
		//関数をインスタンス化しておく
		private var fader:Function = new Function();
		
		public function fadeIn( speed:Number ) : void {
			//※addEventListenerされてない状態をremoveしてもエラーにはならない
			removeEventListener( Event.ENTER_FRAME, fader )
			//リスナー関数をaddEventListenerと同じ位置にかく
			//fader関数の中身を設定
			fader = function( e:Event ) : void {
				alpha += speed;
				if( alpha >= 1 ) {
					removeEventListener( Event.ENTER_FRAME, fader )
				}
			}
			addEventListener( Event.ENTER_FRAME, fader )
		}
		
		public function fadeOut( speed:Number ) : void {
			//※addEventListenerされてない状態をremoveしてもエラーにはならない
			removeEventListener( Event.ENTER_FRAME, fader )
			//fader関数の中身を設定
			fader = function( e:Event ) : void {
				alpha -= speed;
				if( alpha <= 0 ) {
					removeEventListener( Event.ENTER_FRAME, fader )
				}
			}
			addEventListener( Event.ENTER_FRAME, fader )
		}
	}
}

ポイントのひとつは、フェードインもアウトも同じfaderという関数を使っているところ。
インとアウトが同時実行されることはない。(remove処理が確実に行われる)
同時に実行させる必要があれば、新しいFunctionインスタンスを作ればよい。
あと、Functionインスタンスがnullでなければ、addEventListenerしてない状態で、removeEventListenerしてもエラーにはならない。

この書き方なら、フェード処理をもっと細かく設定したい場合も以下のようにすっきりかける。

//フェードイン関数のみ抽出
public function fadeIn( speed:Number ) : void
{
	removeEventListener( Event.ENTER_FRAME, fader )
	fader = function( e:Event ) : void
	{
		alpha += speed;
		//追加:アルファが0.5以上になったら、スピードを半分にする
		if( alpha >= 0.5) {
			removeEventListener( Event.ENTER_FRAME, fader )
			fader = function( e:Event ) : void
			{
				alpha += speed/2
				if( alpha >= 1) {
					removeEventListener( Event.ENTER_FRAME, fader )
				}
			}
			addEventListener( Event.ENTER_FRAME, fader )
		}
	}
	addEventListener( Event.ENTER_FRAME, fader )
}

[AS](MCの)参照渡しと、配列への格納への違い

メモリ管理でつまづいている、ちょっと挙動がわからない。

やりたいことはこんな感じ。

var mc0:MovieClip = new MovieClip();
addChild(mc0);
var array:Array = []
array.push(mc0);
var mc1 = array[0]

//↓で表示リストから消えるのは無問題
removeChild(mc1);
//↓だとmc0分のメモリは消えないっぽい。
mc1=null;
//↓だとmc0分のメモリは消えるっぽい。
array[0] = null;

参照先を操作すれば、表示リストからは消せる。
でも、メモリを開放できないのがなんだか気持ち悪い。
参照で渡した場合、参照先をnullにしても、参照元はnullにならないってこと?
配列に格納するのも参照渡しと同じ感覚だと思っていたけど、違うってこと?
このあたりは今度えらい先生と会う機会があるときに教えてもらおう・・・

[追記]
コメントにて教えて頂きました。
参照で渡した場合、参照先をnullにしても、参照元はnullにならない、でOK。
参照先との関係が切れるだけ、ということだそうです。

[AS]overrideする場合は、元の関数とパラメータを同じにすること

関数をoverrideする場合は、元の関数とパラメータを全て同じにする必要があるらしい。
以前、インターフェースでは戻り値必須という記事を書いたけど、overrideもそんな感じらしい。

↓この関数をoverrideするには・・・

protected function testFunc(){}

↓こんな感じになる。

protected override function testFunc(){}
//↓これだとNG(voidがあるから)
//protected override function testFunc():void{}

またこういう場合は、

protected function testFunc():void{}

こんな感じ

protected override function testFunc():void{}
//↓これだとNG(voidがないから)
//protected override function testFunc(){}

注意が必要なのは、戻り値のvoid。
あってもなくても意味一緒じゃね?と思ってもFlash上では一緒とは判断してくれない模様。
正確にコーディングしないと。。。

参考サイト
desginのFlash:[エラー!!][AS3]1023: オーバーライドに対応していません。

[AS]Flickrの画像のBitmapDataを弄る際のセキュリティ解除方法

Flickrの画像を読み込み、bimapdataを弄ろうとすると、以下のように怒られる。

SecurityError: Error #2122: セキュリティサンドボックス侵害 : BitmapData.draw:http://393.bz/test/New.swf は http://farm4.static.flickr.com/3315/3667944681_06e506542e.jpg にアクセスできません。ポリシーファイルが必要ですが、このメディアがロードされたとき、checkPolicyFile フラグが設定されませんでした。
at flash.display::BitmapData/draw()
at NewClass/drawImage()

以下のおまじないを記述すれば大丈夫。

Security.loadPolicyFile("http://api.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");

[AS]配列の中身全部をtraceする

toString()で楽勝でした。

var num:Number = 100;
var array:Array = ["a","b","c",num]
trace(array.toString()) //出力:a,b,c,100

[AS][自分用]ActionScript3.0デザインパターンの読書メモ(8)
-カプセル化

カプセル化とは、
1.パブリックなプロパティは使わない
2.外部クラスのオブジェクトを参照しない。(そのクラスの引数を経由した参照は除く)

よくわからんけど、プロパティ値を変更するときは直接変更できないようにして(privateにする)、
パブリックなメソッドを用意してそれを使って内部のプロパティを変更するような仕組みを作るといいらしい。
2.については引数を使わずに外部クラスを参照する方法が浮かばないのだが。