2009年9月アーカイブ

Adobe EDGEで全5回の連載を開始しました。

『大重美幸のこれ見落としてませんか? ActionScript 3.0』
image.jpg

内容はもちろんActionScript3.0。知ってそうで知らない。今さら人には聞きづらいといったことを取り上げていく予定です。第1回は『あなたが思う以上に自由自在な「Button コンポーネント」』です。

(section04-01 イベントとイベントリスナーから抜粋)

 イベントが発生するとaddEventListener()で登録しておいたリスナー関数が呼び出されますが、このときイベントオブジェクトが引数として送られてきます。イベントオブジェクトにはイベントの種類によってさまざまなプロパティがあり、発生したイベントの状況を示すデータが含まれています。このプロパティの値を活用することで、スクリプトのむだを省いたり、イベントに応じてできることをひろげることができます。

クリックされたターゲット
 次のサンプルのball1_mcからball4_mcの4個のインスタンスはクリックのたびに10度回転します。各インスタンスのaddEventListener()ではそれぞれのインスタンスを10度回転させるリスナー関数を追加していますが、リスナー関数のstepRotation1()からstepRotation4()の4個のリスナー関数定義をみると回転の対象となるインスタンスが違うだけで同じ機能の関数です。この方法ではターゲットと同じ個数のリスナー関数が必要になります。

[:script:]ターゲットと同じ個数のリスナー関数が必要
//4個のmcに同じ機能のイベントリスナーを追加する
ball1_mc.addEventListener(MouseEvent.CLICK, stepRotation1);
ball2_mc.addEventListener(MouseEvent.CLICK, stepRotation2);
ball3_mc.addEventListener(MouseEvent.CLICK, stepRotation3);
ball4_mc.addEventListener(MouseEvent.CLICK, stepRotation4);

//ball1_mcを回転させる
function stepRotation1(eventObj:MouseEvent):void {
	ball1_mc.rotation+=10;
}
//ball2_mcを回転させる
function stepRotation2(eventObj:MouseEvent):void {
	ball2_mc.rotation+=10;
}
//ball3_mcを回転させる
function stepRotation3(eventObj:MouseEvent):void {
	ball3_mc.rotation+=10;
}
//ball4_mcを回転させる
function stepRotation4(eventObj:MouseEvent):void {
	ball4_mc.rotation+=10;
}
fig04-01-06.jpg
インスタンスをクリックすると、そのインスタンスが10度回転します。。→swfを試す

 このスクリプトは、次のようにリスナー関数の引数のイベントオブジェクトのtargetプロパティを利用することで、どのインスタンスも同じstepRotation()をリスナー関数として使えるようになりスクリプトも短くなります。

[:script:]イベントオブジェクトのtargetプロパティを利用する
//4個のmcに同じイベントリスナーを追加する
ball1_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball2_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball3_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball4_mc.addEventListener(MouseEvent.CLICK, stepRotation);

//ターゲットを回転させる
function stepRotation(eventObj:MouseEvent):void {
	eventObj.target.rotation+=10;
}

 このスクリプトのポイントは9行目のeventObj.targetです。イベントオブジェクトのtargetプロパティには、イベントが発生したターゲットの参照、すなわちクリックされたインスタンスの参照が入っています。したがって、イベントによって呼ばれるリスナー関数が同じであっても、どのインスタンスがクリックされたのかがわかります。eventObj.targetをいったん変数に代入して使う場合には、次のようにas演算子を使って変数のデータ型にキャスト(型変換)しなければコンパイルエラーになります。

[:script:]targetの値を変数に代入して利用する
//4個のmcに同じイベントリスナーを追加する
ball1_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball2_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball3_mc.addEventListener(MouseEvent.CLICK, stepRotation);
ball4_mc.addEventListener(MouseEvent.CLICK, stepRotation);

//ターゲットを回転させる
function stepRotation(eventObj:MouseEvent):void {
	//targetの値をMovieClipクラスにキャストする
	var ball_mc:MovieClip=eventObj.target as MovieClip;
	ball_mc.rotation+=10;
}
 シンボルにもカスタムクラスを関連付けることができます。この手法は先に出版したAS3入門ノートでは解説していましたが、今回の完全改訂版では割愛した内容です。その内容をここで補足したいと思います。

 シンボルからインスタンスを作る方法は「Section07-01 表示オブジェクトの追加」に説明してあるので、ここが補足箇所の候補になりますが(p.211)、この時点ではクラス定義や継承について学んでいません。
 シンボルとカスタムクラスを関連付ける方法はドキュメントクラスと同じ考え方なので、「Section08-06 ドキュメントクラス」の最後のp.486が適当でしょう。ここに以下の原稿を追加します。

シンボルが継承するクラス 追加原稿 p.486
 ドキュメントクラスと同じようにシンボルにもカスタムクラスを関連付けることができます。シンボルにカスタムクラスを関連付けるには、シンボルのプロパティパネルでリンケージ書き出しの設定を行い、クラスフィールドにカスタムクラスを指定します。

fig 08-06-04.jpg
シンボルのリンケージ書き出し設定で関連付けるクラスを指定します

 たとえば、次のFlowerAクラスをシンボルに関連付けると、このシンボルから作ったインスタンスをステージに追加するだけで回転するようになります。このとき、ムービークリップシンボルに関連付けるカスタムクラスは、必ずMovieClipクラスを継承しなければなりません。
 インスタンスはnew FlowerA()で作ることができますが、普通にライブラリからステージにドロップして作ってもかまいません。

[:script:]シンボルに関連付けるFlowerAクラス
package {
	import flash.display.MovieClip;
	import flash.events.Event;

	public class FlowerA extends MovieClip {
		public function FlowerA() {
			addEventListener(Event.ENTER_FRAME, enterFrameHandler );
		}
		protected function enterFrameHandler(eventObj:Event):void {
			rotation += 3;
		}
	}
}

fig 08-06-05.jpg
インスタンスを作ってステージに追加するだけで回転します。→swfを試す
ファイルをダウンロードするextendSymbol.zip

(section04-01 イベントとイベントリスナーから抜粋)

 今度は同じイベントに同じリスナー関数を重ねて追加した場合を見てみましょう。次のサンプルではa_mcのフレーム再生イベントに対してstepRotationA()を4回重ねてリスナー関数として追加しています。この場合にはフレーム再生でstepRotationA()が4回実行されることになり、同じ機能のstepRotationB()を1回しか追加していない場合にb_mcに比べて4倍の速度で回転するでしょうか。
 その結果はa_mcもb_mcと同じくstepRotationA()を1回しか追加していない場合と同じ速度で回転します。すなわち、同じイベントに同じリスナー関数を重ねて追加しても、リスナー関数は重複して登録されないわけです。

[:script:]同じイベントに同じリスナー関数を重ねて追加した場合
//同じイベントに同じリスナー関数を重ねて追加する
a_mc.addEventListener(Event.ENTER_FRAME, stepRotationA);
a_mc.addEventListener(Event.ENTER_FRAME, stepRotationA);
a_mc.addEventListener(Event.ENTER_FRAME, stepRotationA);
a_mc.addEventListener(Event.ENTER_FRAME, stepRotationA);
//b_mcには1度しか追加しない
b_mc.addEventListener(Event.ENTER_FRAME, stepRotationB);

//回転させる
function stepRotationA(eventObj:Event):void {
	a_mc.rotation+=2;
}

function stepRotationB(eventObj:Event):void {
	b_mc.rotation+=2;
}
fig04-01-05.jpg
a_mcもb_mcと同じ速度で回転します。→swfを試す
(section04-01 イベントとイベントリスナーから抜粋)

 同じターゲットの同じイベントに対して複数のリスナーを追加するとどうなるでしょうか。次のスクリプトでは5行目でインスタンスf_mcのEvent.ENTER_FRAMEイベントにstepRotation()をリスナー関数として追加し、次の6行目でも同じくf_mcのEvent.ENTER_FRAMEイベントに今度はstepZoom()をリスナー関数として追加しています。この結果がどうなるかを予想すると、後から実行した6行目のaddEventListener()の設定が5行目のaddEventListener()の設定を上書きしていまい、Event.ENTER_FRAMEイベントではstepZoom()だけが実行されるようになるのではないかと思われます。
 しかし、実際にはEvent.ENTER_FRAMEイベントではstepRotation()とstepZoom()の両方のリスナー関数が実行され、両者の動作が組み合わさったアニメーションになります。すなわち、stepRotation()によって回転し、stepZoom()によって伸縮とアルファ変更を繰り返すアニメーションになります。

[:script:]同じイベントに別のリスナー関数を重ねて追加する
//stepZoomで比率を変化させるための角度
var degree:int;

//同じイベントに別のリスナー関数を重ねて追加する
f_mc.addEventListener(Event.ENTER_FRAME, stepRotation);
f_mc.addEventListener(Event.ENTER_FRAME, stepZoom);

//回転させる
function stepRotation(eventObj:Event):void {
	f_mc.rotation+=2;
}

//伸縮とアルファ変更
function stepZoom(eventObj:Event):void {
	degree=(degree+2)%360;
	//回転角度で比率を変える
	var ratio:Number=Math.abs(Math.sin(degree*Math.PI/180));
	//伸縮
	f_mc.scaleX=f_mc.scaleY=1+9*ratio;
	//アルファ変更
	f_mc.alpha=Math.max(0.02,1-ratio);
}
fig04-01-04b.jpg
回転と伸縮の複数のリスナー関数の動作が組み合わさったアニメーションになります。→swfを試す

 stepZoom()では17行目で比率ratioの値を作っています。sinの値は繰り返しでdegreeに2度ずつ加算され-1〜1のサイン波になり、Math.abs()によって絶対値0〜1で変化する値になります。
 19行目のscaleX、scaleYはインスタンスの横方向、縦方向のスケールを示すプロパティで、1のときが等倍です。この設定値を1+9*ratioで計算しているので、スケールは1倍〜10倍で変化します。21行目のalphaはインスタンスのアルファ値を示すプロパティで、0が透明、1が不透明の0〜1の範囲の値です。この設定値を1-ratioの計算で設定値を変化させ、完全な透明にならないようにMath.max()を使って最低値を0.02に制限しています。
(section04-01 イベントとイベントリスナーから抜粋)

 さらに発展させて、止まっているbox_mcをクリックすると回転が始まり、回転しているbox_mcをクリックすると回転が止まるようにしてみましょう。

 今度は止まっている状態から回転を開始する必要があるので、box_mcの回転を開始するstartRotation()を用意し、startRotation()をクリックイベントのリスナー関数として追加するところから始めます。
 startRotation()では2つのことを行います。1つはbox_mcが回転するようにフレーム再生イベントにstepRotation()を追加します。もう1つはbox_mcをクリックしたら回転を止める機能です。このとき、クリックイベントには回転を開始するstartRotation()がリスナー関数として追加されている状態なので、startRotation()を取り除くのを忘れないようにします。
 回転中にクリックしたときに実行されるstopRotation()では、startRotation()の場合とは逆に回転を止めることに加えて、次にクリックされたならば回転を開始するように設定し直します。このように、addEventListener()とremoveEventListener()を使ってイベントリスナーを追加したり取り除いたりすることで、イベントへの対応を切り替えるのがイベント処理の基本テクニックです。

[:script:]box_mcをクリックして回転と停止を切り替える
//クリックで回転を開始するようにする
box_mc.addEventListener(MouseEvent.CLICK, startRotation);

//回転を始めるリスナー関数
function startRotation(eventObj:MouseEvent):void {
	//フレーム再生で回転するようにする
	box_mc.addEventListener(Event.ENTER_FRAME, stepRotation);
	//クリックで回転を停止するようにする
	box_mc.removeEventListener(MouseEvent.CLICK, startRotation);
	box_mc.addEventListener(MouseEvent.CLICK, stopRotation);
}

//回転を止めるリスナー関数
function stopRotation(eventObj:MouseEvent):void {
	//回転を止める
	box_mc.removeEventListener(Event.ENTER_FRAME, stepRotation);
	//クリックで回転を開始するようにする
	box_mc.addEventListener(MouseEvent.CLICK, startRotation);
	box_mc.removeEventListener(MouseEvent.CLICK, stopRotation);
}

//フレーム再生で実行されるリスナー関数
function stepRotation(eventObj:Event):void {
	//box_mcを回転させる
	box_mc.rotation+=2;
}
fig4-1-3.jpgswfを試す
(section04-01 イベントとイベントリスナーから抜粋)

 イベントターゲットに追加したイベントリスナーを取り除くにはremoveEventListener()を使います。イベントターゲットに対して取り除きたいイベントタイプとリスナー関数を引数で指定します。

 書式:イベントリスナーを取り除く
イベントターゲット.removeEventListener(イベントタイプ, リスナー関数);

 たとえば、box_mcに追加してある「Event.ENTER_FRAMEイベントでstepRotation()を実行する」というイベントリスナーを取り除くスクリプトは次のようになります。これでbox_mcの回転が止まります。

[:script:]box_mcからイベントリスナーを取り除く
box_mc.removeEventListener(Event.ENTER_FRAME, stepRotation);

クリックで回転を止める
 ぐるぐる回転しているbox_mcをクリックすると回転が止まるようにするにはどうすればよいでしょうか。box_mcを回転させる方法は先のサンプルで説明したようにEvent.ENTER_FRAMEのイベントリスナーにリスナー関数としてstepRotation()を追加し、stepRotation()でbox_mcを少しずつ回転させます。この回転をクリックで止めるには次のスクリプトの3行目のようにクリックのMouseEvent.CLICKイベントにstopRotation()をリスナー関数として追加し、stopRotation()の中でEvent.ENTER_FRAMEのイベントリスナーを取り除きます。

[:script:]回転しているbox_mcをクリックして止める
//イベントリスナーを登録する
box_mc.addEventListener(Event.ENTER_FRAME, stepRotation);
box_mc.addEventListener(MouseEvent.CLICK, stopRotation);

//フレーム再生で実行されるリスナー関数
function stepRotation(eventObj:Event):void {
	//box_mcを回転させる
	box_mc.rotation +=2;
}

//クリックで回転を止めるリスナー関数
function stopRotation(eventObj:MouseEvent):void {
	//イベントリスナーを取り除く
	box_mc.removeEventListener(Event.ENTER_FRAME, stepRotation);
}
fig4-1-3.jpgswfを試す

(section04-01 イベントとイベントリスナーから抜粋)

 インスタンスがぐるぐる回転するといったアニメーションを作る場合にもイベント処理を利用します。インスタンスをぐるぐる回転させるには、インスタンスの回転角度を加算するリスナー関数を繰り返し発生するイベントで繰り返し呼び出せばよいわけです。
 フレームレートに合わせて繰り返し発生するフレーム再生イベントは、アニメーションで利用する繰り返しイベントとして最適なイベントです。次のスクリプトではbox_mcのフレーム再生イベントにstepRotation()をリスナー関数として追加しています。stepRotation()が実行されるたびにbox_mcが2度ずつ回転することから、box_mcはぐるぐる回り続けます。

[:script:]box_mcがぐるぐる回り続ける
box_mc.addEventListener(Event.ENTER_FRAME, stepRotation);

//フレーム再生で実行されるリスナー関数
function stepRotation(eventObj:Event):void {
	//box_mcを回転させる
	box_mc.rotation += 2;
}
 なお、Event.ENTER_FRAMEはフレームの移動に合わせて発生するイベントですが、フレームが1フレームしかない場合やstop()でフレーム移動を停止している場合にもフレームレートに合わせて継続的にイベントが発生します。
(section04-01 イベントとイベントリスナーから抜粋)

 「インスタンスbox_mcをクリックしたらtest()を実行する」といったインタラクティブな処理を考えたとき、この中には「1.どこで、2.何が起きたら、3.どうする」の3つの要素が含まれています。

 1.どこで 
 2.何が起きたら
 3.どうする 

 これをイベント処理の用語で言い換えると次のようになります。

 1.イベントターゲット ・・・・ イベントが発生するオブジェクト
 2.イベントタイプ ・・・・ 発生するイベントの種類
 3.リスナー関数 ・・・・ イベント発生で実行する関数

 さきほどの「インスタンスbox_mcをクリックしたらtest()を実行する」をこれに当てはめると次のようになります。

 1.イベントターゲット ・・・・ box_mc
 2.イベントタイプ ・・・・ クリック
 3.リスナー関数 ・・・・ test()

 このイベント処理をスクリプトではaddEventListener()というメソッドを使って設定します。書式は次のようになります。イベントが発生するオブジェクトに対して、イベントタイプとリスナー関数をペアにしてイベントリスナーとして追加します。

書式:イベントリスナーを追加する
イベントターゲット.addEventListener(イベントタイプ, リスナー関数);
[:note:] addEventListener()には引数がまだありますが、ここでは省略しています。

 実際のスクリプトは次のようになります。クリックというイベントタイプはMouseEvent.CLICKで指定します。リスナー関数はtestのように()を付けずに指定します。
 実行するtest()も定義しておきます。リスナー関数にはイベントタイプと同じデータ型のイベントオブジェクトが引数として送られてくるので、コンパイルエラーにならないようにtest(eventObj:MouseEvent)のようにイベントオブジェクトを受け取る引数が必要です。

[:script:]box_mcをクリックしたらtest()を実行する
box_mc.addEventListener(MouseEvent.CLICK, test);

//クリックで実行されるリスナー関数
function test(eventObj:MouseEvent):void {
	trace("test OK");
}
 そこで、test()でbox_mcの現在の回転角度つまりbox_mc.rotationに45度を加算すれば、box_mcをクリックするたびにbox_mcが45度回転するようになります。

[:script:]box_mcをクリックすると45度回転する
box_mc.addEventListener(MouseEvent.CLICK, test);

//クリックで実行されるリスナー関数
function test(eventObj:MouseEvent):void {
	//box_mcを45度回転させる
	box_mc.rotation += 45;
}
fig04-01-02.jpgswfを試す
(section03-02 配列の値を並べ替えるから抜粋)

 配列の値を逆順に並べ替えたいときは、reverse()を使います。

[:script:]配列の値を逆順にする
var vlist:Array=["青森","千葉","京都","宮崎"];
vlist.reverse();
trace(vlist);//出力:宮崎,京都,千葉,青森
(section03-01 Arrayクラスの配列から抜粋)

 配列の値の並びをストリング値にするには、toString()、join()のメソッドが利用できます。たとえば、["black","white","yellow"]というcolors配列があったときcolors.toString()は"black,white,yellow"という1つのストリングを作ります。toString()を実行しても元のcolors配列は変更されません。
 配列をストリングにする必要があるのは、配列の並びをテキストフィールドに表示するといった場合です。

[:script:]フィールドに配列の値を入れる
var colors:Array=["black","white","yellow"];
colors_fld.text=colors.toString();
fig03-01-01.jpg
 配列とストリングを連結するだけで、配列の値の並びは強制的にストリングに変換されます。元のcolors配列は変更されません。

[:script:]フィールドに配列の値を入れる
var colors:Array=["black","white","yellow"];
colors_fld.text="色は「"+colors+"」です。";
fig03-01-02.jpg
ストリングに変換する際に区切り文字を置換する
 join()は配列をストリングに変換する際に区切り文字を「,」ではなく指定の文字に置換します。次の例は区切りを「または」に置換しています。

[:script:]区切り文字を「または」に置換してストリングに変換する
var colors:Array=["黒","白","赤"];
var msg:String=colors.join("または");
trace(msg);//出力:黒または白または赤
 区切りを""にすれば、配列の値を1つのストリングに連結できます。

[:script:]区切り文字を取り除いたストリングに変換する
var colors:Array=["黒","白","赤"];
var msg:String=colors.join("");
trace(msg);//出力:黒白赤
(section03-01 Arrayクラスの配列から抜粋)

 配列の値を検索したい場合には、すべての値を総当たりでチェックしなければならない場合もありますが、単純に値が含まれているかどうかがわかればよい場合があります。そのような場合にはindexOf()、lastIndexOf()のメソッドが便利です。
 indexOf()は指定した検索開始位置から後ろへ検索して最初に見つかった位置を返します。検索開始位置を省略すると最初から探しします。開始位置をマイナスで指定すると後ろから位置を数えます。検索の結果見つからなかった場合には-1が返ってきます。

[:script:]配列を前から後ろへ検索する
var vlist:Array = new Array("a","x","b","a","x","c");
trace(vlist.indexOf("a",2));//出力:3
trace(vlist.indexOf("a",4));//出力:-1
//開始位置を省略
trace(vlist.indexOf("a"));//出力:0
//開始位置を後ろから数える
trace(vlist.indexOf("x",-3));//出力:4
補足:
2行目:"a"をインデックス番号2、つまり"b"の位置から後ろへ検索します。すると"b"の次の"a"が見つかります。この"a"はインデックス番号3なので3が返ります。
3行目:インデックス番号4の"x"の位置から"a"の検索を開始します。"x"より後ろに"a"はないので-1が返ります。
5行目:配列の先頭から"a"を検索します。先頭の"a"が見つかるので、インデックス番号0が返ります。
7行目:検索開始位置が-3なので、後ろから3個目の"a"から検索を開始します。検索方向は"a"から後ろ方向です。"a"の次の"x"が見つかります。この"x"のインデックス番号は4番です。

 lastIndexOf()は指定した検索開始位置から手前に検索して最初に見つかった位置を返します。検索開始位置を省略すると最後から探します。開始位置をマイナスで指定すると後ろから位置を数えます。検索の結果見つからなかった場合には-1が返ってきます。

[:script:]配列を後ろから前へ検索する
var vlist:Array=new Array("a","x","b","a","x","c");
trace(vlist.lastIndexOf("a",2));//出力:0
trace(vlist.lastIndexOf("a",4));//出力:3
//開始位置を省略
trace(vlist.lastIndexOf("a"));//出力:3
//開始位置を後ろから数える
trace(vlist.lastIndexOf("x",-3));//出力:1
補足:
後ろから検索しても、返ってくる値は前から数えるインデックス番号です。勘違いしやすいので注意してください。
2行目:インデックス番号2、つまり"b"の位置から前方向に"a"を検索します。先頭の"a"が見つかるので、インデックス番号0が返ります。
3行目:インデックス番号4、つまり後ろの"x"の位置から前方向へ"a"を検索します。すぐ左の"a"が見つかるので、インデックス番号3が返ります。
5行目:開始位置を省略すると最後から手前へ検索します。後ろの"a"が見つかるので、インデックス番号3が返ります。後ろから3個目ではなく、"a"のインデックス番号です。
7行目:後ろから3個目の"a"から前方向へ"x"を検索します。前から2個目の"x"が見つかるので、インデックス番号1が返ります。

 次のuniquePush()はnoListに同じ値が入っていなければ値を追加する関数です。引数で渡された値が配列に含まれていないかどうかをindexOf()で検索して確かめ、検索結果が-1のときに値をpush()しています。

[:script:]ユニークな値だけ配列に追加する
function uniquePush(tmplist:Array, v:int):void {
	//値が配列に含まれていないか検索する
	var index:int=tmplist.indexOf(v);
	if (index==-1) {
		//値を追加する
		tmplist.push(v);
	}
}
//配列に値を追加していく
var noList:Array=new Array(1,2,3);
uniquePush(noList,2);
uniquePush(noList,50);
uniquePush(noList,60);
uniquePush(noList,50);
trace(noList);//出力:1,2,3,50,60
(section03-01 Arrayクラスの配列から抜粋)

 concat()は複数の配列を連結して新しい配列を作るメソッドです。次の例は配列alist、blist、clistを連結して配列newlistを作っています。式を見た感じでは配列alistにblist、clistの値を追加する印象がありますが、この演算で配列alistの値は変化しません。concat()の引数は何個でもかまいません。

[:script:]配列を連結して新しい配列を作る
var alist:Array=new Array("a","b","c");
var blist:Array=new Array("m","n");
var clist:Array=new Array("x","y","z");
var newlist:Array=alist.concat(blist,clist);
trace(newlist);//出力:a,b,c,m,n,x,y,z

加茂君の初めての本が出版になりました。監修という形でお手伝いしましたが、彼のがんばりには脱帽です。その内容は・・・


最初にコンパイルエラー一覧、コンパイラ警告一覧、ランタイムエラー一覧が29ページあって、そこにはコード番号順にメッセージ本文が日本語と英語でリストになっています。このリストはそのままページインデックスの役目も果たします。
第1章「エラーの基礎知識」はその後です。エラーの基礎知識って?
個々のエラーの説明は続く第2章からです。第2章「コンパイルエラー」第3章「コンパイラ警告」第4章「ランタイムエラー」。どの章も結局エラーについてです。
そうそう、付録もあります。「付録A AS2からの移行」AS2からAS3への移行への変更点です。それが25ページの表になっています。これを守らないとAS2からAS3への移植でエラー続出です。


この本にはエラーメッセージのことしか書いてありません。それなのに375ページもあります。エラーはそんなにあるのか?これは罠なのか?

488337646X
ActionScript 3.0 エラーアーカイブス
コンパイルエラー・コンパイラ警告・ランタイムエラーの解法

加茂雄亮著/大重美幸監修

→■目次

萌え本です。こんな本をいったい誰が買うのだろう?
プログラム開発は、たとえ数行のスクリプトであってもエラーとの戦いです。では、プログラム開発者はエラーが嫌いかと言うと実はそうでもなくて、エラーを取り除くデバッグ作業が結構好き、楽しいという人は少なくないようです。むしろ、デバッグ作業を楽しめるようでなければプログラマに向いてないのかもしれません。デバッグ作業はプログラムと対話している楽しさがあり、エラーというボケにエラーメッセージという鋭いツッコミが入るという面白さじゃないですか?

・・・・
効率よくエラーを出し、エラーを潰す。そういった開発スキルを高めるには、出会ったエラーメッセージを漫然とながめスルーするのではなく、エラーメッセージが伝える意味を理解することが何よりも大事なのです。「エラーメッセージを解説しよう」という本書は、その意味において大きな意義があります。

Q.エラーが出るとヘコむ?
A.楽しいです。

(推薦文より抜粋)

(section03-01 Arrayクラスの配列から抜粋)

 配列は数値やストリングなどと違ってオブジェクトなので、配列を変数に代入するとリファレンス型の変数になります。たとえば、配列の入った変数alistを変数blistに代入したとき、どちらも同じ配列を参照しています。配列alist、blistに対して値の追加などの操作を行ったとき、片方の配列に操作した内容が両方に影響してしまいます。

[:script:]配列を複製したつもりでも同じ配列を参照している
var alist:Array=[1,2,3];
//blistにalistを代入する
var blist:Array=alist;
alist.push("x");//alistに"x"を追加
blist.push("y");//blistに"y"を追加
//どちらも同じ値になっている
trace(alist);//出力:1,2,3,x,y
trace(blist);//出力:1,2,3,x,y
 配列を複製したい場合にはslice()が利用できます。slice()の引数を省略するとslice(0)を実行した場合と同じになり、配列のすべての値を複製した新しい配列を作ることができます。

[:script:]配列を複製する
var alist:Array=[1,2,3];
//blistにalistを複製して代入する
var blist:Array=alist.slice();
alist.push("x");//alistに"x"を追加
blist.push("y");//blistに"y"を追加
//alistとblistは個別の配列になっている
trace(alist);//出力:1,2,3,x
trace(blist);//出力:1,2,3,y

正誤表20090908

|

■この訂正は初版のものです。補足の新規追加原稿も含んでいます。

p.37 本文下から3行目

誤:heikin3wを変数myTest
正:heikin3を変数myTest


p.52 本文2行目(言い回しの修正)

誤:次のいくつか代表的な
正:次にいくつかの代表的な


p.54 「関数の引数の値渡しと参照渡し」の1行目(言い回しの修正)

誤:プリミティブ型であるかリファレンス型にも
正:プリミティブ型なのかリファレンス型なのかにも


p.55 欄外に[:note:]を補足追加します。

[:note:]配列を複製する(p.109)


p.68 スクリプト 「caseの値を式で指定した場合」の行番号6と9

誤:6 case (a>=5 && a<=10) :
正:6 case (a>=5 && a<10) :
誤:9 case (a>10) :
正:9 case (a>=10) :


p.106  本文の下から5行目(言い回しの修正)

誤:undefinedの値になり
正:undefinedが追加され


p.107 本文5行目

誤:["red","yellow","black"]の配列になります。
正:["red","yellow","green","black"]の配列になります。


p.210 最終行に本文とスクリプトを補足追加

 また、あるクラスがDisplayObjectクラスを継承しているかどうかは、is演算子でもチェックできます。
[:script:]MovieClipクラスがDisplayObjectクラスを継承しているか調べる
1 var mc:MovieClip=new MovieClip();
2 trace(mc is DisplayObject);//出力:true


p.409 スクリプトの39行目コメント文

誤:読み込み完了イベントの配信
正:読み込みエラーイベントの配信

(section03-01 Arrayクラスの配列から抜粋)

 配列の一部を取り出すメソッドにはslice()とsplice()があります。どちらも取り出した値の配列を作ります。slice()では元の配列は変化しないのに対し、splice()の場合は抜き取った値が元の配列から取り除かれるという違いがあります。
 次の例はslice()を使って新しい配列を作り出しています。取り出す位置はslice(startIndex,endIndex)のように指定します。このとき、slice(1,4)ならば1〜3番目を取り出し、4番目を含まないので注意が必要です。
 次の例では配列allListから1〜3番目の値を複製して新しい配列selectListを作成します。配列のインデックスは0からカウントするので、1〜3番目は"b"、"c"、"d"になります。slice()で値を取り出しても元の配列allListの中身はそのままで変化していません。

[:script:]配列の1〜3番目の値を取り出す
var allList:Array=["a","b","c","d","e","f"];
var selectList:Array=allList.slice(1,4);
//取り出した配列
trace(selectList);//出力:b,c,d
//元の配列は変化しない
trace(allList);//出力:a,b,c,d,e,f
 slice()は2番目の引数を省略できます。slice(3)のように引数を1つだけ指定した場合は3番目(並びでは4個目)から最後までの値を指定したことになります。

[:script:]配列の3番目から最後までの値を取り出す
var allList:Array=["a","b","c","d","e","f"];
var selectList:Array=allList.slice(3);
trace(selectList);//出力:d,e,f
trace(allList);//出力:a,b,c,d,e,f
 引数をマイナスにすると末尾から個数を数えて取り出します。次の例は末尾から4個の値を取り出した配列を作ります。インデックス番号と違って1から数えるので注意してください。

[:script:]配列の後ろから4個の値を取り出す
var allList:Array=["a","b","c","d","e","f"];
var selectList:Array=allList.slice(-4);
trace(selectList);//出力:c,d,e,f
trace(allList);//出力:a,b,c,d,e,f

*初版ではsplice()の項に間違いがあります。訂正原稿を参照してください。
(section03-01 Arrayクラスの配列から抜粋)

 push()が配列の最後に値を追加するメソッドなのに対し、unshift()は配列の先頭に値を挿入し、挿入後の配列の長さを返すメソッドです。同時に複数の値を挿入することもできます。
 次の例は最初に["red","yellow"]のcolors配列を作り、色を先頭に挿入しています。挿入結果の値の並び順に注目してください。

[:script:]配列の先頭に値を挿入する
var colors:Array=new Array("red","yellow");
//値を先頭に挿入する
colors.unshift("black");
var cnt:uint=colors.unshift("white","gray");
trace(cnt);//出力:5
trace(colors);//出力:white,gray,black,red,yellow
 逆にshift()は配列の先頭の値を抜き取るメソッドです。shift()で値を抜き取ると先頭の値が配列から削除されます。
 次の例はcolorsから先頭の色を抜き取っています。firstColorには先頭の値の"red"が入り、元のcolorsからは先頭の値が削除されて["yellow","black"]の2色になります。

[:script:]配列の先頭の値を抜き取る
var colors:Array = new Array("red", "yellow", "black");
var firstColor:String = colors.shift();
//取り出した値
trace(firstColor);//出力:red
//元の配列からは先頭の値が取り除かれている
trace(colors);//出力:yellow,black
(section03-01 Arrayクラスの配列から抜粋)

 Arrayクラスには、配列に値を追加挿入したり、値を抜き取るといったメソッドがあります。push()は配列の最後に値を追加し、追加後の配列の長さを返すメソッドです。同時に複数の値を追加することもできます。
 次の例は最初に空のcolors配列を作り、色を末尾に追加しています。結果として["red","yellow","green","black"]の配列になります。

[:script:]配列に値を追加する
//空の配列を作る
var colors:Array = new Array();
//値を追加する
colors.push("red");
colors.push("yellow","green");
//pushした順に値が追加されている
trace(colors);//出力:red,yellow,green

var cnt:uint=colors.push("black");
//pushすると配列の長さが返ってくる
trace(cnt);//出力:4
trace(colors);//出力:red,yellow,green,black
 逆にpop()は配列の最後の値を抜き取るメソッドです。演算子[]で最後の値を取り出しても元の配列に入っている値はそのままですが、pop()で値を抜き取ると最後の値が配列から削除されます。
 次の例はcolorsから最後の色を抜き取っています。lastColorには最後の値の"black"が入り、元のcolorsからは最後の値が削除されて["red","yellow"]の2色になります。

[:script:]配列の最後の値を抜き取る
var colors:Array=["red","yellow","black"];
var lastColor:String=colors.pop();
//取り出した値
trace(lastColor);//出力:black
//元の配列からは最後の値が取り除かれている
trace(colors);//出力:red,yellow

 ActionScript 3.0 言語およびコンポーネントリファレンスでLoaderクラスの説明を見ると継承には次のように書いてあります。

継承:Loader→DisplayObjectContainer→InteractiveObject   →DisplayObject→EventDispatcher→Object

 これを見ると確かにLoaderクラスはDisplayObjectContainerクラスを継承しているので、MovieClipやSpriteなどと同じようにaddChild()を使って入れ子の表示オブジェクトを追加できるはずです。しかし実際にはLoaderが表示できるのは読み取り専用のcontantプロパティで参照できる表示オブジェクトだけです。
 その理由はコンポーネントリファレンスの説明の続きに書いてあります。そこには次のように書いてあります。

Loaderクラスの説明

Loader クラスは、継承する次のメソッドをオーバーライドします。これは、Loader オブジェクトが持つことができるのは 1 つの子表示オブジェクト、つまり読み込むオブジェクトに限られているためです。次のメソッドを呼び出すと例外がスローされます。メソッドは、addChild()、addChildAt()、removeChild()、removeChildAt() および setChildIndex() です。読み込まれた表示オブジェクトを削除するには、親の DisplayObjectContainer 子配列から Loader オブジェクトを削除する必要があります。

 p.225の表示リストの図でLoaderを二重枠にしていない理由はそういうわけでした。

fig07-02-06.jpg

まったく新しいAS3の世界!
694a.jpg
Adobe Flash CS4
詳細!ActionScript3.0入門ノート[完全改訂版](CD-ROM付)

楽しいActionScript。
新たなる1歩へと踏み出しましょう。
■内容は?→ 目次を見る
■評判は?→ 書評を読む
この本を書いたわけ

このアーカイブについて

このページには、2009年9月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2009年8月です。

次のアーカイブは2009年10月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

あわせて読みたいブログパーツ