JAVAプログラミング講座  宇宙のJAVAさん外伝
「 第七銀河の彼方に 」


宇宙のJAVAさん外伝「第七銀河の彼方に」

- 第2話  時 空   -


くまがフィールドを歩くプログラム(1)

 

Mr X さて、iアプリプログラミングの続きです。

Mr X 今回はRPGっぽいフィールドをキャラが移動するプログラムを説明します。

みゃあ うし君 はーい!

Mr X こんな感じで、くまが前後左右に移動します。

Mr X まずは、プログラムをダウンロードしてください。

 

くまが歩くプログラム

 sample.lzh (11k)

 

展開すると、「SampleiApp」というフォルダができます。
そのフォルダ中にプログラムソースと画像ファイルが入ってます。

前回の講座で作った「C:\DoJa」の下に、この「SampleiApp」というフォルダを移動してください。

GiGA-Appli Developer's Kit の「プロジェクトを開く」を押して、C:\DoJa の下の「SampleiApp」を開いてください。

みゃあ できたみゃ。

Mr X では、最初にエミュレータで動かしてみましょう。
ダウンロードしたファイルには、すでにコンパイル済みのファイルが入っているので「エミュレータ起動」ボタンを押すと、プログラムが動作します。

Mr X 上下左右ボタンで、くまさんが移動すると思います。

うし君 ほんとだも〜

Mr X では、「SampleiApp.java」を選んで、「ソース編集」を押してください。
エディタ(メモ帳等)でソースファイルが開いたと思います。
さっそく、プログラムの説明をしましょう。

Mr X 本当は「JAVA講座 宇宙のJAVAさん」みたいに、順を追ってプログラムを作りながら説明したいのですが、今回は完成(?)しているプログラムを説明していきます(*1)

Mr X これが、ソースファイルです。
では、上から見ていきましょう。

import com.nttdocomo.ui.*;
import com.nttdocomo.io.*;

// ==========================================
// ========== CanvasTestクラス ==========
// ==========================================
public class SampleiApp extends IApplication {
 public void start() {
  // MyCanvasクラスを画面に表示
  MyCanvas c = new MyCanvas();
  Display.setCurrent(c);
 }
} // End of Class

 

import com.nttdocomo.ui.*;
import com.nttdocomo.io.*;

Mr X iアプリのクラスファイルを読み込んでます。
この2行は、お決まりの宣言です。

 

public class SampleiApp extends IApplication {
 <中略>
} // End of Class

Mr X  IApplication から継承された SampleiAppクラスがこのプログラムのメインクラスになります。

なんとか extends IApplication

で、「なんとか」 IApplication から継承されることになります。

 

 public void start() {
  // MyCanvasクラスを画面に表示
  MyCanvas c = new MyCanvas();
  Display.setCurrent(c);
 }

Mr X iアプリはメインクラスの中の「start()」から始まる! というお約束があるので、start() 関数を書きます。
プログラムはここから始まります。

で、何をやっているかというと、MyCanvas クラスを作成して、

  MyCanvas c = new MyCanvas();

作成した MyCanvasクラスを画面にセットしています。

  Display.setCurrent(c);

これで、画面全体に MyCanvasクラスが表示されます。
これで、メインクラス「SampleiApp」は全部です!

みゃあ あれ? MyCanvasクラスなんて、iアプリのクラスライブラリにあったかにゃ??
Canvasクラスなら聞いたことがあるみゃーが?

Mr X MyCanvas クラスは自作のクラスですよ。
それは、これから説明します。
ってゆぅーかぁー、
プログラムは MyCanvasクラスに書いてあるのです。
SampleiAppクラスは、ほとんど何もしていません。


Mr X 次に MyCanvas クラスを見ていきましょう。

// ==========================================
// ========== 自作キャンバスクラス ==========
// ==========================================
class MyCanvas extends Canvas {

 <中略>

} // End of Class

Mr X <中略>と書いてありますけど、全部で96行ほどあるプログラムリストです。
} // End of Class は、プログラムの一番下の行です。

 

class MyCanvas extends Canvas {

Mr X MyCanvas は、Canvasクラスから派生しています。
Canvasクラスから派生した MyCanvas には、自由にCGが描けます。
ここにゲーム画面を作画していきます。

Mr X では、MyCanvas の中身を上から見ていきましょう。

class MyCanvas extends Canvas {

 // === グローバル変数 ===
 int x, y;
 Image img[];
 char map[][];
 boolean isK = true;

Mr X すぐ下にグローバル変数の宣言があります。
グローバル変数は、MyCanvas全体で使用可能な変数です。
グローバル変数の内容は次のとおりです。

 int x, y;

くまさんの現在座標

 Image img[];

画像(くまや背景)

 char map[][];

マップデータ

 boolean isK = true;

くまさんの状態(左足を上げているかどうか?)

Mr X 次にコンストラクタを見てみましょう。
コンストラクタとは、MyCanvasクラスが実行される時に最初の動作する関数です。
JAVAアプレットの init() 関数と同じと考えて下さい。
コンストラクタはクラス名とおなじ名前の関数名を付けます。
よって、MyCanvasクラスのコンストラクタは MyCanvas() です。

// === コンストラクタ ===
MyCanvas() {
  x=20; y=20;
  img = new Image[5];
  // GIF画像読込み
  for(int i=0; i<5; i++){
    MediaImage mImg = MediaManager.getImage("resource:///"+i+".gif");
    try {
      mImg.use();
    } catch (com.nttdocomo.io.ConnectionException e) {
      System.out.println("Image Read Error !");
    }
    img[i] = mImg.getImage();
  }
  // マップ初期宣言
  map = new char[50][50];
  for(int xx=0; xx<50; xx++)
    for(int yy=0; yy<50; yy++) map[xx][yy]=3;
  for(int xx=5; xx<45; xx++)
    for(int yy=5; yy<45; yy++) map[xx][yy]=1;
  
  // ランダムで岩山を配置(200個)
  java.util.Random rnd;
  rnd = new java.util.Random() ;
  for(int xx=0; xx<200; xx++){
    int r1 = rnd.nextInt();
    if(r1<0) r1=-r1;
    int r2 = rnd.nextInt();
    if(r2<0) r2=-r2;
    map[r1%40+5][r2%40+5]=2;
  }

  // ファンクションキー設定(Exit)
  setSoftLabel(Frame.SOFT_KEY_1, "Exit");
} // Constructor

Mr X け、結構長いですね・・・
では、上から説明しましょう。

 

  x=20; y=20;
  img = new Image[5];

Mr X xに20、yに20を代入しています。
よってゲームスタート時のくまさんの最初の座標は(20,20)になります。
次に img を配列宣言しています。
くまさんと背景を合わせて5枚の画像があるからです。

 

  // GIF画像読込み
  for(int i=0; i<5; i++){
    MediaImage mImg = MediaManager.getImage("resource:///"+i+".gif");
    try {
      mImg.use();
    } catch (com.nttdocomo.io.ConnectionException e) {
      System.out.println("Image Read Error !");
    }
    img[i] = mImg.getImage();
  }

Mr X ここでは、画像ファイル(GIFファイル)を img 変数に読み込んでいます。
画像ファイルは resource フォルダに入っています。
resource フォルダを見てください。 次の5つの画像があると思います。

 0.gif

 1.gif

 2.gif

 3.gif

 4.gif

Mr X このプログラムで、各画像を img[] に収納しています。

 img[0] は 

 img[1] は 

 img[2] は 

 img[3] は 

 img[4] は 

 

  // マップ初期宣言
  map = new char[50][50];

Mr X map[][] を配列宣言します。 50x50 の2次元配列です。
これで全体のマップのサイズは 50 x 50 になります。

うし君 しつもんだも〜
なんで、map[][] は数字を入れるのに char 型なんだも??
普通 int型 にするも〜

Mr X それはですね。 メモリーがもったいないからなんですよ。
私が普通のコンピュータのプログラムを作るときは、もちろん int型にします。
しかし iアプリはメモリーが少なそうなので、念のため(?) char 型にしました。
多分 int型にしても問題ないとは思いますが・・・(ページ下、「追加コメント」参照)

うし君 なるほども。  640kの壁 を思い出すも〜

 

  for(int xx=0; xx<50; xx++)
    for(int yy=0; yy<50; yy++) map[xx][yy]=3;

Mr X 次に map[][]のすべての変数に 3 を代入します。
ちなみにこの数字は img[][] と連動しているので、すべて海の画像にしたことになります。
ちょっとわかりづらいプログラムですが、次のプログラムと同じ事をしています。

  for(int xx=0; xx<50; xx++) {
    for(int yy=0; yy<50; yy++) {
      
map[xx][yy]=3;
    }
  }

 

  for(int xx=5; xx<45; xx++)
    for(int yy=5; yy<45; yy++) map[xx][yy]=1;

Mr X そして次に、(5,5)-(44,44) までのmap[][]に、 1番(平原)を代入します。

Mr X この時点で、map[][] は、イメージ的には次のようになってます。

 

33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333111111111111111111111111111111111111111133333
33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333
33333333333333333333333333333333333333333333333333

 

Mr X ちなみに、map[][] は縦50、横50あるので、 本当はもっと巨大なマップです。

 

  // ランダムで岩山を配置(200個)
  java.util.Random rnd;
  rnd = new java.util.Random() ;
  for(int xx=0; xx<200; xx++){
    int r1 = rnd.nextInt();
    if(r1<0) r1=-r1;
    int r2 = rnd.nextInt();
    if(r2<0) r2=-r2;
    map[r1%40+5][r2%40+5]=2;
  }

Mr X map[][]の (5,5)-(44,44)の部分(平野の部分)に、ランダムで200個、2番(岩)を代入します。
これで、所々に岩があるマップが出来上がりました。

 

  // ファンクションキー設定(Exit)
  setSoftLabel(Frame.SOFT_KEY_1, "Exit");

Mr X 左側のファンクションキーに「Exit」という文字を設定します。
この文字は画面左下に出ます。
あとで、このボタンを押したらiアプリが終了するプログラムを作ります。 <イベント関数で

 

Mr X さて。
あとイベント関数の processEvent( ) と、作画関数の paint() が残ってますが、 これらは次回にしましょう。

 

Mr X では、さようなら! また次回!

 

うし君 なんか、中途半端な終わり方だも〜

みゃあ なんか、説明するのに疲れた感じがとてもででいるみゃ。

Mr X そのとおり!

 

      続く!

 

 

(*1) さいきん時間が無いでぷ〜(T_T)


J2ME Wireless SDK for the DoJa

Mr X いちおう DoCoMo開発ツール「J2ME Wireless SDK for the DoJa」用のサンプルソースも置いておきます。「J2ME Wireless SDK for the DoJa」をお使いの方はこれをダウンロードして、展開してください。
それで、J2MEWSDK4DOJAフォルダの下のappsフォルダに、展開してできた SampleiAppフォルダを移動してください。


追加コメント (2001.06.08.)

Mr X 裕樹さんからメールを頂き、「iアプリではintよりcharの方が、逆にファイルサイズが大きくなる場合があります」との事。
私のほうでもやってみましたら、本当にjarファイルのサイズがわずかに増えました。
こりはビックリ。 メモリー節約で char を使った私の立場は?
裕樹さん、情報ありがとうございます。


宇宙のJAVAさん外伝 (C) BakuretuKen 2001

戻る