ケータイJavaのいろは 第五回 クラスShortTimer


IDGジャパン JavaWorld 2001年10月号 に掲載された記事の原文を公開します。 編集の手がかなり加えられて掲載されたため、 雑誌に掲載されたものとは異なる部分があります (無断転載禁止)。

低レベル API のタイマー / FrogClimber ゲーム / ユーザーインターフェースのまとめ / 終わりに / 戻る / トップページ


低レベル API のタイマー

本連載の第 3 回で取上げたように、i モード対応 Java プロファイルには リアルタイム処理などを実現するための Timer クラスが用意されています。 ユーザーインターフェースとして低レベル API を使う場合にも Timer クラスを使ってリアルタイム処理を実現することが出来ます。 しかし、低レベル API にはもう一つのタイマー処理を実現する com.nttdocomo.ui.ShortTimer クラスが使えます。 このクラスは短時間タイマーと呼ばれ、 比較的に短時間間隔の処理に向いています。
 
今回はタイマー処理を利用したリアルタイムで動作する 簡単なゲームをサンプルとして取上げ、 低レベル API でのタイマー処理について解説します。

FrogClimber ゲーム

ShortTimer クラスのサンプルとして、簡単なゲームを作ります。 カエルを左右移動・ジャンプさせて上へ上へと登っていくゲームです。 このゲームはリアルタイムに動作し、画面が上下方向にスクロールします。 このようなプログラムは低レベル API とその短時間タイマーを使うことで 初めて実現することが出来ます。
 
ゲームを開始すると、自分が操作するカエルといくつかの ボールを表示します (図 1)。左右キーでカエルを左右に移動させ、 決定キーまたは上キーでジャンプさせられます。 カエルがボールにぶつかるとボールにはじかれます。 カエルを上手に操作してボールに上側からぶつかることで より高く飛ぶことができるので、これを利用してより上へと登ります。 カエルが画面上部を越えそうになると画面は自動的にスクロールします。
 

FrogClimber.java

 
画面構成は図 1 のとおりです。このソースファイルが FrogClimber.java (リスト 1)、 FrogClimberCanvas.java (リスト 2) の二つになります。カエル・ボールの画像として frog1.gif, frog2.gif, frog3.gif, ball.gif の 画像ファイルも必要となります (図 2)。
 
(図1 FrogClimber.java の実行結果)
 
(図2 カエル・ボールの画像)
 

短時間タイマー

 
低レベル API UI ではリアルタイム処理を実現するために 短時間タイマーである com.nttdocomo.ui.ShortTimer クラスが使えます。 ShortTimer クラスは com.nttdocomo.util.Timer クラスと機能は同じですが、 比較的付加が少なく短時間のタイマー処理に向いています。 ShortTimer クラスは低レベル API UI 専用のため、 com.nttdocomo.ui パッケージに分類されています。
 
ShortTimer クラスは時間になるとその旨をイベントとして Canvas オブジェクトに通知します。このイベントは低レベル API UI の キーイベントなどと同じように processEvent(int type,int param) メソッドに通知されます。
 
ShortTimer クラスの使い方は以下のとおりです。 まず、ShortTimer クラスのクラスメソッド getShortTimer(Canvas canvas,int id,int time,boolean repeat) で ShortTimer オブジェクトを生成します。 この時、リスナーとなる Canvas オブジェクト、 タイマーの ID (自由に指定できます)、時間間隔、 インターバルタイマーか否かを引数でそれぞれ指示します。 引数 repeat に true を指定するとインターバルタイマーとして、 false を指定するとワンショットタイマーとして動作します (リスト 2 の 88 行目)。
 
start() メソッドで動作開始を行い、時間になると Canvas オブジェクトにイベントが通知されます。 processEvent(int type,int param) メソッドの引数 type に Display.TIMER_EXPIRED_EVENT が、 param に ShortTimer オブジェクト生成時に指定した ID が渡されます。 ID を使い分けることで複数の短時間タイマーを 使用可能です (リスト 2 の 187 行目)。 使用後は stop() メソッドで停止させて、 dispose() メソッドで破棄します (リスト 2 の 211, 212 行目)。
 
短時間タイマーはそのイベントの受け取り手となる Canvas オブジェクトが 画面に表示されている時のみ動作しますので、注意して下さい。 start() メソッドを Canvas オブジェクトのコンストラクタではなく、 start() メソッドで行っているのはこのためです。 コンストラクタ中では Canvas オブジェクトがまだ画面に 表示されていないため、短時間タイマーは動作しません。
 

処理速度

 
携帯電話は消費電力やコストへの配慮からパソコンに比べると 決して高いとはいえない処理能力しか持ち合わせていません。 そのため、このようなリアルタイムに動作するゲームのような アプリケーションでは動作速度の遅さをカバーする工夫が必要です。 i アプリではサービスインごろに発売された機種 P503i (松下電気), F503i (富士通) が処理速度の最低ラインとなるので、 これらの機種でも動作するようにする必要があります。
 
このサンプルでは短時間タイマー (インターバルタイマー) で 1 秒間に 7 回イベントが発生し (リスト 2 の 88 行目)、 その度にメインループと画面の再描画が 発生します (リスト 2 の 191, 192 行目)。 メインループは特に重い処理はしないため、 描画処理である paint(Graphics g) メソッドが処理速度のネックとなります。 インターバルタイマーの時間間隔を短くすればそれだけ高速動作しますが、 描画処理量が携帯電話の処理能力を超えてしまうと、 描画が終わりきらないうちに次のイベントが発生してしまいます。 その結果イベントがたまってしまい、 キーイベントの発生が遅れるなどの弊害が出ます。 このように、携帯電話の処理能力以上の負荷をかけてはならないため、 描画処理速度・タイマーの間隔には気を配るようにしましょう。
 

キー取得

 
前回取上げたように低レベル API UI ではキー入力を イベントで取得できました。 低レベル API UI では、能動的にキー状態を取得することもできます。 ゲームなどの即時性を必要とするアプリケーションでは この方法を使うと良いでしょう。
 
Canvas クラスに getKeypadState() メソッドがあり、 このメソッドで現在の全てのキーの押下状態を取得することが出来ます。 戻り値の各ビットの位置が Display クラスで 定義されているキーに対応します (表1)。 キーが押されていると、対応するビットが 1 となります。
 
ビット 222120 19181716 15141312 11109 8 7 6 5 4 3 2 1 0










2





1


/







































9




8




7




6




5




4




3




2




1




0
(表1 キー押下情報)
 
例えば左方向キーのみが押されていると、ビット 16 が 1、 その他のビットが 0 となります。 ある一つのキーが押されているかどうかを調べるには、 リスト 2 の 96 行目のようにします。
 

透過色

 
i モード対応 Java プロファイルでは画像に透過色を使うことが出来ます。 GIF 画像で指定した透過色は描画時に自動的に透かして描画してくれます。
 
このサンプルのカエルやボールの画像の背景部分 (画像の角のあたりなど) の黒色は透過色にしているため (図 3)、 paint(Graphics g) メソッド (リスト 2 の 164 行目) で描画する際には、 画像に背景の薄い青色が抜けている (黒色の部分が描画されない) 事がわかります。
 
(図3 カエルの画像の拡大図)
 

ソフトキーラベル

 
このサンプルではカエルがこれまで飛んだ高さの最高値を ソフトキーのラベルに表示しています。 ソフトキーのラベルは本来ソフトキーの機能を表示するものですが、 このように情報表示に使うことも出来ます。

ユーザーインターフェースのまとめ

今回まででユーザーインターフェースについては一通り説明してきました。 これまでは理解しやすいように話しをしてきましたが、 ここでユーザーインターフェースについて別の側面から まとめて説明しますので、いま一度理解を深めましょう。
 

Frame クラス

 
画面そのものは Display クラス、 画面に表示される内容は Frame オブジェクトで表されています。 Display クラスにどの Frame オブジェクトを設定するかによって 画面に表示されるユーザーインターフェースが決まります。 表示されるもの、つまり Frame クラスのサブクラスとして、 Panel クラスと Canvas クラス、Dialog クラスの 3 つがあります (表 2)。
 
Panel クラスを使った場合、高レベル API となります。 各種 UI コンポーネント (ボタンやラベルなど) を画面に追加することができ、 イベントはリスナーで処理します。
 
Canvas クラスは継承して使い、低レベル API となります。 プログラムで画面上への描画・ユーザー操作の処理を行い、 イベントはその Canvas オブジェクトに直接伝えられます。
 
Dialog クラスは文字通りダイアログを表します。 使い方はやや特殊で、show() メソッドを呼び出すと表示され、 ユーザーの操作によって閉じられると、 直前に表示していた Frame オブジェクトが再び画面に表示されます。
 
(表2 Frame クラスの継承図)
Frame
┣Panel
┣Canvas
┗Dialog
 

リソース読み込み

 
別個に説明してきましたが、リソース (画像、音声) を読み込む方法は 統一されています。以下にその流れを説明します。
 
MediaManager クラスがリソースを読み込むクラス、 MediaResource インターフェースが読み込まれたリソースを表すクラスです。 読み込むリソースの種類によって MediaResource インターフェースを 継承したインターフェースが使われます。 画像なら MediaImage インターフェース、 音声なら MediaSound インターフェースとなります。
 
MediaManager クラスのクラスメソッドにリソースの置き場所を指定して MediaResource インターフェースを取得します。 画像を読み込む場合は getImage(String location) クラスメソッド、 音声を読み込む場合は getSound(String location) クラスメソッドを使います。 JAR ファイルから読み取る場合、 置き場所は resource:// の後にファイル名を指定することになります。 読み込んだ MediaResource インターフェースは使用前に use() メソッドを呼んで実際の読み込みを実行させます。 この時にファイルが存在しないと com.nttdocomo.io.ConnectionException 例外が投げられます。
 
こうして読み込まれたリソースを扱う時点で、リソースの種類や 高レベル API か低レベル API かによってそれぞれの方法で扱います。 画像を高レベル API で扱う場合、Image オブジェクトを取り出して ImageLabel クラスのコンストラクタに渡します。 画像を低レベル API で扱う場合、Image オブジェクトを取り出して Graphics クラスの drawImage(Image img, int x, int y) メソッドに 渡すなどして描画に使います。 音声の場合、AudioPresenter オブジェクトに setSound(MediaSound sound) メソッドで設定します。
 
MediaResource インターフェースは、使い終わったら unuse() メソッドで使用終了を宣言し、 dispose() メソッドでリソースを破棄します。

終わりに

今回は低レベル API でのタイマーを中心にサンプルを使って解説しました。 また、ユーザーインターフェースについて整理しました。 次回はネットワーク・スクラッチパッドを扱います。

戻る