
| ★はじめに★ |
![]() |
第5話 ゲームボーイアドバンスで動くMIDP2.0のゲームを作る [JAVA PRESS Vol.32] ゲーム:アクションゲーム 対応端末:ゲームボーイアドバンス・ゲームボーイアドバンスSP
|
![]() |
へにへに〜、今回はボーダフォンのゲーム作ってみない?J-SH53って機能満載でちょっとカッコイイから、ついうっかり契約してきちゃった。SH53で拡張された3Dグラフィックスや音声認識の機能ってすっごいし、シーマンみたいなの作れるんじゃない? | |
| う〜ん、 せっかくそらみちゃんがやる気まんまんなところ残念だけど、J-SH53の新機能を使うために必要な開発ツールは一般公開されてないんだよね…。 | ![]() |
|
![]() |
ケチくさっ! ボーダフォンはJ-PHONEのときからしてそんな姿勢だから、一般ユーザーが作った無料面白アプリもなかなか増えやしないんだよね。メールアドレスも無理やり変えられちゃうし、解約してやるっ!! | |
| まぁまぁ、そらみちゃん落ち着いて。そこはかとないプリティフェイスが台無しだよ。気分転換がてら、今回はMIDP2.0のゲームでも作ってみないかい? | ![]() |
|
![]() |
MIDP2.0って…、ボーダフォンやauで使われてるJavaの仕様はMIDP1.0だよね?作ってみても実際に携帯端末で動かせないとつまんないよぉ…。 | |
| ふっふっふ、実はMIDP2.0を動かせる携帯端末があるんだよ…。そらみちゃんもよく知ってるこの端末! | ![]() |
|
![]() |
うわぁ、ゲームボーイアドバンス!?…と、ちょっぴりアングラな香り漂う、不格好に本体から突き出たカートリッジ…。 | |
| めっ! そらみちゃん、そんなこと言っちゃだめ! 普通のゲームボーイ用ソフトだってアドバンスに挿したら不格好に突き出るでしょ!?これは「JEMBlazer」といって、ゲームボーイアドバンスでMIDP2.0のアプリを実行できる 凄いカートリッジなんだよ! |
![]() |
|
![]() |
とりあえず、ボーダフォンよりは面白そうだし、やってみよ〜♪ | |
| ・・・・・・(汗) | ![]() |
| ★MIDP2.0の新機能★ |
MIDP2.0とは
「MIDP(Mobile Information Device Profile)1.0」は、ボーダフォンやauの携帯電話をはじめとする多くの携帯端末で採用されているJavaのAPI仕様です。携帯電話だけでなくPDAまでも視野に入れて設計されている仕様で、Palmでも動きます。しかし、携帯端末の進化ははやく、MIDP1.0の仕様だけではアプリ作成には不十分となり、結果としてキャリア(ボーダフォンやauなどの通信事業者)ごとの拡張APIが乱立するようになりました。そこで、端末依存のAPIを使わなくてもすむように、MIDP1.0を拡張して作られたものが「MIDP2.0」です。2003年8月現在、MIDP2.0のアプリが実行できる端末は、ゲームボーイアドバンスのみです。
MIDP2.0の新機能
MIDP2.0の新機能には、次のようなものがあります。
- 音の再生
MIDP1.0では警告音しか鳴らせませんでしたが、MIDP2.0からは音楽ファイルを再生するAPIが用意されました。ただし、MIDP2.0を採用しているすべての端末で、音楽ファイルを再生できるわけではありません。- ユーザーインタフェースの強化
MIDP1.0ではボタンやダイアログのような基本的なユーザーインタフェースが用意されていませんでした。MIDP2.0からはユーザーインタフェースの自作や自由な配置ができるようになりました。- ゲーム対応
「ダブルバッファリング」や「キー状態の取得」などのゲームに役立つ機能が追加されました。詳しくは実際にゲームを作る時に説明します。- 接続制の強化
MIDP1.0ではHTTP通信のみでしたが、MIDP2.0ではHTTPS・データグラム・ソケット・サーバーソケット・シリアルポート接続を行うAPIが用意されました。サーバーからの情報のプッシュ配信にも対応しました。アプリを登録しておくと、端末がサーバーから情報を受け取った時点でアクティブ化できます。- セキュリティの強化
暗号化したデータの転送を行うAPIが用意されました。- OTA(Over-The-Air)プロビジョニング
「MIDP1.0」ではアプリのダウンロード方法に関する仕様が決まっていなかったため、同じMIDPのアプリが動く端末でも、キャリアごとに異なるダウンロードサイトを作らなければなりませんでした。そこで、MIDP2.0ではダウンロード方式を「OTAプロビジョニング」という仕様で統一することになりました。
| ★開発環境を整える★ |
今回のゲームを作るのに必要な開発ツールは次の4つです。
Java 2 SDK, Standard Edition Version 1.4(JDK1.4以降)
パソコン上で動くJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。次に説明する「J2ME Wireless Toolkit」を実行するのに必要なので、それより先にインストールします。インストーラの指示に従ってインストールしてください。JDK1.3でない点に注意してください。
J2ME Wireless Toolkit 2.0
MIDP2.0仕様のJavaアプリを作るための開発キットです。サン・マイクロシステムズのサイトで入手できます。インストーラの指示に従ってインストールします。
JEMBlazer
MIDP2.0仕様のJavaアプリをゲームボーイアドバンスで動かすためのツール郡です。Java仮想マシンが載った「JEMBlazerカートリッジ」や、MIDP2.0仕様のJavaアプリ(JARファイルとJADファイル)をゲームボーイアドバンス用の実行ファイル(BRLファイル)に変換するツール「MIDletBuilder」などが含まれています。JEMBlazerのサイトで購入でき、価格は$226です。インストーラの指示に従ってインストールしてください。
MMCカードリーダー/ライター
「MMC(MultiMediaCard)」は、携帯音楽プレーヤーなどでよく使われるメモリカードです。JEMBlazerはMMCカード経由でアプリをパソコンからゲームボーイアドバンスに移すので、パソコンからMMCカードの読み書きを行う「MMCカードリーダー/ライター」が必要となります。パソコンショップ等で購入してください。
| ★文字列を表示する★ |
まずはじめに、「Hello World!」という文字列を表示するプログラム「HelloWorld」を作ります。今回のプログラムは、以下の2つのクラスで構成されています。
- HelloWorldクラス ‐本体・HelloCanvasクラス‐キャンバス
プロジェクトの作成
「J2ME Wireless Toolkit」がインストールできたら、Windowsのスタートメニューに「プログラム - J2ME Wireless Toolkit 2.0 - KToolbar」が追加されているので、それを選択してください。「J2ME Wireless Toolkit」の核となるツール「KToolbar」が起動します。
[New Project]ボタンを押すと、「New Projectダイアログ」が開くので、「Project Name」と「MIDlet Class Name」に"HelloWorld"と入力します。
「MIDlet Class Name」はアプリで一番はじめに実行されるクラスの名前です。[Create Project]ボタンを押すと、「J2ME Wireless Toolkit」のルートにあるappsディレクトリの下に「Project Name」と同じ名前のディレクトリ(今回は"HelloWorld")が生成されます。さらにその下に以下の4つのディレクトリが生成されています。アプリの属性を設定する「Settings for project "HelloWorld"ダイアログ」が開きますが、今回は要ないので、そのまま[OK]ボタンを押して閉じてください。
- binディレクトリ
JARファイル(*.jar)とJADファイル(*.jad)がここに生成されます。JARファイルは、アプリの実行に必要なクラスファイルや画像ファイルを1つにまとめたファイルです。JADファイルはアプリの名前やファイルサイズなどの属性を保持するテキストファイルです。- resディレクトリ
JARファイルに含ませる画像ファイルや音声ファイルを置くディレクトリです。- srcディレクトリ
プログラムファイルを置くディレクトリです。- libディレクトリ
今回は使用しません。
HelloWorldクラス
HelloWorldクラスは、プログラムの本体となるクラスです。
HelloWorld.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; //HelloWorld(本体) public final class HelloWorld extends MIDlet { //コンストラクタ public HelloWorld() { Display.getDisplay(this).setCurrent(new HelloCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
import
はじめの"import"というのはパッケージを使う時に使う予約語で、ここでは「javax.microedition.lcduiパッケージ」と「javax.microedition.midletパッケージ」を使うことを宣言しています。次で説明する「MIDletクラス」や「Displayクラス」がこれらのパッケージに含まれています。
HelloWorld.javaの一部 import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
MIDletクラス
アプリの本体となるクラスは、「MIDletクラス」を継承します。
HelloWorld.javaの一部 public class HelloWorld extends MIDlet {
MIDletを継承したクラスは、以下の3つのメソッドを必ず持つ(オーバーライドする)必要があります。今回は何も行わないので全て空です。
- startApp()メソッド ‐ アプリの開始時によばれます。
- pauseApp()メソッド ‐ アプリの一時停止時に呼ばれます。
- destroyApp()メソッド ‐ アプリの終了時に呼ばれます。
Displayクラス
DisplayクラスのgetDisplay()メソッドでDisplayクラスのオブジェクトを取得し、そのオブジェクトのsetCurrent()メソッドで、実機の画面に表示するキャンバス等を指定します。キャンバスとは文字列や絵などのグラフィックを表示するためのものです。
static Display getDisplay(MIDlet midlet)
midlet:MIDletクラスのオブジェクト
戻り値:Displayクラスのオブジェクト
void setCurrent(Displayable displayable)
displayable:画面に表示するもの(キャンバス等)
今回は、次で説明するHelloCanvasクラスのオブジェクトをセットしています。
HelloWorld.javaの一部 Display.getDisplay(this).setCurrent(new HelloCanvas());
HelloCanvasクラス
HelloCanvasクラスは、キャンバスとなるクラスです。
HelloCanvas.java import javax.microedition.lcdui.*; //HelloWorld(キャンバス) class HelloCanvas extends Canvas { //描画 public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(0,0,0); g.drawString("Hello World!",0,0,g.LEFT|g.TOP); } }
Canvasクラス
キャンバスとなるクラスは、Canvasクラスを継承します。Canvasを継承したクラスは、paint()メソッドを必ず持つ(オーバーライドする)必要があります。paint()メソッドは、アプリ起動時や、再描画が必要な時に呼ばれます。このpaint()メソッドに渡されるGraphicsクラスを操作することにより、画面に文字列や絵などを表示します。
void paint(Graphics g)
g:グラフィックス
Graphicsクラス
Graphicsクラスには、画面に文字列や絵などの表示を行なうためのメソッドが用意されています。
色を指定するには、setColor()メソッドを使います。このメソッドを使った後、それ以降の文字列や図形の描画時に、指定された色が適用されます。
void setColor(int red,int green,int blue)
red :赤(0〜255)
green:緑(0〜255)
blue :青(0〜255)
画面を塗り潰すには、fillRect()メソッドを使います。引数には、矩形の左上のXY座標と、幅・高さを指定します。
void fillRect(int x,int y,int width,int height)
x :X座標
y :Y座標
width :幅
height:高さ
文字列を表示するのでdrawString()メソッドを使います。
void drawString(String str,int x,int y,int align)
str :表示する文字列
x :X座標
y :Y座標
align:配置
strには表示する文字列を指定します。ただし、使用できるのは英数字のみで、日本語を指定すると文字化けします。
align引数には配置定数を指定します。指定した座標に文字列の左上を配置したい時は"Graphics.LEFT|Graphics.UP"を指定します。
配置定数 Graphics.TOP 上 Graphics.BOTTOM 下 Graphics.LEFT 左 Graphics.RIGHT 右 Graphics.HCENTER 水平中央 Graphics.VCENTER 垂直中央
今回は、画面全体を白で塗り潰した後、黒で"Hello World!"という文字を表示するので、以下のようになります。
HelloCanvas.javaの一部 g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0,0,0);
g.drawString("Hello World!",0,0,g.LEFT|g.TOP);
ビルドとエミュレータでの実行
プログラムファイルをsrcディレクトリに置いて、[Build]ボタンを押してコンパイルし、メニューの[Project - Package - CreatePackage]でJARファイルを生成します。「Deviceコンボボックス」でデバイスを選んで[Run]ボタンを押すとエミュレータで実行できます。
ゲームボーイアドバンスのエミュレータで実行したい時は、"C:\aJile\JEMBlazer\Emulator\wtklib\devices\JEMBlazer"ディレクトリを"C:\WTK20\wtklib\devices"ディレクトリの下にコピーして、KToolbarを起動しなおしてください。DeviceコンボボックスにJEMBlazerが追加されているので、それを選択して[Run]ボタンを押します。ただし、実機とはフォントサイズが若干違い、ABLRボタンも効かないので注意してください。
画面サイズ LARGEフォント MEDIUMフォント SMALLフォント ゲームボーイアドバンス 240x141 7x13 7x13 7x13 エミュレータ 240x139 7x20 6x16 5x12
![]()
ゲームボーイアドバンスで実行する
ゲームボーイアドバンスで実行するには、JARファイルとJADファイルをゲームボーイアドバンス用の実行ファイル「BRLファイル(*.brl)」に変換する必要があります。「JEMBlazer」に含まれている「MIDletBuilder」を使ってこの変換を行います。「MIDletBuilder」の実行ファイル(C:\aJile\MIDletBuilder\MIDletBuilder.exe)をダブルクリックして起動してください。
最初に、次の3種類のターゲットから作成したい実行ファイル形式を選択します。「JEMBlazerデスクトップ」は、JEMBlazerカートリッジに複数のアプリを入れて、その中から選択して起動するための管理ツールです。今回はこのJEMBlazerデスクトップを使うので、メニューの[Target - JEMBlazerDesktop」を選択してください。
- JEMBlazerStandaloneRAM
デバッグ機能付きで単独アプリとして実行する。- JEMBlazerStandaloneFlash
単独アプリとして実行する。- JEMBlazerDesktop
JEMBlazerデスクトップ上で実行する。
次に「JAD File」に変換対象となるJADファイルを、「Output Directory」に変換後のBRLファイルの出力先ディレクトリを指定します。[Browse...]ボタンを使って指定してください。
最後に、メニューの「File - Build」を選択します。成功すれば出力先ディレクトリに「HelloWorld.brl」が生成されます。
「HelloWorld.brl」が生成できたらMMCに書き込み、ゲームボーイアドバンスにJEMBlazerカートリッジを、JEMBlazerカートリッジにMMCを挿し込みます。そして、ゲームボーイアドバンスの電源をONにすると、JEMBlazerデスクトップが起動します。HelloWorldアイコンが表示されるので選択すれば、HelloWorldが実行されます。
| ★絵を表示する★ |
次に、絵を表示するプログラム「ImageEx」を作ります。今回のプログラムは、以下の2つのクラスで構成されています。「Project Name」「MIDlet Class Name」に"ImageEx"を指定して、プロジェクトを作成してください。
- ImageExクラス ‐本体
- ImageCanvasクラス‐キャンバス
画像ファイルの用意
このプログラムでは1枚の画像ファイルを使います。この画像ファイルをImageExディレクトリの下のresディレクトリに置いてください。MIDPで扱える画像形式はPNG-8形式です。
・そらみ
-sorami.png
-140x140
ImageExクラス
ImageExクラスは、プログラムの本体となるクラスです。コンストラクタでキャンバスの生成だけを行っています。
ImageEx.java import javax.microedition.lcdui.*; import javax.microedition.midlet.*; //絵を表示する(本体) public class ImageEx extends MIDlet { //コンストラクタ public ImageEx() { Display.getDisplay(this).setCurrent(new ImageCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
ImageCanvasクラス
ImageCanvasクラスは、キャンバスとなるクラスです。
ImageCanvas.java import javax.microedition.lcdui.*; //絵を表示する(キャンバス) class ImageCanvas extends Canvas { private Image image;//イメージ //コンストラクタ public ImageCanvas() { try { image=Image.createImage("/sorami.png"); } catch (Exception e) { } } //描画 public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect(0,0,getWidth(),getHeight()); g.drawImage(image,getWidth()/2,getHeight()/2, g.VCENTER|g.HCENTER); } }
Imageクラス
ImageクラスのcreateImage()メソッドで画像ファイルを読み込みます。ファイル名には「/sorami.gif」のように頭に"/"をつけてください。
ImageCanvas.javaの一部 image=Image.createImage("/sorami.png");
drawImage()メソッド
GraphicsクラスのdrawImage()メソッドでイメージをキャンバスに描画します。
void drawImage(Image image,int x,int y,int anchor)
image :表示するイメージ
x :X座標
y :Y座標
anchor:配置
引数anchorはdrawString()メソッドと同じです。
| ★ボタン操作を行う★ |
次に、押されたボタンの名前をキャンバスに表示するプログラム「KeyEventEx」を作ります。今回のプログラムは、以下の2つのクラスで構成されています。「Project Name」「MIDlet Class Name」に"KeyEvent"を指定して、プロジェクトを作成してください。
- KeyEventExクラス ‐本体
- KeyEventCanvasクラス‐キャンバス
KeyEventExクラス
KeyEventExクラスは、プログラムの本体となるクラスです。コンストラクタでキャンバスの生成だけを行っています。
KeyEventEx.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; //ボタン操作を行う(本体) public final class KeyEventEx extends MIDlet { //コンストラクタ public KeyEventEx() { Display.getDisplay(this).setCurrent( new KeyEventCanvas()); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
KeyEventCanvasクラス
KeyEventCanvasクラスは、キャンバスとなるクラスです。
KeyEventCanvas.java import javax.microedition.lcdui.*; //ボタン操作を行う(キャンバス) class KeyEventCanvas extends Canvas implements CommandListener { private Command soft1; //ソフトキー1 private Command soft2; //ソフトキー2 private String output="?";//出力データ //コンストラクタ KeyEventCanvas() { soft1=new Command("SOFT1",Command.SCREEN,1); soft2=new Command("SOFT2",Command.SCREEN,2); addCommand(soft1); addCommand(soft2); setCommandListener(this); } //描画 public void paint(Graphics g) { g.setColor(255,255,255); g.fillRect(0,0,getWidth(),getHeight()); g.setColor(0,0,0); g.drawString(output,0,0,g.LEFT|g.TOP); } //キープレスイベント public void keyPressed(int keyCode) { //ゲームアクション int action=getGameAction(keyCode); if (action==UP) output="UP BUTTON"; if (action==DOWN) output="DOWN BUTTON"; if (action==LEFT) output="LEFT BUTTON"; if (action==RIGHT) output="RIGHT BUTTON"; if (action==FIRE) output="START BUTTON"; if (action==GAME_A) output="A BUTTON"; if (action==GAME_B) output="B BUTTON"; if (action==GAME_C) output="R BUTTON"; if (action==GAME_D) output="L BUTTON"; //再描画 repaint(); } //コマンドイベント public void commandAction(Command c,Displayable s) { //ソフトキー if (c==soft1) output="SOFT1"; if (c==soft2) output="SOFT2"; //再描画 repaint(); } }
キーイベント
キーイベントは、ゲームボーイアドバンスのボタンを操作した時に発生するイベントです。ボタンを押した時にはkeyPressed()メソッド呼ばれ、ボタンを離した時はkeyReleased()メソッドが呼ばれます。
public void keyPressed(int keyCode)
keyCode:キーコード
public void keyReleased(int keyCode)
keyCode:キーコード
キーコードをCanvasクラスのgetGameAction()メソッドに渡して得られる値「ゲームアクション」によって、どのボタン押されたかを判断します。
int getGameAction(int keyCode)
keyCode:キーコード
戻り値 :ゲームアクション
ゲームアクション Canvas.UP 上ボタン Canvas.DOWN 下ボタン Canvas.LEFT 左ボタン Canvas.RIGHT 右ボタン Canvas.FIRE スタートボタン Canvas.GAME_A Aボタン Canvas.GAME_B Bボタン Canvas.GAME_C Rボタン Canvas.GAME_D Lボタン
KeyEventCanvas.javaの一部 int action=getGameAction(keyCode);
if (action==UP) output="UP BUTTON";
if (action==DOWN) output="DOWN BUTTON";
if (action==LEFT) output="LEFT BUTTON";
if (action==RIGHT) output="RIGHT BUTTON";
if (action==FIRE) output="START BUTTON";
if (action==GAME_A) output="A BUTTON";
if (action==GAME_B) output="B BUTTON";
if (action==GAME_C) output="R BUTTON";
if (action==GAME_D) output="L BUTTON";
ただし、ゲームボーイアドバンスのエミュレータでは、ABLRボタンが効かないので注意してください。
コマンドの生成
画面下端に表示されるメニューを「コマンド」と呼びます。コマンドを生成するには、Commandクラスを使います。
labelには、メニューとして表示する文字列を指定します。
Command(String label,int type,int priority)
label :ソフトラベル
type :コマンドタイプ
priority:優先度
typeには、コマンドタイプ定数を指定します。コマンドタイプはコマンドの種別を識別するためだけのもので、BACKを指定したら前画面に戻るというわけではありません。基本的にCommand.SCREENを指定すれば良いです。
コマンドタイプ定数 Command.BACK バック Cinnabd.CANCEL キャンセル Command.HELP ヘルプ Command.ITEM アイテム Command.SCREEN スクリーン Command.STOP ストップ
priorityには、優先度を指定します。優先度の順番に応じてソフトキーの配置が変わり、
ゲームボーイアドバンスでは、小さい値のものから右下・左下の順に配置されます。ただし、エミュレータでは、右下にまとめて表示されます。
今回は、ラベルが"SOFT1"、コマンドタイプがCommand.SCREEN、優先度が1のソフトキー1と、ラベルが"SOFT12"、コマンドタイプがCommand.SCREEN、優先度が2のソフトキー2を生成するので、以下のようになります。
KeyEventCanvas.javaの一部 soft1=new Command("SOFT1",Command.SCREEN,1);
soft2=new Command("SOFT2",Command.SCREEN,2);
コマンドの追加と削除
コマンドを画面に追加するにはDisplayableクラスのaddCommand()メソッドを、削除するにはremoveCommand()メソッドを使います。CanvasクラスはDisplayableクラスを継承しているので、この2つのメソッドを持っています。
void addCommand(Command command)
command:Commandクラスのオブジェクト
void removeCommand(Command command)
command:Commandクラスのオブジェクト
今回は、Commandオブジェクトのsoft1とsoft2をキャンバスに追加するので、以下のようになります。
KeyEventCanvas.javaの一部 addCommand(soft1);
addCommand(soft2);
コマンドイベント
「セレクトボタン+Bボタン」で優先順位1番目のコマンド、「セレクトボタン+Aボタン」で優先順位2番目のコマンドが実行され、CommandListenerのcommandAction()メソッドを呼びます。
今回は、KeyEventCanvasクラス自身にcommandAction()メソッド持たせるので、CommandListenerインタフェースを実装し、DisplayableクラスのsetCommandListener()メソッドでコマンドイベントの通知先を自身に指定します。
KeyEventCanvas.javaの一部 class KeyEventCanvas extends Canvas
implements CommandListener {
KeyEventCanvas.javaの一部 setCommandListener(this);
commandAction()メソッドの書式は次の通りです。
cにはイベント発生元となるCommandオブジェクト、sにはイベント発生元となるDisplayableオブジェクトが渡されます。
void commandAction(Command c,Displayable s)
c:イベント発生元となるCommandオブジェクト
s:イベント発生元となるDisplayableオブジェクト
今回は、「セレクトボタン+Bボタン」で"SOFT1"、「セレクトボタン+Aボタン」で"SOFT2"とキャンバスに表示するので、以下のようになります。
KeyEventCanvas.javaの一部 if (c==soft1) output="SOFT1";
if (c==soft2) output="SOFT2";
| ★アクションゲームを作る★ |
それでは、本題の「アクションゲーム」を作ります。スタートボタンを押すとゲームが開始します。そらみは強制的に右に移動するので、Aボタン(または上ボタン)でジャンプしながら、下に落ちないように進んでください。どれだけ進むことができたかがスコアとなります。このゲーム以下の2つのクラスで構成されています。「Project Name」「MIDlet Class Name」に"ActinGame"を指定して、プロジェクトを作成してください。
- ActionGameクラス ‐本体
- ActionCanvasクラス‐キャンバス
![]()
画像ファイルの用意
このゲームでは以下の4枚の画像ファイルを使います。ActionGameディレクトリの下のresディレクトリに置いてください。
・そらみA
-0.png
-30x33
・そらみB
-1.png
-30x33
・地面
-2.png
-30x30
・ゲームオーバー
-3.png
-86x16
ActionGameクラス
ActionGameクラスは、プログラムの本体となるクラスです。コンストラクタで、キャンバスとスレッドの生成を行っています。
ActionGame.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; //アクションゲーム(本体) public class ActionGame extends MIDlet { //コンストラクタ public ActionGame() { //キャンバス ActionCanvas canvas=new ActionCanvas(); Display.getDisplay(this).setCurrent(canvas); //スレッド Thread thread=new Thread(canvas); thread.start(); } //アプリの開始 public void startApp() { } //アプリの一時停止 public void pauseApp() { } //アプリの終了 public void destroyApp(boolean unconditional) { } }
ActionCanvasクラス
ActionCanvasクラスは、キャンバスとなるクラスです。
ActionCanvas.java import javax.microedition.lcdui.game.*; import javax.microedition.lcdui.*; import java.util.Random; //横スクロールアクションゲーム(キャンバス) class ActionCanvas extends GameCanvas implements Runnable { //シーン private final static int S_TITLE =0,//タイトル S_PLAY =1,//プレイ S_GAMEOVER=2;//ゲームオーバー //システム private int init=S_TITLE; //初期化 private int scene; //シーン private int score; //スコア private int event; //イベント private Image[] image=new Image[4];//イメージ private Graphics g; //グラフィクス private Random rand=new Random(); //乱数 //そらみ private int soramiY; //Y座標 private int jumpPow; //ジャンプ力 private boolean jumpAble;//ジャンプ可 //地面 private int mapDX; //X相対位置 private int[] mapH=new int[10];//高さ //コンストラクタ ActionCanvas() { super(false); } //メインループ public void run() { try { //初期化 g=getGraphics(); for (int i=0;i<4;i++) { image[i]=Image.createImage("/"+i+".png"); } //メインループ while (true) { tick(); Thread.sleep(60); } } catch (Exception e) { } } //処理 private void tick() throws Exception { int i; //初期化 if (init>=0) { scene=init; init=-1; //タイトル・プレイ if (scene==S_TITLE || scene==S_PLAY) { score =0; soramiY =getHeight()-63; jumpPow =0; jumpAble=true; mapDX =0; for (i=0;i<10;i++) mapH[i]=1; } event=-999; } //背景 int red =35; int green=100; int blue =200; for (i=0;i<15;i++) { g.setColor(red,green,blue); g.fillRect(0,10*i,getWidth(),10); red +=20;if (red >255) red =255; green+=20;if (green>255) green=255; blue +=20;if (blue >255) blue =255; } //そらみ i=1; if (jumpAble) i=score%2; g.drawImage(image[i],45,soramiY,g.LEFT|g.TOP); //地面 for (i=0;i<mapH.length;i++) { g.drawImage(image[2],mapDX+i*30, getHeight()-mapH[i]*30,g.LEFT|g.TOP); } //スコア g.setColor(0,0,0); g.drawString(""+score,5,3,g.LEFT|g.TOP); //プレイ if (scene==S_PLAY) { //スコアアップ score++; //衝突判定 if (soramiY>getHeight()-33-mapH[2]*30) { init=S_GAMEOVER; jumpAble=false; } //上移動 else if (jumpPow>=0) { soramiY-=jumpPow*2; jumpPow--; } //下移動 else { soramiY+=6; jumpAble=false; if (mapH[2]!=0 && soramiY>getHeight()-33-mapH[2]*30) { soramiY=getHeight()-33-mapH[2]*30; jumpAble=true; } } //右移動 mapDX-=3; if (mapDX==-30) { mapDX=0; //地面の高さを左にシフト System.arraycopy(mapH,1,mapH,0,9); //地面の高さを指定 i=(rand.nextInt()>>>1)%6; if (mapH[8]==0) { mapH[9]=mapH[7]; } else if (i==0) { mapH[9]=0; } else if (i==1) { mapH[9]=mapH[8]+1; if (mapH[9]>4) mapH[9]=4; } else if (i==2) { mapH[9]=mapH[8]-1; if (mapH[9]<1) mapH[9]=1; } } //イベント i=getKeyStates(); if (jumpAble) { if ((i&(UP_PRESSED|GAME_A_PRESSED))!=0) { jumpAble=false; jumpPow =9; event=-999; } } else { if ((i&(UP_PRESSED|GAME_A_PRESSED))==0) { jumpPow=-10; } } } //ゲームオーバー if (scene==S_GAMEOVER) { //そらみ落下 if (soramiY<getHeight()+33) soramiY+=12; //ゲームオーバー表示 g.drawImage(image[3],getWidth()/2,30,g.HCENTER|g.TOP); } //画面に反映 flushGraphics(); } //描画 public void paint(Graphics g) { } //キープレスイベント public void keyPressed(int keyCode) { if (scene!=S_PLAY && getGameAction(keyCode)==FIRE) init=S_PLAY; } }
シーン
このゲームには以下の4つのシーンがあります。現在のシーンはscene変数で保持しています。次に遷移するシーンはinit変数で保持しています。遷移しない時はinitは-1を保持しています。
- タイトル(S_TITLE)
アプリ起動時のシーンです。スタートボタンを押すとゲームが開始し、シーンは「プレイ」に遷移します。- プレイ(S_PLAY)
実際にゲームをプレイするシーンです。そらみが下に落ちた時、「ゲームオーバー」に遷移します。- ゲームオーバー(S_GAMEOVER)
"GameOver"と表示するシーンです。スタートボタンを押すとゲームが開始し、シーンは「プレイ」に遷移します。
GameCanvasクラス
ActionCanvasクラスはGameCanvasクラスを継承しています。GameCanvasクラスはCanvasクラスを拡張したクラスで、「ダブルバッファリング」や「キー状態の取得」などのゲームに役立つ機能が使用できます。
「ダブルバッファリング」は、画面と同じサイズのイメージを用意し、必要なものをこのイメージに描画してから、実際の画面に一変に反映させるという処理で、画面のチラツキを防ぎます。GameCanvasクラスのgetGraphics()メソッドでGraphicsオブジェクトを取得し、それに必要な描画を行い、最後にflushGraphics()メソッドを呼んで実際の画面に反映します。
ActionCanvas.javaの一部 g=getGraphics();
ActionCanvas.javaの一部 flushGraphics();
「キー状態の取得」は、現在どのキーが押されているかを調べる機能です。「キーイベント」や「コマンド」がボタンを操作した時に処理を行っていたのに対し、「キー状態の取得」では現在どのキーが押されているかによって、それに応じた処理を行います。GameCanvasクラスのgetKeyStates()メソッドを使います。
int getKeypadState()
戻り値:キー状態
戻り値の各ビットの位置がGameCanvasクラスで定義されているキー定数に対応します。
キー定数 GameCanvas.UP_PRESSED 上ボタン GameCanvas.DOWN_PRESSED 下ボタン GameCanvas.LEFT_PRESSED 左ボタン GameCanvas.RIGHT_PRESSED 右ボタン GameCanvas.FIRE_PRESSED スタートボタン GameCanvas.GAME_A_PRESSED Aボタン GameCanvas.GAME_B_PRESSED Bボタン GameCanvas.GAME_C_PRESSED Rボタン GameCanvas.GAME_D_PRESSED Lボタン
特定のキーが押されているかどうかは、getKeyStates()メソッドで取得した値と「GameCanvasクラスで定義されているキー定数」の値を&で計算して0になるかどうかでわかります。
今回のプログラムは、Aボタンか上ボタンを押している時、ジャンプ処理を行うので以下のようになります。
ActionCanvas.javaの一部 if ((i&(UP_PRESSED|GAME_A_PRESSED))!=0) {
スクロール処理
地面がスクロールする処理は、mapDX変数と、mapH配列で行っています。mapH配列には10個分の地面の高さの情報が格納されています。右から左へ地面1つ分(30ドット)スクロールしては、次の地面の高さをランダムに指定するという処理を繰り返しています。
ActionCanvas.javaの一部 mapDX-=3; if (mapDX==-30) { mapDX=0; //地面の高さを左にシフト System.arraycopy(mapH,1,mapH,0,9); //地面の高さを指定 i=(rand.nextInt()>>>1)%6; if (mapH[8]==0) { mapH[9]=mapH[7]; } else if (i==0) { mapH[9]=0; } else if (i==1) { mapH[9]=mapH[8]+1; if (mapH[9]>4) mapH[9]=4; } else if (i==2) { mapH[9]=mapH[8]-1; if (mapH[9]<1) mapH[9]=1; } }
ジャンプ処理
そらみのジャンプ処理は、jumpAble変数と、jumpPow変数で行っています。jumpAble変数はジャンプできる状態にあるかどうかを示します。そらみがのすぐ下に地面がある時はtrue、ない時はfalseを保持します。jumpPow変数はジャンプ力を示します。Aボタン(または上ボタン)が押された時jumpAbleがtrueなら、jumpPowに9がセットされ、上昇しながら1ずつ減っていき、0以下になったら下降しはじめます。ボタンを離した時にはjumpPowに-10がセットされ、ただちに下降しはじめます。
ActionCanvas.javaの一部 i=getKeyStates(); if (jumpAble) { if ((i&(UP_PRESSED|GAME_A_PRESSED))!=0) { jumpAble=false; jumpPow =9; event=-999; } } else { if ((i&(UP_PRESSED|GAME_A_PRESSED))==0) { jumpPow=-10; } }
| ★おわりに★ |
次回は、Phase2.5の新機能を使ったEZアプリ(Java)を作る予定です。お楽しみに。
−戻る−
(C)Npaka/Sehira, 2003-2004