Category Archive: ActionScript

[AS]配列で任意の位置に値を追加する方法

配列で指定した位置に値を追加する方法。
指定した位置を削除するときと同じArray.splice()を使う。

以下、削除、追加のソース

var array:Array = ["a","b","c"]
trace(array); //出力:a,b,c
var number = 1;
array.splice(number,1);
trace(array); //出力:a,c
array.splice(number,0,"d");
trace(array);//出力:a,d,c

[AS]TextField.defaultTextFormatを複数作って、TextFormatを追加していける

defaultTextFormatの挙動について、
名前の通り、TextFieldに設定されている、TextFormatを一度デフォルトに戻してから、新しいFormatを設定するものと思ったら、上塗りで追加していくことが可能でした。
(今まで検証せずに使ってた、恐ろしい・・・)

↓以下フレームアクション

var tf:TextField = new TextField();
var str:String = "ほげほげ";
tf.autoSize = "left";
addChild(tf);
//テキストフォーマット1個目
var tfm1:TextFormat = new TextFormat();
tfm1.size = 50;
//1個目を設定
tf.defaultTextFormat = tfm1
//テキストフォーマット2個目
var tfm2:TextFormat = new TextFormat();
tfm2.color = 0xFF0000;
//2個目を設定(1個目の設定を残して上塗り設定)
tf.defaultTextFormat = tfm2;
tf.text = str

一点だけ注意は、tf.text = strをTextFormat適用後に設定してること。
これは適用後にしないと、それ以後にdefaultTextFormatしても無意味。

[AS]フォーカスをステージに戻す方法(どこもクリックされていない状態)

以下、1行でOK。

stage.focus = stage;

[AS]定義と同時に実行する無名関数

こういう書き方もあるのね。

//フレームアクション
(function(){
trace("a");
trace("b");
trace("c");
})();

うまい使い道がうかばないけれども。、

[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]動的に追加したオブジェクトは、インスタンス名(nameプロパティ)を使ってアクセスすることはできない?→できます。

できそうでできなかったのでメモ。
※2009/9/25/21:43追記 できました→下に追記があります。

前提として、ステージ上にMcを配置し、そのインスタンス名はmc
mcの中には2個Mcが配置してあり、それぞれ、mc1、mc2とインスタンス名を設定

//メインのタイムラインのフレームアクション
trace(mc["mc"+1]);//出力:[object MovieClip]
trace(mc["mc"+2]);//出力:[object MovieClip]

//動的にspriteを作って、ステージ上のmcに配置
var sp1 = new Sprite();
sp1.name = "sprite1";
mc.addChild(sp1);
trace(this.mc["sprite1"]); //出力:underfined

//動的にspriteを作って、ステージに配置
var sp2 = new Sprite();
sp2.name = "sprite2";
addChild(sp2);
trace(this["sprite2"]); //出力:underfined

//配列につっこむ
var array = [];
array.push(sp1);
trace(array[0]);//出力:[object Sprite]

動的に設定したSpriteはnameプロパティを設定しても、それを使ってアクセスってできないのかな?
とりあえず配列つっこんで保持しておけばそこから呼び出すことはできるけど。
気分的には配列作るのにちょっと抵抗あり。
うーん。

※2009/9/25/21:43 追記
コメント欄にて教えていただきました。
以下のようにすればアクセス可能。

var sp1 = new Sprite();
mc.addChild(sp1)
sp1.name = "sprite1";
mc["sprite1"] = sp1
trace(this.mc["sprite1"].name);  //出力:sprite1

ついでにもう一点。
「as3 name インスタンス名」でググッてみたらF-siteにて野中さんの詳しい解説もありました。
[AS3] MovieClipインスタンスとインスタンス名

これによるとDisplayObjectContainer.getChildByName(String)を使う手段もあり。

var sp1 = new Sprite();
mc.addChild(sp1);
sp1.name = "sprite1";
trace(mc.getChildByName(sp1.name).name); //出力:sprite1

[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 )
}