シューティングゲーム


  1. 原版

    原版はインターネットから取得したのですが、そのサイト名が定かでありません(ごめんなさい)。制御手法はほぼそのまま借用し、グラフィックや音響効果を付加しました。

  2. 操作法

    Sキーで開始します
    スペースキーでレーザービームで攻撃します
    矢印キーで前後・左右に移動します

    攻撃機の体当たりを避けてください 。
    爆撃機は狙いを定めた爆弾を投下します 。
    (近距離ではかなりランダムです)早めに打ち落としましょう



  3. 手法

    1. スレッド起動まで

      init()はアプレット起動時に実行される関数で、得点を表示する「ラベル」を作成します。続けて、start() で描画用画面Canvasを作成します。createImage(Width,Height);  を行い表示画面とは別に画面を生成する imgGra を生成します。ここに描画することで、ちらつきのないグラフィックスを実現しています。
      最後にスレッドを起動します。 (aThread = new Thread(this)).start();

    2. スレッド

      スレッドを起動すると、run() の処理が始まります。まず、ゲーム全体を統括するFieldAdminクラスを生成します。
       admin = new FieldAdmin(Width,Height);
      次に、adminにimageとsoundフォルダにある映像と音声を取り込み、設定をします。
       admin.aucBeam = getAudioClip( getDocumentBase(), "sound/beam.au" );
       admin.imgJiki = getImage( getDocumentBase(), "image/im1.gif" );
      繰り返しの中で、移動処理(move)、描画処理、状態表示(時間、得点)を行います。
          while(true) {
            admin.move();//敵の生成や移動
            imgGra.setColor(Color.black);
            imgGra.fillRect(0,0,Width,Height);
            admin.draw(imgGra);//描画
            gra.drawImage(img,0,0,null);
            scLabel.setText("Time: "+admin.timer+" , Score: "+admin.score);
      
            try {
              Thread.currentThread().sleep(55);
              } catch(InterruptedException exception) {}
          }

    3. クラス構成

       FileldAdminクラスが全体を統括します。生成されるすべての「もの」は、種類毎にリストに結合します。
        // 自機が発射するミサイルを管理するリスト
        ListAdmin missileList;
        // 敵を管理するリスト
        ListAdmin enemyList;
        // 敵弾を管理するリスト
        ListAdmin enemy2List;
        // 爆発している敵を管理するリスト
        ListAdmin bombList;
        // 画面上を動くオブジェクトすべてを管理するリスト
        ListAdmin allObject;
       Fieldadminのコンストラクタで、各リストを、allObjectリストに結合しています。これで、allObjectに対して、move などのコマンドを出すと、リストに結合されたすべてが 「移動」処理を行います。このリスト処理を行うため、ListElementクラスが用意されています。「もの」の移動を処理する基本クラスとして、MoveObjectクラスが定義され、これはListElementクラスを継承しています。
       自機や敵を総括するEnemyクラスは、このMoveObjectクラスを継承します。敵のEnemy1、Enemy2、Tama、等のクラスは、Enemyクラスを継承しています。したがって、Enemy1クラスは
       ListElement>MoveObject>Enemy>Enemy1
      のように、多段のクラスを継承しています。

  4. 各クラスの構成

    1. Applet1クラス

      1. コンポーネント
        上部に時刻と得点表示用のラベルを作成します。キー操作を利用するため、キー入力を必要とするGUI(textFieldなど)は利用できません。
      2. 主要変数
        Graphics gra,imgGra; //オフスクリーングラフィックスです
        FieldAdmin admin; //ゲーム進行をするクラスです

      3. start()
        画像と音声ファイルを読み込みます。
        オフスクリーングラフィックス:imgGra とスレッドを作成します。

      4. run()
        ウィンドウの幅、高さ、音声、画像ファイルを読み込み引き渡します。画像はimageフォルダ、音声はsoundフォルダに保存しておきます。
         admin(FieldAdminクラス)に対し、移動と表示処理を行います。
         55m秒単位で再描画をします。
         時刻とスコアの表示をします。

      5. keyDown,keuUp()
        キーを押したときに実行される関数で、押されたキーの情報を admin に引き渡します。

      6. main()
         アプレットとして実行するときは不要です。

    2. FieldAdminクラス

      1. 目的
        ゲームの進行をします。敵機の生成/消滅、モノの移動や描画、キー入力の受付などを行います。

      2. 主要変数
        int width,height;//画面のサイズ
        int counter=0;// Game開始してからのカウンタ
        boolean upKey,downKey,leftKey,rightKey;// 方向Keyの状態
        int shotKeyState = 0; // Shot keyの状態
        Jiki jiki;// 自機のオブジェクト
        int timer;// 敵が出現する間隔を制御するカウンター

        ListAdmin allObject;// 画面上を動くオブジェクトすべてを管理するリスト
        ListAdmin missileList;// 自機が発射するミサイルを管理するリスト
        ListAdmin enemyList;// 敵を管理するリスト
        ListAdmin enemy2List;// 敵弾を管理するリスト
        ListAdmin bombList;// 爆発している敵を管理するリスト
        int score = 0;
        AudioClip aucBomb, aucBeam; // 効果音
        Image imgJiki, imgEnemy1, imgEnemy2; // 機体の画像

      3. init()
        ミサイル:missikeList、敵機:enemyList,enemy2List、爆弾bombList、のリストを作成します。
        jiki(自機)のインスタンスを作成し配置をします。
        すべてのリストを結合するallObjectオブジェクトを作成します。

      4. move()
        timerとカウンターの値で、敵機を生成し、enemyListに加えます。
        敵機や爆弾の移動を行います。
        allObject.move() で各リストのオブジェクトを移動します。。
        自機の移動は jik.mov が担当します。

      5. draw()
        allObject.draw(g); で各リストのオブジェクトを表示します。
        ゲームを開始していない場合、"Push [S] key!!"を表示します。

      6. key(int code,boolean flag)
        キー情報を受け取り、フラグをセット/クリアします。

    3. ListElement

       データの管理を行う ListAdminクラスや 移動を行う MoveObject クラスの親クラスとなります。すべてのモノはListElement の子供の(派生)クラスになります。ListAdminの関数で、リストのすべての要素の描画を次のように行います。リストの要素( head.next)には、BombやEnemy1などのインスタンスが接続されますが、共通の親(obj)に代入が可能です。obj.draw() は実際に代入されたクラスのdraw()関数が実行されます。たとえば、obj が Bomb クラスならBonbクラスの draw() が実行されます。
        // リスト内の要素すべての描画をおこなう。
        void draw(Graphics g) {
          ListElement obj;
          obj = head.next;
          while( obj != tail ) {
            obj.draw(g);
            obj = obj.next;
          }
        }
       共通の処理は親クラスで処理し、非共通の処理は子供のクラスで再定義します。

    4. ListAdmin:ListElement

      1. 目的
         複数現れる敵機や爆弾をリストで結合し管理します。

      2. add()
        リストの最後に追加します。

      3. draw()
        リストを辿りながら、オブジェクトを表示する。

      4. mov()
        draw()
        リストを辿りながら、すべてのオブジェクトを移動します。

      5. hitTest()
        衝突する最初のオブジェクトを返します。なければnullを返します。

    5. MoveObjectクラス:ListElement

      1. 目的
        移動する各オブジェクトの親クラスとなります。

      2. データ
         ものの位置(x,y)と幅・高さ(width,height)の情報を持ちます。

      3. hitTest()
        領域が重なって衝突(弾が当たる)したかを判断します。

    6. Jiki:MoveObject

      1. 目的
         MobObjectクラスを継承し、自機を管理します。

      2. move()
        キーのフラグに従い、speed(8)だけ移動します。
        スペースキーなら、攻撃用ミサイルを misileListに追加します。

      3. addDamage
        isAliveをfalseにし、bombListに加える。ゲーム終了です。

      4. draw()
        isAliveなら、imgJiki画像を表示、
        そうでないとき、counterを増し16以上でkill()する(自機の爆発を表示)。

    7. enemy:MoveObject

      1. 目的
        敵クラスを代表します。

      2. setPosition
        位置を設定します。

    8. Tama:enemy

      1. 目的
        爆撃機の落とす爆弾の制御をする。

      2. setDirection()
        自機との距離が遠い場合、自機の方向に向ける。そうでないとき、乱数でランダムな方向に設定する。

      3. move()
        設定された方向に移動する。
        hitTestを行い、あれば、addDamege()を実行する。

      4. draw(Graphics g)
        白の楕円で表示する

    9. Enemy2:enemy

      1. 目的
        爆撃機の制御をする

      2. move()
        y+方向に移動する。速度4
        hitTestを行い、あれば、addDamege()を実行する。
        counterの値が0になったら、爆弾を生成する。
         方向を定め、速度8,ランダム制御をする
        counterの値は、乱数でセットする。現在 Math.random()*100+8

      3. draw(Graphics g)
        爆撃機の画像を表示する

    10. Enemy1:enemy

      1. 目的
        攻撃機の制御をする

      2. コンストラクタ
        x方向の移動量を乱数で定める

      3. move()
        x,y方向に移動する。y方向速度12
        hitTestを行い、あれば、addDamege()を実行する。

      4. draw(Graphics g)
        攻撃機の画像を表示する

      5. addDamage
        削除し、爆発リストに加える

  5. 実行

    1. 操作

      Sキーで開始します。スペースキーでレーザービームで攻撃します
      矢印キーで前後・左右に移動します




  6. ダウンロード

    このプロジェクトをダウンロードできます。次の行をクリックして、shooting.exeファイルを適当なフォルダに保存します。
    ダウンロード開始
    このファイルは自己解凍型の圧縮ファイルです。このファイルを実行すると指定したフォルダに必要なファイルが生成されます。ソースはここにあります。二つのソースファイルを結合しています。実行するには、二つのソースに分割する必要があります。(上のダウンロードが便利です)

  7. 機能追加

    1. スクリプト
      主要キャラクタはスクリプト駆動とし、ステージにより定型パターンを持たせる。

    2. ボスキャラ
      特徴をもったボスキャラを登場させる。ボスは多くのダメジを与えないと破壊できない。避けることもできない。

    3. シールド
      一定以上の得点でシールドを装備する。シールドがある場合、攻撃はシールドに損害を与える。

    4. イベント機能
       各種のイベントを仕掛ける。特定のイベントを実行しないとステージが進まない。

  8. 追加・補足


    1. メモ用紙

       ピンク色のメモ用紙を渡しています。このメモ用紙(1枚)は試験中に参照可能です。ただし、自筆に限り、コピーした用紙は利用できません。

    2. プログラムレポート

       講義内容にそった自由課題のプログラムを試験前に課題提出フォルダに提出してください。

    3. 筆記試験

       講義で説明/実習した java および メディア処理 の考え方や手法の説明をしてください。


       仮想マシン、クラスの継承、スレッド、ダブルバッファ、GUI、イベント処理、
       画素単位の処理、メディアトラッカ、など

    4. プログラムの流れ

      ゲームの流れは、Applet1::run():スレッド から開始されます。ここで、admin.move():移動およびそれに伴う処理 と admin.draw():描画 を行います。
       admin.move では allobject.move() を行いすべての要素に 「自分流」のmove() の実行を要求します。Tama のリストの場合、dx,dy 移動後、hitTest(admin.jiki) で 自機 との衝突判定をし、衝突の場合攻撃をします。また、位置が枠外になったら、消滅(kill)を行います。クラスの継承と多態性を利用しています。
       
    5. アンケート

      この種のゲームは得意(好き)ですか?  1:はい 2:少し 3:ぜんぜん
      プログラムは理解できましたか?  1:はい 2:少し 3:ぜんぜん
      プログラムは参考になりましたか?  1:はい 2:少し 3:ぜんぜん
      話は良くきいておましたか? 1:はい 2:少し 3:ぜんぜん