
| ★はじめに★ |
![]() |
第2話 新生FOMAによるシューティングゲームの作成 [JAVA PRESS Vol.29] ゲーム:シューティングゲーム 対応端末:・N2051・F2051・P2102V
|
![]() |
ねぇねぇ、へにへに〜。FOMAって、第3世代の携帯電話とか言われてるけど、もの凄い勢いで人気無いよね? | |
| ピー!! そらみちゃんはもう少し穏やかな物腰で発言してください。…でも実際のところ、FOMAよりも504iシリーズの方が小さくて性能良いしね…。 | ![]() |
|
![]() |
えっ? FOMAは次世代携帯のはずなのに、どうして現行機の504iより性能が悪いの? | |
| まだ各メーカーが端末を作り慣れていないし、ネットワークが新しい分、回線の整備も行き届いてないみたいなんだよ。 | ![]() |
|
![]() |
うーん、iアプリの性能が504iと同じなら、パケット通信料は10分の1で済むし普及しそうなのにねぇ…。 | |
| …ふっふっふ、そらみちゃん。504i並のiアプリ処理能力を持ったFOMAが先日発売されたのは知ってるかい? | ![]() |
|
![]() |
あ、それってもしかして、N2051とかF2051とか…P2102Vなんかのこと?どうでもいいけど、中身がNのP端末なんて、あたしゃ認めないよ!! | |
| うん。とりあえずそらみちゃんのマニア心は横に置いておくとして、ようやく504i用のアプリも動くようになって、動画も綺麗になったし、これからはFOMAの逆襲がはじまりそうだね。 | ![]() |
|
![]() |
(…最近は505iシリーズの噂もちらほら聞くけど、とりあえず黙っとこ…) |
| ★FOMA02仕様モデル★ |
FOMAとは
「FOMA」は、NTTドコモが2001年10月からサービスを開始したIMT-2000方式による携帯電話サービスです。アナログ携帯電話を第1世代、デジタル携帯電話(PCD方式)を第2世代、FOMAは第3世代と位置付けられています。IMT-2000方式の特徴としては、などが挙げられます。さらに、「パケットパック」というオプション料金を払うことで、通信料金を最大10分の1にできることも、大きな魅力となっています。
- 通話品質が良い
- 高速なデータ通信
- 将来的には海外でも通話可能
しかし、初期のFOMAは、と、第2世代である503i・504iシリーズより性能が悪かったため、普及しませんでした。
- 利用できるエリアが日本国内の一部の地域に限定される。
- 携帯の体積が大きい。
- 電池の持ちが悪い。
- iアプリの処理能力は503iシリーズ並。
これを打破すべく2003年に投入されたのが、F2051・N2051・P2102Vといった次世代のFOMA端末です。これらは「FOMA02仕様モデル」と呼ばれ、プロファイルとして504iシリーズのDoJa-2.0を拡張したDoJa-2.1が採用され、iアプリの処理能力は504iシリーズ並になり、iモーションの画質も格段に良くなりました。また、通話エリアも関東・甲信越で人口カバー率約95%、全国の人口カバー率約82%と、ようやく実用に耐える端末になりました。
FOMA02仕様モデルの拡張機能
FOMA02仕様モデルの拡張機能には次のようなものがあります。
iモーション
「iモーション」は、FOMA向けの動画配信サービスです。今まで100Kバイト/最大15秒から、300Kバイト/最大40秒となり、画質も格段に良くなりました。動画フォーマットは映像コーデック(圧縮/展開技術)は「MPEG-4」、音声コーデックは「AMR」と変わりませんが、ファイルフォーマットが従来の「ASF」から「MP4」に変更されました。MP4はQuickTimeのファイルフォーマットを基本として策定されたファイルフォーマットで、MPEG標準とされています。FOMA02仕様モデルでは、ASFは再生できないので注意してください。
この新しいiモーションを再生できるのは、FOMA02仕様モデルと、新しいバージョンのQuickTimeをインストールしたパソコンとなります。QuickTimeは従来からMP4に対応していますが、音声コーデックがAMRであるiモーションは再生できません。次期バージョンで対応するとのことですが、執筆時現在(2003年1月)まだリリースされていません。
映像コーデック 音声コーデック ファイルフォーマット ドコモ新FOMA MPEG-4 AMR MP4 ドコモ旧FOMA MPEG-4 AMR ASF KDDIムービー MPEG-4 QCELPまたはMP3 MP4 J-PHONEムービー写メール Nancy AMR Nancy
ポインティングデバイス
ポインティングデバイスは、パソコンのマウスのように、カーソルを移動させることで座標位置を伝えることができる入力デバイスです。執筆時現在(2003年1月)、携帯で利用可能なポインティングデバイスは、N2051で採用されている「ニューロポインター」のみです。
携帯電話の個体識別情報の取得
アプリから携帯電話の個体識別情報を取得することができます。個体識別情報には以下の2種類があり、同じ値が複数の個体に割り当てられることはありません。
- 携帯電話本体の識別情報(製造番号)
- ICチップカードの識別情報(製造番号)
スクラッチパッドとHTTP送受信データのサイズ拡大
スクラッチパッドとは、アプリごとに割り当てられるデータ保存領域のことです。スクラッチパッドの最大サイズは今まで10〜100Kバイトでしたが、FOMA02仕様モデルは200Kバイトまで引き上げられました。また、HTTP通信時の送受信データの最大サイズは今まで送信5Kバイト、受信10Kバイトでしたが、FOMA02仕様モデルは送信80Kバイト、受信150Kバイトまで引き上げられました。
503iシリーズ 504iシリーズ FOMA02仕様モデル スクラッチパッドサイズ 10Kバイト 100Kバイト 200Kバイト 送信データサイズ 5Kバイト 5Kバイト 80Kバイト 受信データサイズ 10Kバイト 10Kバイト 150Kバイト
メロディフォーマットの追加
サウンドデータのフォーマットは今まで「iメロディ形式」が標準でしたが、FOMA02仕様モデルでは「SMF(Standard MIDI File)」が標準となりました。今後発売される端末は「iメロディ形式」をサポートしない可能性があります。
オプションAPIと拡張APIの実装状況
FOMA02仕様モデルのiアプリオプションAPIとiアプリ拡張APIの実装状況は次の通りです。
オプションAPIと拡張APIの実装状況
オプションAPIと拡張APIの実装状況 F2051 N2051 P2102V 携帯電話組み込みの効果音を鳴らす ○ 複数のサウンドを同時に鳴らす イメージマップを使う ○ ○ 描画クリッピングを行う ピクセルを操作する イメージの回転・反転・拡大縮小を行う ラスタオペレーションを行う スプライト機能を使う ○ ○ カラーパレットを変更する サウンドエフェクトを使う ○ ○ 待ち受け画像を変更する サブディスプレイにイメージを表示する ○ ○ 3Dポリゴンを表示する(高レベル) ○ ○ ○ 3Dポリゴンを表示する(低レベル) 2Dアニメーションを表示する 静止画の撮影 ○ ○ ○ 動画の撮影 ○ ○ ○ ポインティングデバイス ○
| ★開発環境を整える★ |
今回のゲームを作るのに必要な開発ツールは次の3つです。どれも無償で入手できます。
Java 2 SDK, Standard Edition Version 1.3(JDK1.3以降)
パソコン上で動くJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。次に説明する「iαppli Development Kit」を実行するのに必要なので、それより先にインストールします。インストーラの指示に従ってインストールしてください。
iαppli Development Kit for DoJa2.1 (FOMA) Ver.1.00
iアプリを作るための開発キットです。FOMA02仕様モデルの新機能にも対応しました。NTTドコモのサイトで入手できます。ボタン1つでビルド(コンパイル+検証+JAR作成)やエミュレータでの実行ができます。インストーラの指示に従ってインストールしてください。Microsoft Windows 98 Second Edition/2000で動作します。
また、同サイトから開発に役立つドキュメントが入手できるので、いっしょにダウンロードしてください。
- iアプリコンテンツ開発ガイドfor504i(詳細編)
- iアプリコンテンツ開発ガイドfor504i(iアプリオプション・拡張編)
- APIリファレンス(iアプリ基本API編)
- APIリファレンス(iアプリオプション・拡張API編)
- 各機種オプションAPI・拡張API実装状況
Japanese documentation for the J2ME CLDC
CLDCのAPIリファレンスはNTTドコモのサイトで入手できるドキュメントの中には含まれないので、サン・マイクロシステムズのサイトから入手してください。
| ★iモーションの再生★ |
はじめに、ボタンを押した時にiモーションを再生するプログラム「VisualPresenterEx」を作ります。
このプログラムは以下の2つのクラスで構成されています。「iαppli Development Kit」のエミュレータでは、iモーションの再生機能をサポートしてないので、動作テストは実機で行ってください。
- VisualPresenterExクラス ‐本体
- VisualPresenterPanelクラス‐パネル
動画ファイルの準備
このプログラムでは、1つの動画ファイルを使います。プロジェクトのresディレクトリ(C:\iDKDoJa2.1FOMA\apps\VisualPresenterEx\res)に置いてください。
・サンプル
sample.3gp
iモーションの動画ファイル(*.3gp)を生成するには、次の2つの方法があります。執筆時現在(2003年1月)、iモーションの動画ファイルに変換する方法は公開されていないので、FOMA端末で動画を撮影することにします。メールに添付できる動画ファイルのサイズは最大100Kバイトです。今回の動画ファイルはJARファイルに含めます。JARファイルのサイズ制限は504iシリーズと同じ30Kバイトなので、動画ファイルのサイズは20Kバイト程度の短いものにしてください。
- 変換ツールでAVI等の動画ファイルをiモーションの動画ファイルに変換する。
- FOMA端末で動画を撮影し、メールに添付してパソコンに送る。
VisualPresenterExクラス
VisualPresenterExクラスは、プログラムの本体となるクラスです。VisualPresenterPanelオブジェクトを生成し、 DisplayクラスのsetCurrent()メソッドに引数として渡しています。
VisualPresenterEx.java import com.nttdocomo.ui.*; //iモーションの再生(本体) public class VisualPresenterEx extends IApplication { //アプリの開始 public void start() { Display.setCurrent(new VisualPresenterPanel()); } }
VisualPresenterPanelクラス
VisualPresenterPanelクラスは、パネルとなるクラスです。
VisualPresenterPanel.java import com.nttdocomo.ui.*; //iモーションの再生(パネル) class VisualPresenterPanel extends Panel implements ComponentListener { private static Button button;//ボタン private static VisualPresenter vp; //ビジュアルプレゼンター //コンストラクタ VisualPresenterPanel() { //ボタン button=new Button("動画の再生"); add(button); setComponentListener(this); try { //動画ファイルの読み込み MediaImage m=MediaManager.getImage( "resource:///sample.3gp"); m.use(); //ビジュアルプレゼンター vp=new VisualPresenter(); add(vp); vp.setImage(m); } catch (Exception e) { } } //コンポーネントアクションイベント public void componentAction(Component c,int type,int param) { //iモーションの再生 if (type==BUTTON_PRESSED && c==button) { try { vp.play(); } catch (Exception e) { } } } }
パネル
「パネル」はラベルやテキストボックスなどの「コンポーネント(部品)」を貼り付けて使うものです。キャンバスが画面に文字列やイメージを描画したい時に使うのに対し、パネルはHTMLブラウザのフォームのようなインターフェイスを作りたい時に使います。パネルとなるクラスはPanelクラスを継承します。
VisualPresenterPanel.javaの一部 class VisualPresenterPanel extends Panel
「DoJa-2.1プロファイル」で使えるコンポーネントは9種類あります。
ラベル 1行のテキストを表示する。 イメージラベル イメージを表示する。 ボタン ボタンによって入力する。 イメージボタン イメージを貼り付けることができるボタン。 アンカーボタン HTMLのアンカー風のボタン。 テキストボックス 文字列を入力する。 リストボックス 各種選択リストによって入力する。 ティッカー スクロールする文字列を表示する。 ビジュアルプレゼンター 動画を再生する。
ボタン
Buttonクラスのオブジェクトを作り、パネルに追加します。Buttonクラスには2種類のコンストラクタがあります。
Button()
Button(String label)
label:ボタン上に表示する文字列
パネルにコンポーネントを追加するにはadd()メソッドを使います。
void add(Component c)
c:コンポーネント
今回は、"動画の再生"というボタンを作るので以下のようになります。
VisualPresenterPanel.javaの一部 button=new Button("動画の再生");
add(button);
ボタンが押した時に処理を行う時には、コンポーネントリスナーを使います。コンポーネントリスナーは、ボタンを押したことや、テキストボックスの中身が変更したことなど、イベント情報を受信するためのリスナーです。
はじめに、VisualPresenterPanelクラス自身にコンポーネントリスナーのインタフェースを実装します。Java言語では、インタフェースを実装していることを示すために、implementsキーワードの後にインタフェース名を記述します。
VisualPresenterPanel.javaの一部 implements ComponentListener {
次に、PanelクラスのsetComponentListener()メソッドで、イベントが発生した時、そのことをどこへ送信すれば良いかを指定します。今回はVisualPresenterPanelクラス自身がコンポーネントリスナーになるのでthisをセットします。
VisualPresenterPanel.javaの一部 setComponentListener(this);
最後にcomponentAction()メソッドを実装します。実機はイベントが発生した時、このメソッドを呼びます。
void componentAction(Component source, int type, int param)
source:イベントが発生したコンポーネント
type:イベント種別
param:パラメータ
sourceはイベントが発生したコンポーネントのオブジェクト、typeはイベント種別でComponentListenerインタフェースが持つイベント種別定数が渡されます。
イベント種別定数 BUTTON_PRESSED ボタンが押された時に発行するイベント TEXT_CHANGED テキスト入力が確定した時に発行するイベント SELECTION_CHANGED リストの選択が変化した時に発行するイベント
paramはパラメータで、意味はコンポーネントごとに異なります。今回は、ボタンを押した時にiモーションを再生するので以下のようになります。
VisualPresenterPanel.javaの一部 public void componentAction(Component c,int type,int param) { //iモーションの再生 if (type==BUTTON_PRESSED && c==button) { try { vp.play(); } catch (Exception e) { } } }
動画ファイルの読み込み
動画ファイルを読み込むには、「MediaManagerクラス」を使います。MediaManagerクラスは、動画ファイルを読み込むためのgetImage()メソッドを持っています。
static MediaImage getImage(String location)
location:読み込み先
戻り値:MediaImageオブジェクト
読み込み先は以下のフォーマットで指定します。
resource:///ファイル名
動画データをリソースでなく、スクラッチパッドから読み込む場合は、以下のフォーマットで指定します。
scratchpad:///0;pos=位置
戻り値として「MediaImageクラス」のオブジェクトが返ってきます。MediaImageクラスは、ファイルを読み込み、内部表現形式に変換するクラスです。use()メソッドで読み込み処理を行います。
今回は、"sample.3gp"を読み込むので以下のようになります。
MediaImage m=MediaManager.getImage("resource:///sample.3gp");
m.use();
ビジュアルプレゼンター
ビジュアルプレゼンターは、動画を再生するコンポーネントです。「iモーション」の他に、全機種で「GIFアニメーション」、N504iとN504iSで「E-アニメーター」を再生できます。
VisualPresenterクラスのオブジェクトを作り、パネルに追加し、VisualPresenterクラスのsetImage()メソッドで動画データをセットします。
VisualPresenterPanel.javaの一部 vp=new VisualPresenter();
add(vp);
vp.setImage(m);
再生するにはVisualPresenterクラスのplay()メソッドを呼びます。
VisualPresenterPanel.javaの一部 vp.play();
| ★ポインティングデバイスの使用★ |
次に、ポインティングデバイスのカーソルが示している座標を表示するプログラム「PointingDeviceEx」を作ります。
このプログラムは以下の2つのクラスで構成されています。執筆時現在(2003年1月)、ポインティングデバイスが使用できるのはN2051のみです。
- PointingDeviceExクラス ‐本体
- PointingDeviceCanvasクラス‐キャンバス
PointingDeviceExクラス
PointingDeviceExクラスは、プログラムの本体となるクラスです。PointingDeviceCanvasオブジェクトを生成し、 DisplayクラスのsetCurrent()メソッドに引数として渡しています。最後にPointingDeviceCanvasのexe()メソッドを呼んでいます。
PointingDeviceEx.java import com.nttdocomo.ui.*; //ポインティングデバイスの使用(本体) public class PointingDeviceEx extends IApplication { //アプリの開始 public void start() { PointingDeviceCanvas c=new PointingDeviceCanvas(); Display.setCurrent(c); c.exe(); } }
PointingDeviceCanvasクラス
PointingDeviceCanvasクラスは、キャンバスとなるクラスです。exe()メソッドでは無限ループを行い、100ミリ秒ごとにポインティングデバイスのカーソルの座標を描画しています。
PointingDeviceCanvas.java import com.nttdocomo.ui.*; import com.nttdocomo.opt.ui.*; //ポインティングデバイスの使用(キャンバス) class PointingDeviceCanvas extends Canvas { //実行 void exe() { //Graphicsオブジェクトの取得 Graphics g=getGraphics(); //ポインティングデバイスの使用 PointingDevice.setEnabled(true); while (true) { //描画 g.lock(); g.setColor(g.getColorOfName(g.WHITE)); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(g.getColorOfName(g.BLACK)); g.drawString("X座標>"+PointingDevice.getX(),0,20); g.drawString("Y座標>"+PointingDevice.getY(),0,40); g.drawString("ポインティング>"+PointingDevice.isEnabled(),0,60); g.unlock(true); //スリープ try { Thread.sleep(100); } catch (Exception e) { } } } //描画 public void paint(Graphics g) { } }
Graphicsオブジェクトの取得
画面に図形や文字列を描画するにはGraphicsオブジェクトを操作します。Graphicsオブジェクトはpaint()メソッドの引数として渡されますが、CanvasクラスのgetGraphics()メソッドで明示的に取得することもできます。
PointingDeviceCanvas.javaの一部 Graphics g=getGraphics();
ポインティングデバイス
ポインティングデバイスを操作するにはcom.nttdocomo.opt.uiパッケージのPointingDeviceクラスを使います。ポインティングデバイスを使用するかどうかを指定するにはsetEnabled()メソッド、使用しているかどうかを取得するにはisEnabled()メソッドを使います。
static void setEnabled(boolean flag)
flag:ポインティングデバイスを使用するかどうか
static boolean isEnabled()
戻り値:ポインティングデバイスを使用しているかどうか
今回は、使用するので以下のようになります。
PointingDeviceCanvas.javaの一部 PointingDevice.setEnabled(true);
また、ポインティングデバイスのカーソルのX座標を取得するにはgetX()メソッド、Y座標を取得するにはgetY()メソッドを使います。
static int getX()
戻り値:ポインティングデバイスのX座標
static int getY()
戻り値:ポインティングデバイスのY座標
今回は、ポインティングデバイスの座表を描画するので以下のようになります。
PointingDeviceCanvas.javaの一部 g.drawString("X座標>"+PointingDevice.getX(),0,20);
g.drawString("Y座標>"+PointingDevice.getY(),0,40);
| ★シューティングゲームを作る★ |
それでは、本題の「シューティングゲーム」を作ります。落ちてくる隕石をレーザーで破壊し、地球を守るゲームです。操作方法はポインティングデバイス(未対応機種は方向キー)で照準の移動、選択キーでレーザーの発射です。隕石が地球に落ちるとゲームオーバーです。どれだけ長い時間守れたかがスコアとなります。ゲームオーバー時には、ソフトキー1によってリトライできます。
![]()
このゲームは以下の2つのクラスで構成されています。
- ShootingGameクラス ‐本体
- ShootingCanvasクラス‐キャンバス
画像ファイルの用意
このゲームでは、5枚の画像ファイルを使います。resディレクトリ(C:\iDKDoJa2.1FOMA\apps\ShootingGame\res)に置いてください。
・宇宙船
-0.gif
-16x16
・照準
-1.gif
-20x16
・隕石
-2.gif
-16x16
・爆発
-3.gif
-24x24
・ゲームオーバー
-4.gif
-86x16
ShootingGameクラス
ShootingGameクラスは、プログラムの本体となるクラスです。ShootingCanvasオブジェクトを生成し、 DisplayクラスのsetCurrent()メソッドに引数として渡しています。最後にShootingCanvasのexe()メソッドを呼んでいます。
ShootingGame.java import com.nttdocomo.ui.*; //シューティングゲーム(本体) public class ShootingGame extends IApplication { //アプリの開始 public void start() { ShootingCanvas c=new ShootingCanvas(); Display.setCurrent(c); c.exe(); } }
ShootingCanvasクラス
ShootingCanvasクラスは、キャンバスとなるクラスです。exe()メソッドでは無限ループを行い、100ミリ秒ごとに状態の遷移と再描画を行っています。
ShootingCanvas.java import com.nttdocomo.ui.*; import com.nttdocomo.opt.ui.*; import java.util.*; //シューティングゲーム(キャンバス) class ShootingCanvas extends Canvas { //定数 private static int S_PLAY=0,S_GAMEOVER=1; //シーン private static int E_NONE=-1,E_DOWN=0,E_BOM=1;//敵 //システム private static int scene; //シーン private static int init =S_PLAY; //初期化 private static int score; //スコア private static Image[] image=new Image[5];//イメージ private static Random rand =new Random();//乱数 private static Graphics g; //グラフィックス //照準 private static boolean pointing;//ポインティング private static int targetX; //X座標 private static int targetY; //Y座標 //星 private static int[] starX=new int[10];//X座標 private static int[] starY=new int[10];//Y座標 //隕石 private static int[] enState=new int[8];//状態 private static int[] enX =new int[8];//X座標 private static int[] enY =new int[8];//Y座標 //処理 void exe() { int i; long sleepTime=0; MediaImage m; //ポインティングデバイス try { PointingDevice.setEnabled(true); pointing=true; } catch (Exception e) { pointing=false; } try { //初期化 g=getGraphics(); for (i=4;i>=0;i--) { m=MediaManager.getImage("resource:///"+i+".gif"); m.use(); image[i]=m.getImage(); } //メインループ while (true) { tick(); while (System.currentTimeMillis()<sleepTime+100); sleepTime=System.currentTimeMillis(); } } catch (Exception e) { } } //時間経過 private void tick() { int i,j; //初期化 if (init>=0) { scene=init; init =-1; //プレイ if (scene==S_PLAY) { for (i=9;i>=0;i--) { starX[i]=(rand.nextInt()>>>1)%getWidth(); starY[i]=(rand.nextInt()>>>1)%getHeight(); } for (i=7;i>=0;i--) enState[i]=E_NONE; targetX=getWidth()/2; targetY=getHeight()/2; score =0; setSoftLabel(SOFT_KEY_1,""); } //ゲームオーバー else if (scene==S_GAMEOVER) { setSoftLabel(SOFT_KEY_1,"リトライ"); } } //背景 g.lock(); g.setColor(g.getColorOfName(g.BLACK)); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(g.getColorOfName(g.WHITE)); for (i=9;i>=0;i--) { g.fillRect(starX[i],starY[i],1,1); starY[i]+=10; if (starY[i]>getHeight()) { starX[i]=(rand.nextInt()>>>1)%getWidth(); starY[i]=-(rand.nextInt()>>>1)%100; } } g.setColor(g.getColorOfRGB( 50, 50,255)); g.fillRect(0,getHeight()-9,getWidth(),3); g.setColor(g.getColorOfRGB(100,100,255)); g.fillRect(0,getHeight()-6,getWidth(),3); g.setColor(g.getColorOfRGB(150,150,255)); g.fillRect(0,getHeight()-3,getWidth(),3); //隕石 j=(rand.nextInt()>>>1)%100; for (i=7;i>=0;i--) { //出現 if (enState[i]==E_NONE && j<5) { enX[i] =(rand.nextInt()>>>1)%getWidth(); enY[i] =-16; enState[i]=E_DOWN; j=99; } //下 if (enState[i]==E_DOWN) { g.drawImage(image[2],enX[i]-8,enY[i]-8); enY[i]++; if (score>300) enY[i]++; if (score>600) enY[i]++; if (enY[i]>getHeight()+8) enState[i]=E_NONE; } //爆発 else if (enState[i]==E_BOM) { g.drawImage(image[3],enX[i]-12,enY[i]-12); enState[i]=E_NONE; } } //プレイ if (scene==S_PLAY) { //ゲームオーバーチェック for (i=7;i>=0;i--) { if (enState[i]!=E_NONE && enY[i]>getHeight()-18) { init=S_GAMEOVER; } } //スコア score++; //レーザー j=getKeypadState(); if ((1<<Display.KEY_SELECT&j)!=0) { g.setColor(g.getColorOfRGB(160,230,255)); g.drawLine(targetX,getHeight()-28,targetX,targetY); g.drawLine(targetX,getHeight()-29,targetX,targetY+1); for (i=7;i>=0;i--) { if (enState[i]==E_DOWN) { if (targetX-8<=enX[i] && enX[i]<=targetX+8 && targetY-8<=enY[i] && enY[i]<=targetY+8) { enState[i]=E_BOM; } } } } //ポインティングデバイス操作 else if (pointing) { targetX=PointingDevice.getX(); targetY=PointingDevice.getY(); } //キー操作 else { if ((1<<Display.KEY_UP&j)!=0 && targetY>12) targetY-=8; if ((1<<Display.KEY_DOWN&j)!=0 && targetY<getHeight()-12) targetY+=8; if ((1<<Display.KEY_LEFT&j)!=0 && targetX>12) targetX-=8; if ((1<<Display.KEY_RIGHT&j)!=0 && targetX<getWidth()-12) targetX+=8; } //照準 g.drawImage(image[1],targetX-10,targetY-8); } //ゲームオーバー else { g.drawImage(image[4],(getWidth()-86)/2,40); } //スコア g.setColor(g.getColorOfName(g.WHITE)); g.drawString(String.valueOf(score),4,14); //宇宙船 g.drawImage(image[0],targetX-8,getHeight()-30); g.unlock(true); } //キーイベント public void processEvent(int type, int param) { if (type ==Display.KEY_PRESSED_EVENT && param==Display.KEY_SOFT1 && scene==S_GAMEOVER) { init=S_PLAY; } } //描画 public void paint(Graphics g) {} }
ポインティングデバイスの対応機種判定
ポインティングデバイスを使用可能に指定した時、例外が発生するかどうかで、対応機種かどうかの判定を行っています。使用可能な時はpointing変数にtrue、使用不可能な時はfalseを指定します。
ShootingCanvas.javaの一部 try { PointingDevice.setEnabled(true); pointing=true; } catch (Exception e) { pointing=false; }
スリープ
100ミリ秒に1回処理を行うために必要なスリープを行っています。
while (System.currentTimeMillis()<sleepTime+100);
sleepTime=System.currentTimeMillis();
System.currentTimeMillis()メソッドは、ミリ秒で表される現在の時間(現在時刻と協定世界時のUTC1970年1月1日午前0時との差)を返すメソッドです。端末によっては精度が良くない端末もあります。sleepTime変数にスリープ完了した時の時間を指定し、次のスリープ時には、その時間から100ミリ秒経つまで空のループを行って処理を止めています。
シーンの遷移
このゲームには以下の2つのシーンがあります。現在のシーンはscene変数で保持しています。次に遷移するシーンはinit変数で保持しています。遷移しない時はinitは-1を保持しています。
- プレイ(S_PLAY)
実際にゲームをプレイするシーンです。隕石が地球に落下した時「ゲームオーバー」に遷移します。- ゲームオーバー(S_GAMEOVER)
ゲームオーバーという文字を表示するシーンです。ソフトキー1を押すと「プレイ」に遷移します。
隕石の状態遷移
隕石には以下の3つの状態があります。現在の状態はenState配列で保持しています。8つの隕石の状態を保持するので、配列の長さは8です。
- なし(E_NONE)
画面に表示していない状態です。毎フレーム100分の5の確率で「落下」に遷移します。- 落下(E_DOWN)
画面上から下に移動する状態です。レーザー打たれると「爆発」にし、画面下まで移動すると「なし」に遷移します。- 爆発(E_BOM)
爆発を表示する状態です。すぐに「なし」に遷移します。
キー状態の取得
キー状態を取得するには、CanvasクラスのgetKeypadState()メソッドを使います。processEvent()メソッドでは、キーを押したというイベントが発生するたびに、任意の処理を行っていました。それに対し今回のgetKeypadState()メソッドは、現在どのキーが押されているかという情報を取得して、それに対応した処理を行います。
int getKeypadState()
戻り値:キー状態
戻り値の各ビットの位置がDisplayクラスで定義されているキー定数に対応します。 ビットとキーの対応は、1<<(Displayクラスで定義されているキーの値) となります。 押された状態になっているキーに対応するビットは1に、 押されていない状態になっているキーに対応するビットは、0になります。
キー定数 意味 値 KEY_0 0キー 0 KEY_1 1キー 1 KEY_2 2キー 2 KEY_3 3キー 3 KEY_4 4キー 4 KEY_5 5キー 5 KEY_6 6キー 6 KEY_7 7キー 7 KEY_8 8キー 8 KEY_9 9キー 9 KEY_ASTERISK *キー 10 KEY_POUND #キー 11 KEY_LEFT 左キー 16 KEY_UP 上キー 17 KEY_RIGHT 右キー 18 KEY_DOWN 下キー 19 KEY_SELECT 選択キー 20 KEY_SOFT1 ソフトキー1 21 KEY_SOFT2 ソフトキー2 22
2進数に直してみると分かりやすいでしょう。
2キーを押す →4 4を2進数にすると 00000100
3キーを押す →8 8を2進数にすると 00001000
2キーと3キー同時押し→12 12を2進数にすると 00001100
特定のキーが押されているかどうかは、getKeypadState()メソッドで取得した値と「1<<(Displayクラスで定義されているキーの値)」の値を&で計算して0になるかどうかでわかります。
| ★おわりに★ |
次回は、「J2ME Personal Profile for Zaurus」を使って、「Zaurus SL-C700」で動くゲームを作る予定です。お楽しみに。
−戻る−
(C)Npaka/Sehira, 2003-2004