(メインページへ)
4.ActionScript2.0のオブジェクト指向プログラミング/4.1 ActionScript2.0のクラス定義の基礎知識

4.1 ActionScript2.0のクラス定義の基礎知識

クラスとは何か?

プログラムとは一連の作業の手続きを書いたものです。そして、決まって行う手続きは1つの作業としてルーチン化してしまい名前を付けて呼ぶことにします。これは日常生活の中にも見ることができます。たとえば「コーヒーを煎れる」という行為の中には何段階かの作業がありますが、「コーヒーを煎れる」という1つの「命令」で指示することができます。このような命令がたくさんたまってくると、次からも利用できるようにまとめて整理しておこうということになります。簡単に言えば、それが「クラス」です。
逆に言えば、クラスには便利な命令が入っているので、クラスから命令を引き出して使えばよいという考え方になります。しかし、料理はレストランで注文し給油はガソリンスタンドで行うように、クラスにも専門分野があります。たくさんある命令は分類されていくつかのクラスに整理されています。それがMathクラスであったり、Dateクラスであったりするわけです。
ActionScriptで利用できるクラスは、あらかじめ用意してあるビルトインクラスとユーザーが定義して作るカスタムクラスの2つに大きく分類できます。いつでもすぐに使えるという意味ではビルトインクラスが便利ですが、効率のよいプログラミングを行うためにはカスタムクラスを作ることを避けられません。
ビルトインクラスには、ECMAScript4に準拠したコアクラスとFlash Player固有のクラス(メディアクラス、ムービークラス、クライアント・サーバークラス、オーサリングクラスなど)が含まれています。カスタムクラスは、ActionScript1でもActionScript2.0でも作ることができますが、手法が違うだけで同じように動作します。ただ、今後のためにはActionScript2.0のクラス定義の方法を学ぶほうがよいことから、本書ではActionScript1.0のクラス定義については触れません。

個別リンク | コメント (0) | トラックバック

クラス定義とインスタンス

オブジェクト指向プログラミングやクラス定義の説明の前に「オブジェクトとは何か?」「クラス定義とは何か?」という話をしておきましょう。
次の図はredCarオブジェクトを示したものです。redCarオブジェクトにはcolorとtypeの2つのプロパティがあり、それぞれ"red"と"at"という値をもっています。さらにredCarオブジェクトにはrun()というメソッドもあります。run()が何を行うメソッドなのかはこれだけではわかりませんが、名前からするとrun()を実行するとredCarが走るメソッドだろうと想像できます。


図4-1-1 redCarオブジェクトには2つのプロパティと1つのメソッドがあります。

次の図はblueCarオブジェクトです。redCarオブジェクトと同様にcolorとtypeの2つのプロパティとrun()メソッドがあります。


図4-1-2 blueCarオブジェクトにも2つのプロパティと1つのメソッドがあります。

次のcardもオブジェクトです。カードはデータつまりプロパティだけという作りも考えられますが、カードを表示したり、urlをリンクするといった機能をcardオブジェクト自身のメソッドとして組み込むやりかたもあります。ここではプロパティとメソッドを両方持ったcardオブジェクトになっています。

図4-1-3 cardオブジェクト

このようにオブジェクトはプロパティ(属性)の値とメソッド(関数)を自分自身でもっています。これを図に示すと次にようになります。

図4-1-4 オブジェクトとは、プロパティ(属性)の値とメソッド(関数)を自分自身でもったものをいいます。


では、どうやってこのような構造を持ったオブジェクトを作るのでしょうか。先のredCarオブジェクトとblueCarオブジェクトはプロパティの値が違うだけでプロパティの項目やメソッドは同じである点に注目してください。そこで次のようにオブジェクトの仕様を定義したものを用意し、それに基づいてredCarとblueCarのオブジェクトを作れば、オブジェクトを効率よく作れることがわかります。これは車を作るにはまず車の設計図を用意し、あとはそれに基づいて車を大量生産するのに似ています。
ここで、オブジェクトの仕様を「クラス」と呼び、クラスに基づいて作られたオブジェクトを「インスタンス」と呼びます。すなわち、Carクラスを定義して、redCarオブジェクトとblueCarオブジェクトというインスタンスを作ります。

図4-1-5 Carクラスを定義して、redCarとblueCarのインスタンスを作ります。


クラス定義からインスタンスを作るという図を一般化して示すと次のようになります。用語としては、「クラスからインスタンスを作る」、「クラスからインスタンスを生成する」といった言い回しが使われています。なお、プロパティとメソッドのことをメンバーと呼びます。後述するように、メンバーにはクラスメンバーとインスタンスメンバーがあります。

図4-1-6 オブジェクトの仕様を決めた「クラス定義」を用意し、それに基づいて「インスタンス」を生成します。


note:
Flashではライブラリからシンボルをステージに配置したものもインスタンスと呼びますが、これはMovieClipクラスやButtonクラスなどからインスタンスを作る行為を手作業で行っていると言えます。

個別リンク | コメント (0) | トラックバック

クラス定義ファイルとクラス定義の構造

ActionScript2.0のクラス定義は、外部ActionScriptファイル(ASファイル)で行います。Flash MX Professional版の場合はクラス定義ファイルの作成とアクションウインドウのスクリプト編集機能を利用できますが、スタンダード版にはその機能がありません。クラス定義ファイルは拡張子が.asのテキストファイルなので、一般のテキストエディタで作成編集ができます。
クラス定義ファイルのファイル名は、これから定義するクラスと同名でなければなりません。たとえば、MyClassというクラスを定義する場合にはMyClass.asファイルを作ります
クラス定義ファイルの構造は次のようになります。プロパティは変数で定義して値を保存しますが、次の構造にはプロパティが書いてありません。プロパティについては後述します。


クラス定義ファイルの構造:
class クラス名{
 //コンストラクタ関数
function クラス名() {
}
 //メソッド
function メソッド名() {
}
 //関数
function 関数名() {
return(戻り値);
}
}


ここでのメソッドと関数の違いはreturnで値を戻すかどうかだけの違いです。両者を区別せずにどちらもメソッドあるいは関数と呼ぶこともあります。ただし、関数の戻り値のデータ型を指定した場合には、returnを入れないとコンパイルエラーになります。
クラス名はクラス定義ファイル名と同じにします。名前の大文字小文字を区別する点に注意してください。一般的にクラス名は大文字から始めます。クラス定義の内容はすべてclassステートメントのブロック内に書きます。たとえば、MyClassクラスのクラス定義ファイルは次のようになります。このクラスにはコンストラクタ関数だけで、メソッドや関数はありません。つまり、インスタンスを作るだけで何もしないクラスです。プロパティも設定していません。

sample→ ex04-01/my1stClassフォルダ

MyClassクラスのクラス定義:MyClass.as
class MyClass {
//コンストラクタ関数 ←クラス名と同じ
function MyClass() {
}
}

個別リンク | コメント (0) | トラックバック

コンストラクタ関数の省略

コンストラクタ(constructor;建設者)関数ではプロパティの初期化などを行いますが、先の例のMyClassクラスのように何もしないコンストラクタ関数もあります。何もしないコンストラクタ関数は省略が可能です。また、関数という呼び方をしますが、値をreturnで戻す必要はありません。つまり、もっとも単純なクラス定義のスクリプトは次のように空のclassブロックだけになります。

もっとも単純なクラス定義:MyClass.as
class MyClass {
//コンストラクタ関数は省略
}

個別リンク | コメント (0) | トラックバック

クラス定義からインスタンスを作る

クラス定義したクラスのインスタンスを作る方法は、ビルトインクラスのインスタンスを作る場合と基本的には同じです。先のMyClassクラス定義からmyObjインスタンスを作るスクリプトは次のとおりです。myObjインスタンスのデータ型はMyClassになります。すなわち、クラス定義には新しいデータ型を定義するという側面があることも理解できます。

sample→ ex04-01/my1stClassフォルダ

//MyClassクラスのインスタンスを作る
var myObj:MyClass = new MyClass();
//myObjを調べる
trace(typeof myObj); // 出力→ object

このとき、このFlashムービーはクラス定義ファイルMyClass.asファイルと同じ階層に作ります。Flashムービーと別の階層にあるクラス定義ファイルを利用するには、クラスパスを指定しなければなりません(クラスパス→p.??)。

note:
Flashムービーをパブリッシュするとクラス定義ファイルのスクリプトはムービー内に取り込まれてしまうので、配布の際にクラス定義ファイルを添付する必要はありません。

個別リンク | コメント (0) | トラックバック

メソッドとプロパティ

クラス定義のもう少し具体的な例として、メンバーすなわちメソッドやプロパティをもったクラスを定義してみましょう。メンバーにはクラスメンバーとインスタンスメンバーがありますが、ここではインスタンスメンバーだけを使っています。両者の違いとクラスメンバーについては改めて説明します(クラスメンバーとインスタンスメンバー→p.??)。
次のMyClass01クラス定義には、プロパティmcとcircleメソッドが定義してあります。mcは操作対象となるムービークリップインスタンスの参照でクラスからインスタンスを作る際に引数から受け取って値を入れます。スクリプトで示すようにプロパティはコンストラクタ関数より前にvarで宣言します。circleメソッドは引数で指定したxy座標を中心とする半径rの円周上を回転角度dずつインスタンスを移動させるメソッドです。インスタンスは円周に沿った座標移動と同時に円の中心点を向くように自転します。

sample→ex04-01/MyClass01フォルダ

クラス定義ファイル:MyClass01.as
//MyClass01クラス
class MyClass01 {
//プロパティ
var mc:MovieClip;
//コンストラクタ
function MyClass01(target:MovieClip) {
mc = target;
}
//常に中心(x,y)を向くように円周を回る
function circle(x:Number, y:Number, r:Number, d:Number):Void {
//d度ずつ回転
mc._rotation += d;
var rad = mc._rotation * Math.PI / 180;
//中心座標(x,y)、半径rの円のradラジアン回転した点の座標
mc._x = x + r * Math.cos(rad);
mc._y = y + r * Math.sin(rad);
}
}

次のムービーでは、このMyClass01クラスを使ってムービークリップインスタンスのアニメーションを行っています。ステージには正方形のcenter_mcと長方形のbar_mcの2つのインスタンスがあります。ムービーをパブリッシュして確認するとbar_mcを引数としてMyClass01クラスのbarObjが作られるので、barObjのmcプロパティの値がbar_mcになります。
フレームが進むたびにbar_mcインスタンスのonEnterFrameイベントハンドラが実行されるので、barObjのcircle()メソッドが実行されてcenter_mcの周りをbar_mcが回ります。

フレームアクション:methodTest2.fla
//MyClass01クラスからインスタンスbarObjを作る
var barObj:MyClass01 = new MyClass01(bar_mc);
//毎フレームに実行
bar_mc.onEnterFrame = function() {
var x = center_mc._x;
var y = center_mc._y;
var r = 100;
var d = 10;
//barObjインスタンスのcircle()メソッドを実行する
barObj.circle(x, y, r, d);
};


図4-1-7 center_mcを円の中心としてその周りをbar_mcが回ります。

さらにcenter_mcもcircle()メソッドで動くようにすると、bar_mcの動きは公転する地球の周りを月が回るような動きになります。利用するクラス定義ファイルは同じなのでフレームアクションだけを書き換えます。

フレームアクション:methodTest3.fla
//インスタンスの生成
var centerObj:MyClass01 = new MyClass01(center_mc);
var barObj:MyClass01 = new MyClass01(bar_mc);
//円を描くようにcenter_mcを動かす
center_mc.onEnterFrame = function() {
var x = Stage.width / 2;
var y = Stage.height / 2;
var r = 100;
var d = 5;
var centerObj.circle(x, y, r, d);
};
//center_mcの周りを回る
bar_mc.onEnterFrame = function() {
var x = center_mc._x;
var y = center_mc._y;
var r = 100;
var d = 10;
barObj.circle(x, y, r, d);
};

図4-1-8 円を描いて回るcenter_mcの周りをbar_mcが回ります。どちらもMyClass01()クラスのcircle()メソッドを使っています。

なお、Windows版でムービープレビューを行った場合にはcenter_mcがステージからはみだした位置で円を描きますが、ブラウザまたはFlash Playerでswfを再生すればステージの中央を中心点として円を描きます。

個別リンク | コメント (0) | トラックバック

プロパティのインライン初期化

プロパティの初期値をコンストラクタ関数の引数で決めるのではなく、プロパティの宣言と同時に初期化することもできます。これをインライン初期化と呼びます。たとえば、先のMyClass01クラスの円の半径と回転角度をプロパティとして決定してしまうならば、クラス定義は次のようになります。

sample→ex04-01/MyClass02フォルダ

クラス定義ファイル:MyClass02.as
//MyClass02クラス
class MyClass02 {
//プロパティのインライン初期化
var r:Number = 100;//円の半径
var d:Number = 10;//回転速度
var mc:MovieClip;//対象のムービークリップインスタンス
//コンストラクタ
function MyClass02(target:MovieClip) {
mc = target;
}
//常に中心を向くように円周を回る
function circle(x:Number, y:Number):Void {
//d度ずつ回転
mc._rotation += d;
var rad = mc._rotation * Math.PI / 180;
//中心座標(x,y)、半径rの円のradラジアン回転した点の座標
mc._x = x + r * Math.cos(rad);
mc._y = y + r * Math.sin(rad);
}
}

個別リンク | コメント (0) | トラックバック

クラスパス

クラス定義ファイルを使うには、Flashのコンパイラが探せるようにクラス定義ファイルを保存してあるディレクトリを登録しておく必要があります。このクラス定義ファイルを保存してあるディレクトリの一覧をクラスパスと呼びます。
クラスパスにはドキュメントレベルのクラスパスとグローバルなクラスパスの2つがあります。コンパイラは最初にドキュメントレベルのクラスパスを検索し、そこで見つからなければグローバルなクラスパスを検索します。ドキュメントレベルのクラスパスはパブリッシュ設定のFlashタブにある[ActionScript設定...]で設定します。

図4-1-9 ドキュメントレベルのクラスパスは、パブリッシュ設定のFlashタブにある[ActionScript設定...]で設定します。初期値は空になってます。

初期値の設定ではドキュメントレベルのクラスパスは空なので、通常はグローバルなクラスパスを検索します。グローバルなクラスパスは編集メニューの環境設定のActionScript設定にある[ActionScript2.0設定...]で設定します。初期値ではクラスパスが2つ設定してあり、その1つはドット(.)すなわち、現在のドキュメントを保存しているフォルダになっています。したがって、クラス定義ファイルとFlashムービーファイルを同じフォルダに保存すれば、クラス名だけでクラス定義ファイルを読み込むことができるわけです。


図4-1-10 グローバルなクラスパスは、環境設定のActionScript設定にある[ActionScript2.0設定...]で設定します。


もう1つのクラスパスは、Windowsでは各ユーザーのアプリケーションフォルダのMacromedia/Flash MX 2004/ja/Classesフォルダ、Mac OSXでは各ユーザーのLibrary/Application Support/Macromedia/Flash MX 2004/ja/Configurarion/Classesフォルダになっています。このクラスパスには標準のActionScript2.0のクラス定義ファイル(クラスライブラリ)があります。

個別リンク | コメント (0) | トラックバック

パッケージの利用

クラスパスで指定してあるディレクトリよりも下ならば、クラス定義ファイルをフォルダにまとめて入れておくことができます。このときのフォルダのパス(サブディレクトリ)をパッケージと呼びます。パッケージを使う場合には、クラス定義およびインスタンスを生成する際にクラスパスからのディレクトリ階層、すなわちパッケージ名を指定します。
次の例では、現在のFlashムービーファイルpackageSample.flaの階層にpetsフォルダがあり、その中にHana.asとTaro.asの2つのクラス定義ファイルが入っています。

sample→ex-04/packageフォルダ

packageSample.fla
petsフォルダ
 ├ Hana.as
 └ Taro.as

この場合のにHanaクラスのクラス定義ファイルは次のようになります。クラス名にパッケージ名を付けた完全修飾名でクラス名を指定しなければならない点に注意してください。


クラス定義ファイル:pets/Hana.as
//パッケージ名に続けてクラス名を書く
class pets.Hana {
//コンストラクタ
function Hana() {
}
//関数
function nakigoe():String{
return "ニャー";
}
}


同様にTaroクラスのクラス定義ファイルは次のようになります。

クラス定義ファイル:pets/Taro.as
//パッケージ名に続けてクラス名を書く
class pets.Taro {
//コンストラクタ
function Taro() {
}
//関数
function nakigoe():String {
return "ワン";
}
}

この2つのクラス定義ファイルからインスタンスを作り、それぞれのクラスのnakigoe()関数をテストするスクリプトは次のようになります。インスタンスをnew演算子で作る際にもパッケージ名に続いてクラス名を指定します。インスタンスを入れる変数のデータ型にもパッケージ名とクラス名を指定しなければならない点に注意してください。

フレームアクション:packageSample.fla
//Hanaクラスのインスタンスを作る
var hanaObj:pets.Hana = new pets.Hana();
//Taroクラスのインスタンスを作る
var taroObj:pets.Taro = new pets.Taro();
//関数を実行する
var naki_hana = hanaObj.nakigoe();
var naki_taro = taroObj.nakigoe();
trace("hanaは、" + naki_hana); // 出力→ hanaは、ニャー
trace("taroは、" + naki_taro); // 出力→ taroは、ワン

個別リンク | コメント (0) | トラックバック

importの利用

クラスを指定するたびにパッケージ名を指定するのでは、複数のクラス定義ファイルを利用したり、パッケージ名が長い時にスクリプトが読みにくくなります。
importキーワードを使えば、使用するクラス定義ファイルが入っているパッケージ全体を前もって読み込んでおくことができ、クラス定義ファイルを呼び出すときにはクラス名だけで呼び出せるようになります。
importはクラス定義ファイルの中だけでなく、フレームアクションでも利用できます。importをフレームアクションで使用した場合は、importが有効な範囲はそれを呼び出している現在のスクリプトにのみ適用されます。別のスクリプトに移った場合には再びimportを実行しなければなりません。
次の例は、あらかじめ2つのクラス定義ファイルをimportしているので、それ以降でクラス名を指すときにはパッケージ名が必要ありません。

フレームアクション:
//利用するクラスファイル定義をあらかじめimportしておく
import pets.Hana;
import pets.Taro;
//Hanaクラスのインスタンスを作る
var hanaObj:Hana = new Hana();
//Taroクラスのインスタンスを作る
var taroObj:Taro = new Taro();

同じパッケージ内にあるクラス定義ファイルを指定する場合にはワイルドカードの*が利用できます。pets.*のようにすれば、petsフォルダにあるすべてのクラス定義ファイルを読み込むことができます。この場合、実際に読み込まれるのは参照されたファイルだけなので、利用しないファイルまで読み込まれてファイルサイズが肥大化する心配はありません。

sample→ ex04-01/importフォルダ

フレームアクション:
import pets.*;
//Hanaクラスのインスタンスを作る
var hanaObj:Hana = new Hana();
//Taroクラスのインスタンスを作る
var taroObj:Taro = new Taro();

個別リンク | コメント (0) | トラックバック