本書は、Flash Player 10で備わった3次元座標表現を扱うクラスについておもに解説してきました。そして、それらのクラスの機能に焦点を当て、また手軽に試せるように、スクリプトはすべてフレームアクションでサンプルを書きました。けれども、とくにActionScript 3.0では、クラスを定義してスクリプトを組立てる人も多いでしょう。そこで、本章では、これまでご紹介したサンプルスクリプトのいくつかを、改めてクラスで構成してみます。
なお、本章の解説はクラス定義の基礎を習得されていることが前提となります。クラス定義についての基本を学ばれたい場合には、拙著『ActionScript 3.0プロフェッショナルガイド』などの解説書をお読みください。
○SPL-01 矩形のインスタンスを任意の平行四辺形に変換する
まずは、Matrixクラスにより、矩形のインスタンスを任意の平行四辺形に変換するサンプルです(再掲図03-017)。前掲スクリプト03-005をお題とします(図SPL-001)。
図03-017■ポイントをドラッグするとその座標に合わせて矩形のインスタンスが平行四辺形に変換される(再掲)
矩形のインスタンスの3つの角にあるポイントをドラッグすると、その座標に合わせてインスタンスが任意の平行四辺形に変換される。
|
●クラスをMovieClipシンボルに定義する
手始めに、メインタイムラインのフレームアクションとして書いたスクリプト03-005の中から矩形のインスタンスを変換する関数(xTransformPoints())は、その矩形のMovieClipシンボル自身に定義するクラスのメソッドとして切離します(図SPL-001)。
図SPL-001■3つの角のポイントの座標に合わせて矩形のインスタンスを変換する
矩形のインスタンスを変換する関数xTransformPoints()は、その矩形のMovieClipシンボル自身に定義するクラスのメソッドとして切離す。
|
そうすると、メインタイムラインのフレームアクションから関数xTransformPoints()がなくなります。そして、矩形のインスタンス(my_mc)のメソッドになる訳ですから、引数にはインスタンスが要らなくなり、つぎのようにインスタンスを参照して呼出すことになります(メソッド名はtransformPoints()とします)。
function xTransform():void {
var point0:Point = new Point(point0_mc.x,point0_mc.y);
var point1:Point = new Point(point1_mc.x,point1_mc.y);
var point2:Point = new Point(point2_mc.x,point2_mc.y);
// xTransformPoints(my_mc, point0, point1, point2);
my_mc.transformPoints(point0, point1, point2); // インスタンスのメソッドとして呼出す
}
|
矩形のMovieClipシンボルに定義するのは、この変換のメソッドひとつだけを備えたクラスです。クラス名はImageとします。カスタムクラスについてざっとおさらいしながら、順に書いていきましょう。
クラスは、MovieClipシンボルの[シンボルプロパティ]ダイアログボックスで設定します([ライブラリ]でシンボルをクリックして、右クリックまたはオプションポップアップメニューから[プロパティ]を選択)。[ActionScript用に書き出し]をチェックしたうえで、[クラス]にクラス名Imageを入力します。(図SPL-002)。
図SPL-002■[シンボルプロパティ]ダイアログボックスで[クラス]を設定
[ライブラリ]でシンボルをクリックして、右クリック(ショートカットメニュー)またはオプションポップアップメニューから[プロパティ]で[シンボルプロパティ]ダイアログボックスを開く。[ActionScript用に書き出し]をチェックしたうえで、[クラス]にImageを入力。
|
Tips SPL-001■クラス定義の自動生成
[シンボルプロパティ]ダイアログボックスに指定した[クラス]が定義されていないと、デフォルトではクラス定義が自動生成されます(図SPL-003)。カスタムクラスを後で定義するときや、コンストラクタでインスタンスを生成するだけの場合は、[OK]ボタンをクリックします。
図SPL-003■クラスの定義を自動生成する警告
クラスを後で定義するときや、コンストラクタのみのクラス定義でよい場合には[OK]。
|
|
矩形のMovieClipシンボルに設定するクラスImageは、後に全体の定義をスクリプトSPL-001として掲げます。カスタムクラスの定義は、つぎのような記述で始めます。
- package {
- import flash.display.Sprite;
- public class Image extends Sprite {
- public function Image() {} // コンストラクタメソッド
- }
- }
|
第1に、package定義キーワードに続けて、必要があればパッケージを定めます。今回はクラス定義ファイルをFlashムービー(.fla)ファイルと同階層に保存しますので、指定はありません。第2に、class定義キーワードの後に、クラス名を書きます。シンボルに設定するクラスは、アクセス制御の属性をpublicとします。第3に、extends定義キーワードでスーパークラスを継承します。タイムライン(複数フレーム)が使われていればMovieClipクラス、そうでなければSpriteクラスを指定します。そのクラスをimport宣言しておくことも必要です。そして第4に、コンストラクタメソッドの定義です。メソッドの名前は、クラスと同じです。コンストラクタメソッドのアクセス制御属性はpublic以外使えません。
ActionScript(.as)ファイルは、前述のとおりFlashムービーファイルと同じ階層に、クラス名をつけて(Image.asとして)保存します。
Tips SPL-002■クラス定義で省略できる記述
まず、本文に述べたとおり、「コンストラクタメソッドのアクセス制御属性はpublic以外使えません」。そのため、アクセス制御の属性を省くと、デフォルトでpublic属性が用いられたものとして扱われます。それに対して、classキーワードによるクラスの定義については、デフォルトがinternal属性になります。したがって、クラスImageの定義では、public属性は必ず書添えなければなりません。
つぎに、Imageクラスは、コンストラクタメソッドに引数もステートメントもありません。このような空のコンストラクタは、記述しなくても差支えはありません。なぜなら、「クラスでコンストラクタメソッドを定義しなかった場合、コンパイラが自動的に空のコンストラクタを作成します」(ヘルプ[ActionScript 3.0のプログラミング] > [ActionScriptのオブジェクト指向プログラミング] > [クラス] > [メソッド]「コンストラクタメソッド」)。
[*筆者用参考]「クラスのコードの作成」。
|
このクラスImageに、あとはvar宣言でプロパティを、function定義でメソッドを書き加えていけばよいでしょう。今回、プロパティはとくに要りません。そして、メソッドは、フレームアクション(前掲図SPL-001)から移行する関数ひとつだけです。
- package {
- import flash.display.Sprite;
- import flash.geom.Matrix;
- import flash.geom.Point;
- public class Image extends Sprite {
- public function Image() {}
- // internal function transformPoints(point0:Point, point1:Point, point2:Point):void {
public function transformPoints(point0:Point, point1:Point, point2:Point):void {
- var myMatrix:Matrix = new Matrix();
- transform.matrix = myMatrix;
- var nWidth:Number = width;
- var nHeight:Number = height;
- var point1_0:Point = point0.subtract(point1);
- var point1_2:Point = point2.subtract(point1);
- myMatrix.a = (point1_0.x) / nWidth;
- myMatrix.b = (point1_0.y) / nWidth;
- myMatrix.c = (point1_2.x) / nHeight;
- myMatrix.d = (point1_2.y) / nHeight;
- myMatrix.tx = point1.x;
- myMatrix.ty = point1.y;
- transform.matrix = myMatrix;
- }
- }
- }
|
メソッドがフレームアクションと異なるのは、引数にインスタンスを受取るのでなく、インスタンス自らを参照して座標変換することです(スクリプト第7〜21行目)。これで、前述のとおり、以下のフレームアクションにより、矩形のインスタンスを任意の平行四辺形に変換できます。なお、クラスImageのスクリプト第7行目は、メソッドのアクセス制御の属性を、フレームアクションから呼出せるようにpublicとしています。しかし、最終的には、コメントアウトされているinternal属性にします。
function xTransform():void {
var point0:Point = new Point(point0_mc.x,point0_mc.y);
var point1:Point = new Point(point1_mc.x,point1_mc.y);
var point2:Point = new Point(point2_mc.x,point2_mc.y);
my_mc.transformPoints(point0, point1, point2);
}
|
[ムービープレビュー]で、矩形のMovieClipシンボルに設定したクラスImageが正しく動作することを確かめましょう。それが済んだら、メインタイムラインのフレームアクションとポイントのMovieClipシンボルのフレームアクションも、それぞれクラスとして定義します。クラスImageも含めた3つのクラスは、すべてFlashムービーファイルと同じ場所に保存します。そうすると、クラスImageのメソッドtransformPoints()は、アクセス制御の属性を同じパッケージ内からアクセスできるinternalで指定できます(スクリプトSPL-001)。
スクリプトSPL-001■矩形のMovieClipシンボルに設定するクラスImageの定義
// ActionScript 3.0クラス定義ファイル: Image.as
// 矩形のMovieClipシンボルに設定
- package {
- import flash.display.Sprite;
- import flash.geom.Matrix;
- import flash.geom.Point;
- public class Image extends Sprite {
- public function Image() {}
- internal function transformPoints(point0:Point, point1:Point, point2:Point):void {
- var myMatrix:Matrix = new Matrix();
- transform.matrix = myMatrix;
- var nWidth:Number = width;
- var nHeight:Number = height;
- var point1_0:Point = point0.subtract(point1);
- var point1_2:Point = point2.subtract(point1);
- myMatrix.a = (point1_0.x) / nWidth;
- myMatrix.b = (point1_0.y) / nWidth;
- myMatrix.c = (point1_2.x) / nHeight;
- myMatrix.d = (point1_2.y) / nHeight;
- myMatrix.tx = point1.x;
- myMatrix.ty = point1.y;
- transform.matrix = myMatrix;
- }
- }
- }
|
●ふたつのクラスをコールバックで結ぶ
メインタイムラインのフレームアクションは、クラスMainとして[プロパティ]インスペクタでドキュメントクラスに設定します(図SPL-004)。ドキュメントクラスは、メインタイムラインに設定されるクラスです。Mainクラスには、もとのフレームアクションをほぼそのまま定義することもできます。けれど、ふたつ設計上の変更を加えることにしましょう。
図SPL-004■[プロパティ]インスペクタでドキュメントクラスを設定
メインタイムラインをクリックして、[プロパティ]インスペクタで[クラス]にドキュメントクラスを設定する。
|
第1に、タイムラインには何も置かず、矩形およびドラッグするポイントのインスタンスは動的に生成します。第2は、ポイントのインスタンスからクラスMainのメソッドに、どのようにアクセスさせるかです。アクセス制御の属性をpublicまたはinternalとすれば、単純に呼出せます。けれども、メソッドが呼出せるインスンスタンを限定する手法として、コールバックを使ってみます。
[*筆者用参考]「Event model versus callbacks」。
- package {
- import flash.display.Sprite;
- import flash.geom.Point;
- public class Main extends Sprite {
- private var my_mc:Image = new Image();
- private var point0_mc:DragPoint = new DragPoint(transformImage);
- private var point1_mc:DragPoint = new DragPoint(transformImage);
- private var point2_mc:DragPoint = new DragPoint(transformImage);
- private function transformImage():void {
- var point0:Point = new Point(point0_mc.x,point0_mc.y);
- var point1:Point = new Point(point1_mc.x,point1_mc.y);
- var point2:Point = new Point(point2_mc.x,point2_mc.y);
- my_mc.transformPoints(point0, point1, point2);
- }
- }
- }
|
まず、ドラッグするポイントのインスタンスから呼出すコールバックのメソッドtransformImage()は、アクセス制御の属性をprivateにします(スクリプト第27行目)。つまり、原則としてこのメソッドは、クラスMainの外からは呼出せません。
そこでつぎに、ポイントのMovieClipシンボルに設定するクラスDragPointを定義して、そのコンストラクタメソッドにコールバックのメソッドtransformImage()を引数として渡します(スクリプト第6〜8行目)。これにより、コールバックを渡されたDragPointインスタンスだけがクラスMainのprivateなコールバックメソッドを呼出せるようになります。
あとは、矩形およびドラッグするポイントのインスタンスをタイムラインに動的に生成すれば、クラスMainの処理は完成です(スクリプトSPL-002)。矩形のインスタンスは、基準点が左上角にありますので、幅と高さの1/2をそれぞれ調整してステージの中央に置き、ポイントのインスタンスはその右上と左上、および左下の3つの角に配置します。
スクリプトSPL-002■ポイントのドラッグで矩形のインスタンスを変換するドキュメントクラスMainの定義
// ActionScript 3.0クラス定義ファイル: Main.as
// ドキュメントクラスに設定
- package {
- import flash.display.Sprite;
- import flash.geom.Point;
- public class Main extends Sprite {
- private var my_mc:Image = new Image();
- private var point0_mc:DragPoint = new DragPoint(transformImage);
- private var point1_mc:DragPoint = new DragPoint(transformImage);
- private var point2_mc:DragPoint = new DragPoint(transformImage);
- private var centerX:Number = stage.stageWidth / 2;
- private var centerY:Number = stage.stageHeight / 2;
- private var offsetX:Number = my_mc.width / 2;
- private var offsetY:Number = my_mc.height / 2;
- public function Main() {
- my_mc.x = centerX - offsetX;
- my_mc.y = centerY - offsetY;
- point0_mc.x = centerX + offsetX;
- point0_mc.y = centerY - offsetY;
- point1_mc.x = centerX - offsetX;
- point1_mc.y = centerY - offsetY;
- point2_mc.x = centerX - offsetX;
- point2_mc.y = centerY + offsetY;
- addChild(my_mc);
- addChild(point0_mc);
- addChild(point1_mc);
- addChild(point2_mc);
- }
- private function transformImage():void {
- var point0:Point = new Point(point0_mc.x,point0_mc.y);
- var point1:Point = new Point(point1_mc.x,point1_mc.y);
- var point2:Point = new Point(point2_mc.x,point2_mc.y);
- my_mc.transformPoints(point0, point1, point2);
- }
- }
- }
|
ドラッグするポイントのMovieClipシンボル(Point)には、クラスDragPointを定義します(図SPL-005)。前述のとおり、コンストラクタメソッドがコールバックの関数を受取り、インスタンスがドラッグされている間その関数を呼出し続けます(スクリプトSPL-003)。
図SPL-005■ドラッグするポイントのMovieClipシンボルにクラスを定義
DisplayObjectをベース型とするVectorインスタンスには、Objectインスタンスはエレメントとして加えられない。
|
スクリプトSPL-003■ドラッグするポイントのMovieClipシンボルに設定するクラスDragPointの定義
// ActionScript 3.0クラス定義ファイル: DragPoint.as
// ドラッグするポイントのMovieClipシンボルに設定
- package {
- import flash.display.Sprite;
- import flash.events.Event;
- import flash.events.MouseEvent;
- public class DragPoint extends Sprite {
- private var dragging:Function;
- public function DragPoint(callback:Function) {
- buttonMode = true;
- addEventListener(MouseEvent.MOUSE_DOWN, press);
- dragging = callback;
- }
- private function press(eventObject:MouseEvent):void {
- stage.addEventListener(MouseEvent.MOUSE_UP, release);
- addEventListener(Event.ENTER_FRAME, update);
- startDrag();
- }
- private function release(eventObject:MouseEvent):void {
- stage.removeEventListener(MouseEvent.MOUSE_UP, release);
- removeEventListener(Event.ENTER_FRAME, update);
- stopDrag();
- update();
- }
- private function update(eventObject:Event=null):void {
- if (dragging is Function) {
- dragging();
- }
- }
- }
- }
|
コンストラクタメソッドDragPoint()は、コールバック関数を引数として受取り、それをプロパティ(dragging)にもちます(スクリプト第7〜11行目)。そして、インスタンスがドラッグされている間呼出されるリスナーメソッドupdate()から、そのコールバック関数を呼出しています(スクリプト第23〜27行目)。なお、コールバックを呼出す前にifステートメントで、念のためプロパティに関数が設定されているかどうかをis演算子で確かめています。
これで、3つのクラス定義はでき上がりました。ドラッグするポイントのインスタンスの位置に合わせて、矩形のインスタンスが変換されます。
[Prev/Next]
作成者: 野中文雄
作成日: 2010年4月11日