• 2002/05/13 [Java]Javaでシューティングゲーム☆彡
    Javaでシューティングゲームを作りました。
    以前にDirectXで作ったやつの移植なのでゲーム自体は新鮮味はないのですが、 「遅い」といわれるJavaとは思えないほど問題なく動きます。
    ダウンロード:Sylbis.jar(195,168バイト)
    動作環境
  • JDK1.4以上
  • Celeron500MHz以上
    OSはWindows2000で動作確認しています。


    JDK1.4からVolatileImageが追加されました。
    コイツを使えば、ビデオカードの機能を使って高速に描画できます。 このVolatileImageを直接使ってもいいんですが、その代わりにBufferStrategyというクラスを使えば、 もっと簡単に扱うことができます。 パッケージは、java.awt.imageです。 Webでいいサンプルが見つかったので、これを参考にさせてもらいました。
    Java in the Box BufferStrategyTest2.java です。
    ココは、JDK1.4で追加された機能の解説がしてあってとてもイイですね!


    サウンドは、大昔はApplet.getAudioClip()しかなかったのですが、JDK1.3から 強力になっています。 (うーん、サウンド関係は苦手なんだよな〜。) まず、MIDI形式とオーディオ形式で扱い方が異なります。 MIDI形式は、*.midや*.rmfがあります。オーディオ形式は*.wav, *.au, *.aiff があります。 MIDI形式を扱うときには、javax.sound.midiパッケージのクラスを使います。 大雑把に言えば、MidiManagerクラスを中心に、Sequencerを使って演奏します。 オーディオ形式の場合は、javax.sound.sampledパッケージのクラスを使います。 AudioSystemクラスを中心に、ファイルをAudioInputStreamにし、Clipを使って演奏します。 でも、ラインとか、ミキサーとか、ポートとか、チャンネルとか・・・ ここら辺の専門用語がよくわかんないです。
    JBuilderに含まれるJDKにサウンドのデモがあるのですが、これがスグレモノです。 メチャクチャいいです。 なぜかJDK1.4のデモにはありません。
    ゲーム内ではWAVのみを使っています。 試行錯誤しながら作ったので、まだまだ改良の余地があります。


    あとゲームで必要なのは入力デバイスなのですが、ゲームパッド/ジョイスティック関係はないです。(よね?) キーボードで扱うにしても、通常のアプリケーションとは違い、押されているかどうかの 状態が取得できなければなりません。 でも、これもないです。 しかし、KeyEventを使えばできなくもないです。
        boolean[] keystat = new boolean[256]; //256で足りるかな?
        public void keyPressed(KeyEvent e) {
            if(e.getKeyCode()<256) {
                keystat[e.getKeyCode()] = true;
            }
        }
        public void keyReleased(KeyEvent e) {
            if(e.getKeyCode()<256) {
                keystat[e.getKeyCode()] = false;
            }
        }
    使うときは、以下の感じで。
        if(keystat[KeyEvent.VK_LEFT]) fighter.x -= 10;
    これでキー状態の取得はできるのですが、複数のキーを同時に押すと、押すキーの種類によって うまく取れない場合があります。 しかし、これはJavaの原因によるものではなく、キーボードのハードウェア上の問題だそうです。 同じことがDirectXでも起きます。(少なくとも106キーボードでは)
    余談ですが、CapsLock, NumLock, ScrollLock, KanaLock などのロックするタイプのキーなら java.awt.ToolkitgetLockingKeyState(int keyCode);で取得できます。


    あと移植ですが、1997年当時のDirectX版のソースは今見直してみるとあまり美しくないです。 Javaもデザインパターンも知らなかったし、それにオブジェクト指向でカプセル化をすると、 ゲームの自由な演出をするのに障害になるのではないかと思い、意識的にオブジェクト指向以前の 作りにしてました。
    でも今回はだいぶオブジェクト指向してイジってます。 1つ紹介するとすれば、デザインパターンのStateパターンを使ってます。 このゲームにはオープニング状態とプレイ状態の2つがありますが、 どちらも、初期化、移動&描画のメソッドを持っています。 それをStateパターンに当てはめて、状態クラスを切り換えて使うようにしています。 でも、洗練度としてはまだまだです。 階層的な状態には使えないので、もっとソースを磨く必要があるでしょう。


    最後にスピードですが、私の家のマシンはCeleron500MHzと、やや型落ち気味です。 単純に移植しただけでは少し遅かったので、簡単なチューニングをしました。 目標は20FPS(つまり毎秒20コマ)なのですが、最初はそこまで出なかったのです。 いろいろ試してみたところ、イメージの数が大きく影響してました。 イメージが20ぐらいなら大丈夫なのですが、50になるとギリギリ、100になると 遅くてほとんど使えません。 そこで、以下のような変更を行いました。
  • 背景の星をイメージからRectangle()の描画に変えた。
  • 垂直レーザーは短い画像をつなげて描画しているが、それを縦長にし、 イメージの描画回数を減らした。
  • 垂直レーザーの残像を5本から3本に減らした。
    簡単なチューニングですが、結構効果がありました。 でも、Celeron800MHzならチューニング以前で全然平気に動いていたので、 対象機種をもう少し上に設定すれば問題ないでしょう。 もちろん、ビデオカードとか色んな要因があるでしょうが。


    ソースはjarファイルの中に入ってます。GPLです。 それと、起動時に-DEBUGを指定するとデバッグモードで起動します。
     >java -jar Sylbis.jar -DEBUG

    2002/05/25 追記
    Java in the Boxの櫻庭さんからメールを頂きました。 (StrategyBufferを参考にさせていただいた方です)
    ゲームを終了し、フルスクリーンから通常の画面に戻ったとき、 他のウィンドウのサイズが小さくなる場合があります。 ゲームは640x480に切り換えているのですが、それ以上のウィンドウがあると、 すべてそのサイズになり、画面左上に寄ってしまうのです。 ただ、これが毎回起こるのではなく、稀にしか起こりません。 原因はわかっていませんし、再現性もつかめていません。 Java Developer Connection のBug Paradeでもまだ話題に上がっていないそうです。 (まだ認知されていないバグでしょうか?)
    戻る