コードの記述 その6 敵機に様々な動きをつける

現状では、敵機の動きがワンパターンだし、同じ経路しかたどっていないのではゲームになりません。敵機の動きに様々なバリエーションをもうけ、出現位置もランダムになるようにしてみましょう。

ではまず、出現位置をランダムに変えてみましょう。Notepad++にEnemy.javaのタブが表示されているはずです。このタブをクリックするとEnemy.javaの変数が可能になります。もし、Enemy.javaのタブがない場合は、iアプリ開発ツールの「プロジェクト」メニューから「ソースファイルを開く」を選択し、出てきたダイアログでEnemy.javaを選択し「開く」を押してください。Notepad++の画面にEnemy.javaのコードが表示されるはずです。

最初に6行目に以下の行を追加します。

import com.nttdocomo.ui.*;
import java.util.Random;

この行はJ2MEに用意されているRandomクラスを利用しますという意味になります。詳しくはVectorを調べた時と同じように、CLDC Library API 仕様を開いて参照してみてください。

次に9行目を以下のように変更します。

public class Enemy {
    int xpos = 0;
    int ypos = 0;

さらに、Enemy( )関数の頭の部分に、以下のコードを追加します。

    Enemy(Graphics g) {
        this.g = g;
        Random rand = new Random();
        xpos = rand.nextInt() % Display.getWidth();
        if (xpos < 0) {    //マイナスだと都合が悪いのでプラスにしてしまう
            xpos *= -1;
        }

ここでまた、保存と「ビルド」、「実行」を行います。こんどは、敵機の出てくる場所がランダムになったはずです。

次は1種類しかない敵機の動きのパターンを4種類に増やし、ランダムに変わるようにしてみましょう。まず、動きのパターンを4つに増やします。16行目近辺の敵機の動きの定義を以下のように書き換えます。

    // 敵機の左右と上下の動きの定義
    int [][] xDeltaArray = {
        {0, 1, 1, 1, 0, -1, -1, -1, 0, 0, 1, 0, 1, -1, 0, 1, 0, 1, 1, 0},
        {-1, 0, 1, 2, 1, 0, -1, -2, -1, 0, -1, -2, -1, 0, 1, 2, 1, 0, 0, 0},
        {0, 0, -1, -1, 0, 0, -1, -1, 0, 0, 1, 2, 1, 0, -1, -2, -1, 0, 1, 1},
        {1, 0, -1, -1, 0, 0, -1, -1, 0, 1, 1, 1, 0, 0, 1, -1, 1, 0, 1, 1},
        };
    int [][] yDeltaArray = {
        {1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
        {1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1},
        {1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 0, -1, -1, -1, 0, 1, 2, 1, 1},
        {1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1},
        };
    int [] xDelta, yDelta;

int [][] xDeltaArrayというのは、整数の2次元配列の変数xDeltaArrayというのを宣言しています。中括弧の中に、さらに4つの中括弧に囲まれた配列が宣言されています。つまり2次元の配列というのは、ある配列を1つの要素とした配列を表します。

では、さらに41行目近辺に、4つの動作パターンから、ランダムに1つを取り出すコードを追加しましょう。

       if (xpos < 0) {    //マイナスだと都合が悪いのでプラスにしてしまう
            xpos *= -1;
        }
        
        //敵の動きの選択
        int enemyNum = rand.nextInt() % 4;
        if (enemyNum < 0) {    //マイナスだと都合が悪いのでプラスにしてしまう
            enemyNum *= -1;
        }
        xDelta = xDeltaArray[enemyNum];
        yDelta = yDeltaArray[enemyNum];
        
        try {

ここでまた、保存してから「ビルド」、「実行」と順番に進めていきましょう。さて、だいぶゲームっぽい動きになってきたのではないでしょうか。

画面イメージ

ここでもうひとつ変更を加えたいと思います。敵機の出現間隔は、現状で900ミリ秒の設定になっていますが、時間の経過とともに出現間隔を少しずつ縮めて行きたいと思います。

編集の対象を、Enemy.javaからStarJet.javaに切り替えてください。切り替え方はNotepad++のタブをクリックするだけですね。もし、StarJet.javaのタブがなかったら、iアプリ開発ツールの「プロジェクト」メニューから「ソースファイルを開く」の選択でしたよね。

まず、34行目近辺に整数の変数appearTermを宣言を追加し、同時に900という初期値を代入します。

class MainCanvas extends Canvas implements TimerListener{
    Graphics g = getGraphics();
    Fighter fighter = new Fighter(g);
    Vector enemyList = new Vector();
    Timer tm1, tm2;
    int appearTerm = 900;

次は、敵機生成用のタイマーの生成部分を以下のように変更します。ようは900という数字の代わりに、appearTermを放り込みます。

        tm2 = new Timer();        //敵機生成用のタイマー
        tm2.setTime(appearTerm);
        tm2.setRepeat(true);
        tm2.setListener((TimerListener)this);
        tm2.start();

最後に、timerExpired( )関数の中に、タイマーの間隔を縮めていくためのコードを追加します。120行目近辺に、以下のコードを追加します。

       } else if (source == tm2) {
            //tm2からの呼び出しで、敵機を生成する
            Enemy enemy = new Enemy(g);
            enemyList.addElement(enemy);
            
            // 出現間隔をだんだん短くする
            if (appearTerm > 100) {
                appearTerm -= 5;
            }
            // 1旦タイマーを止めて、時間の再設定後再スタートさせる
            tm2.stop();
            tm2.setTime(appearTerm);
            tm2.start();
        }

1回出現するたびに、5ミリ秒ずつ出現間隔を短くしていますが、あまり間隔が短くなりすぎても困りますので、最短の時間を100ミリ秒としています。あとは、コメントの通りいったんタイマーを止めてから、appearTermで時間を設定しなおし、タイマーを再スタートさせています。

では、ここまで保存し、「ビルド」、「実行」の順に進めていきましょう。

エミュレータ画面に敵機が出現していますね。しばらく放っておいてみてください。最終的には、画面が敵機で埋まるほどになったのではないでしょうか。

画面イメージ

今さらなのですが、ここで作っているゲームの趣旨としては、敵機にぶつからないようにひたすらファイターを動かすというものです。実に単純なのですが、やってみると意外と燃えるものです。