前回の第20回 はクラスMyTimerに修正を加えて、public属性のメソッドgetElapsedTime()がMyTimerInfoインスタンスを返すようにした(前回のサンプルファイルは、2ページ からダウンロードできる) 。MyTimerInfoクラスには時分秒ミリ秒をそれぞれ納めるint型のインスタンスプロパティが宣言され、数値でなければ設定できない(図1 ) 。これらのプロパティを、もっときめ細かく管理できないだろうか。これが今回のテーマである。
図1 int型のプロパティに文字列を設定するとコンパイルエラーになるプロパティを設定するメソッドの定義 たとえば、MyTimerInfoインスタンスのsecondsプロパティに、整数150を代入してみよう。データ型は正しいので、そのまま150が設定される(図2 ) 。しかし、時間は60秒につき1分繰上がるのだから、できればminutesプロパティに120秒分の2分が加算され、secondsプロパティは30になってほしい。図2 60秒以上の値をプロパティsecondsに設定してもminutesに繰上がらないプロパティsecondsの値をminutesに繰上げるには、設定のためのメソッドをMyTimerInfoクラスに用意することが考えられる。secondsプロパティを設定するメソッドは、クラス MyTimerInfo(前回のスクリプト2 )にたとえばsetSeconds()としてつぎのように定義すればよい(他のプロパティは一旦脇に置く) 。// ActionScript 3.0クラス定義ファイル: MyTimerInfo.aspackage { public class MyTimerInfo { public var milliseconds:int; public var seconds:int; public var minutes:int; public var hours:int; public function MyTimerInfo(nMilliseconds:Number=0) { setTime(nMilliseconds); }public function setSeconds (nSeconds:Number) { // 追加 setTime(nSeconds*1000); } private function setTime(nTime:Number):void { milliseconds = nTime % 1000; nTime = Math.floor(nTime / 1000); seconds = nTime % 60; nTime = Math.floor(nTime / 60); minutes = nTime % 60; hours = Math.floor(nTime / 60); } }} MyTimerInfoインスタンス(oElapsedTime)に対して、このsetSeconds()により設定値の秒数を渡せば、60秒ごとに1分がminutesプロパティに繰上がる。たとえば、setSeconds()メソッドの引数に150秒を渡せば、プロパティminutesに2分が、secondsに30秒が設定される(図3 ) 。図3 プロパティsecondsに設定した値は60秒ごとに1分がminutesに繰上がるget/setアクセサメソッド 前項『プロパティを設定するメソッドの定義』に述べたとおり、メソッドを定義すればプロパティに対して単にデータ型の指定だけでなく、値の範囲を限定したり、他のプロパティの値と関連づけることができる。しかし、値を設定するという操作は、プロパティの方が端的でわかりやすい。ActionScript 3.0には、プロパティと同じアクセスの仕方で呼出せる特別なメソッドがある。それがgetおよびsetアクセサメソッドだ。getおよびsetアクセサメソッドは、メソッドにgetおよびset定義キーワードを添えて、以下のように同じメソッド名で定義する。アクセサメソッドにはpublic属性を指定しつつ、内部的に用いるプロパティはprivateとするのが基本だ。【get/setアクセサメソッドの定義】 private var プロパティ:データ型;public function get アクセサメソッド():データ型 { return プロパティ;}public function set アクセサメソッド(引数:データ型):void { プロパティ = 引数;}getとsetのアクセサメソッドには、プロパティと同じようにアクセスできる。つまり、MyTimerInfoクラスに秒数のprivateプロパティを_secondsで宣言し、getおよびsetアクセサメソッドをsecondsとして以下のように定義し直す(ここでも他のプロパティは一旦脇に置く)と、秒数のプロパティがsecondsであるかのようにアクセスできる(図4 ) 。// ActionScript 3.0クラス定義ファイル: MyTimerInfo.aspackage { public class MyTimerInfo { public var milliseconds:int;private var_seconds :int; public var minutes:int; public var hours:int; public function MyTimerInfo(nMilliseconds:Number=0) { setTime(nMilliseconds); }public functionget seconds ():int { return_seconds; }public functionset seconds (nSeconds:int) { setTime(nSeconds*1000); } private function setTime(nTime:Number):void { milliseconds = nTime% 1000; nTime = Math.floor(nTime / 1000);_seconds = nTime% 60; nTime = Math.floor(nTime / 60); minutes = nTime% 60; hours = Math.floor(nTime / 60); } }} 図4 アクセサメソッドsecondsにはプロパティのようにアクセスできるそれでは、改めてクラスMyTimerInfoにget/setアクセサメソッドを定義したい。前回のスクリプト2 とは異なり、実際のインスタンスプロパティはprivate属性で指定するので、タイムラインから直接アクセスされることはない。代わりに、get/setアクセサメソッドがプロパティの役割を果たす。すると、実際のプロパティが時分秒ミリ秒の値をそれぞれもつ必要はない。したがって、privateのインスタンスプロパティは総ミリ秒数のみを保持することとして、時分秒ミリ秒の値はアクセサメソッドの方で分ければよい[1] 。そこで、つぎのスクリプト1のように総ミリ秒数のprivateプロパティはtotalMillisecondsとして宣言し、hours、minutes、seconds、millisecondsはアクセサメソッドとして定義した。スクリプト1 クラスMyTimerInfoにget/setアクセサメソッドを定義 // ActionScript 3.0クラス定義ファイル: MyTimerInfo.aspackage { public class MyTimerInfo {private vartotalMilliseconds: Number; public function MyTimerInfo(nMilliseconds:Number=0) { totalMilliseconds = nMilliseconds; }public functionget milliseconds ():int { var nMilliseconds:int = totalMilliseconds%1000; return nMilliseconds; }public functionget seconds ():int { var nSeconds:int = Math.floor(totalMilliseconds/1000)%60; return nSeconds; }public functionget minutes( ):int { var nMinutes:int = Math.floor(totalMilliseconds/1000/60)%60; return nMinutes; }public functionget hours ():int { var nHours:int = Math.floor(totalMilliseconds/1000/60/60); return nHours; }public functionset milliseconds (nMilliseconds:int):void { setTime(hours, minutes, seconds, nMilliseconds); }public functionset seconds (nSeconds:int):void { setTime(hours, minutes, nSeconds, milliseconds); }public functionset minutes (nMinutes:int):void { setTime(hours, nMinutes, seconds, milliseconds); }public functionset hours (nHours:int):void { setTime(nHours, minutes, seconds, milliseconds); } public functionsetTime (nHours:int=0, nMinutes:int=0, nSeconds:int=0, nMilliseconds:int=0):void { nMinutes = nHours*60+nMinutes; nSeconds = nMinutes*60+nSeconds; nMilliseconds = nSeconds*1000+nMilliseconds; totalMilliseconds = nMilliseconds; } }}この仕様変更にともない、setTime()は時分秒ミリ秒をそれぞれ引数として受取るメソッドに定義し直し、総ミリ秒数のprivateプロパティtotalMillisecondsを設定することとした。各メソッドの処理内容は、前回までの説明で理解できよう。なお、setTime()メソッドはpublic属性にしたので、タイムラインから呼出して、時分秒ミリ秒をまとめて設定することも可能だ。アクセサメソッドsecondsは、タイムラインからたとえばつぎのようなフレームアクションで試すことができる(図5 ) 。
// タイムライン: メイン// フレームアクションvar myObject:MyTimer = new MyTimer();var oElapsedTime:MyTimerInfo = myObject.getElapsedTime();oElapsedTime.seconds = 150; // 150秒を設定trace(oElapsedTime.minutes, oElapsedTime.seconds);oElapsedTime.seconds -= 50; // 50秒を差引くtrace(oElapsedTime.minutes, oElapsedTime.seconds);図5 アクセサメソッドでプロパティ値を変更するこれでクラス定義の基本は、ひととおり解説した。次回からはお題を変えて、MovieClipシンボルにクラスを設定してみたい。
[1] 時分秒ミリ秒の各値に素早くアクセスする処理が頻繁かつ大量にあるようなときは、各値をそれぞれ別のプロパティとして保持した方が有利な場合もありえる。
今回解説した次のサンプルファイルがダウンロードできます。