人工知能に関する断創録

このブログでは人工知能のさまざまな分野について調査したことをまとめています(更新停止: 2019年12月31日)

連続発射

連続で弾を発射できるようにします。

invader03.jar

Shotを下のように配列で管理すれば複数の弾を作れます。今回は5発の弾を連続で撃てるようにするので弾の数(NUM_SHOT)を5としました。コンストラクタでは5発の弾を作り、配列に入れています。

    // 連続発射できる弾の数
    private static final int NUM_SHOT = 5;
    // 弾
    private Shot[] shots;
    
    public MainPanel() {
        ・・・
        
        // 弾を作成
        shots = new Shot[NUM_SHOT];
        for (int i = 0; i < NUM_SHOT; i++) {
            shots[i] = new Shot(this);
        }
        
        ・・・
    }

弾を複数用意したので移動や描画の処理を書き換える必要があります。

    // 弾を移動する
    for (int i = 0; i < NUM_SHOT; i++) {
        shots[i].move();
    }
    
    // 弾を描画
    for (int i = 0; i < NUM_SHOT; i++) {
        shots[i].draw(g);
    }

forループで配列をまわしてすべての弾を移動したり、描画しています。

最後に弾を連発する処理です。少し長かったのでtryToFire()というメソッドにまとめてみました。tryとついているのは撃てない場合もあるからです。撃てない場合は、

  • 5発全部撃っているとき
  • 前の弾を撃ってからFIRE_INTERVALしか経っていないとき

です。1つめの条件は当然必要です。5発しか弾を用意していないので5発以上は同時に撃てません。2つめの条件は発射に充填時間が必要だと考えてください。今回実装するのは連発であって全弾発射ではないので弾を撃てる間隔を入れます。つまり、1発撃ったらしばらく撃てないようにします(といっても充填時間は300ミリ秒なので短いですが・・・)。充填時間は、

    // 発射できる間隔(弾の充填時間)
    private static final int FIRE_INTERVAL = 300;

のように定義しています。tryToFire()が発射処理です。

    /**
     * 弾を発射する
     */
    private void tryToFire() {
        // 前との発射間隔がFIRE_INTERVAL以下だったら発射できない
        if (System.currentTimeMillis() - lastFire < FIRE_INTERVAL) {
            return;
        }

        lastFire = System.currentTimeMillis();
        // 発射されていない弾を見つける
        for (int i = 0; i < NUM_SHOT; i++) {
            if (shots[i].isInStorage()) {
                // 弾が保管庫にあれば発射できる
                // 弾の座標をプレイヤーの座標にすれば発射される
                Point pos = player.getPos();
                shots[i].setPos(pos.x + player.getWidth() / 2, pos.y);
                // 1つ見つけたら発射してbreakでループをぬける
                break;
            }
        }
    }

1回前に発射した時間はlastFireに保存しておきます。そして、currentTimeMillis()で取得した現在時間と1つ前に発射したlastFireの差がFIRE_INTERVALより小さい場合は未充填で発射できないようにしました。

充填が終わっている場合は、発射されていない(保管庫に入っている)弾を探して発射します。tryToFire()1回の呼び出しで1発だけ発射されればいいので、撃っていない弾を1発見つけて発射した場合はbreakでぬけています。スペースキーを5回連続で押せば、tryToFire()が5回呼ばれて5発連続発射されます。

これで終わりですが、ためしにFIRE_INTERVALを0にして実行してみてください。充填時間をなしにすると1回スペースを押しただけで5発全部発射されてしまいます。これはゲームループであるrun()が高速で回るため1回スペースを押している間にループが何回も回り、tryToFire ()が5回以上呼び出されてしまうためです。

次はエイリアンを実装する予定です。