今日のlibGDX(20150527):E. 開発記 3 シーケンス遷移

今日のlibGDX目次

http://snoopopo.hatenablog.com/entry/2015/04/27/220545

今日のテーマ:E. 開発記 3 シーケンス遷移

今回は画面遷移っていうほどじゃないけど、

タイトル→ゲーム→クリア判定、クリアした→タイトルに戻る

の流れを作ります。

もっとちょっと細かく考える

ゲーム起動
↓
タイトルの画像表示
↓
(クリックされたら)タイトル画像非表示
↓
「スタート」の文字(画像)表示
↓
(クリックされたら)「スタート」画像非表示
↓
クリア判定…すべてのTargetクラスの消滅フラグがON
↓
(判定結果:クリアだったら)「クリア」の文字(画像)表示
↓
(クリックされたら)「クリア」画像非表示
↓
タイトルの画像表示へもどる…あとループ

今いまは入力の受け取り方をクリックイベントしか知らないので、いちいちクリックでやってみる。

デモソースはどうやってるか

デモソースと言っているのは、以下の作者さんが作ったゲームのことです。

https://github.com/badlogic/theplanethatcouldntflygood

GameStateという列挙型のクラスを作ってて、

・com.badlogicgames.plane.PlaneGame.java

   static enum GameState {
        Start, Running, GameOver
    }

ゲームループの中にいるrenderメソッドから呼ばれている、 ゲームを更新しているupdateWorld()メソッド、ゲームの描画をしているdrawWorld()メソッドのなかで、

このGameStateで定義した状態を使って処理を分けているように見えます。

今回はこのつくりをパクリます。

ゲームのステータス

今回は「タイトル」「スタート」「プレイ中」「クリア」の4つの状態を定義しておきます。

「ゲームオーバー」は今のところ仕様的に考えてないので、後で追加すると思う。

javaであんまりenum使った経験がないので、これもパクってenumで定義してみた。

・MainLisner.java

   private static enum GameState {
        Title, Start, Playing, Clear
    }

ステータスの更新

ステータスを更新しないといけないパターンは、

・「タイトル」→「スタート」 クリック

・「スタート」→「プレイ中」 クリック

・「プレイ中」→「クリア」 クリア判定でクリア

・「クリア」→「タイトル」 クリック

の4種類なので、以下のように出来る。

・MainLisner.java updateGameメソッド

       //ステータス更新
        if (GameState.Title == status && isClick()) {
            //「タイトル」→「スタート」
            status = GameState.Start;
        } else if (GameState.Start == status && isClick()) {
            //「スタート」→「プレイ中」
            status = GameState.Playing;
        } else if (GameState.Playing == status) {
            // ~ボールとか的の動作とか~
            if(isClear()){
                //「プレイ中」→「クリア」
                status = GameState.Clear;
            }
        } else if (GameState.Clear == status && isClick()) {
            //「クリア」→「タイトル」
            status = GameState.Title;
        }

クリア判定

考え方はひらしょー本の荷物君と同じで、すべてのTargetクラスの消滅フラグがONの場合は、クリア。

・MainLisner.java updateGameメソッド

   private boolean isClear(){
        for (Target target : targetList) {
            if (!target.isDisappear()){
                return false;
            }
        }
        return true;
    }

20150602 add.

以下の通りにstreamAPIを使うと一発で書けました。

private boolean isClear() {
    return targetList.stream().allMatch(target -> target.isDisappear());
}

クリック判定

クリックイベントは以下でやりました。 もっといいやり方があると思うのでださいけど、まずは知っていることでやる。

http://snoopopo.hatenablog.com/entry/2015/05/13/093039

・MainLisner.java createメソッド

       Gdx.input.setInputProcessor(stage);
        ClickListener titlelistener = new ClickListener(){
            @Override
            public void clicked(InputEvent event, float x, float y){titleClick = true;}
        };
        title.addListener(titlelistener);

上記はタイトル画像がクリックされたときに、 titleClickというbooleanの変数にtrueを格納する、というものです。

titleClick…と名前わけしているので、スタート用、クリア用と分けています。

これははじめはひとつの変数でやるつもりだったし、ClickLisnerクラスも1つしかインスタンス作りたくなかったのですが、 一回クリックした瞬間に、タイトル~クリアまで遷移してしまったので、 今回はそれぞれを分けて、遷移処理の際にfalseに戻しています。

このあたりもひらしょー本でやったところをまねているけど、なんかいい方法ないかと思うので、あとでリファクタる。

ゲームの初期化

ここでいうゲーム…というのは、プレイ中の状態の初期化という意味です。

「プレイ中」→「クリア」→「タイトル」→「スタート」→「プレイ中」のとき、つまり2回目以降のプレイ中になったときに、 1回目プレイした情報は残っていたくありません。

なので、ゲームクリア後に初期化します。

・MainLisner.java

   private  void resetGame() {

        //ボールの状態を初期化
        boll = new Boll(2, 2, new Image(new Texture("img/boll.gif")));

        //的の状態を初期化
        targetList.clear();
        targetList.add(new Target(200, 400, new Image(new Texture("img/target_red.png"))));
        targetList.add(new Target(400, 400, new Image(new Texture("img/target_blue.png"))));
        targetList.add(new Target(600, 400, new Image(new Texture("img/target_green.png"))));

        //ステージに格納
        targetList.forEach(target -> stage.addActor(target.getImage()));
        stage.addActor(boll.getImage());

        //画像非表示
        boll.getImage().setScale(0);
        targetList.forEach(target -> target.getImage().setScale(0));
    }

このあと

今時点でインプットはクリックイベントを拾うことしか知らないので、 先のばしにしてましたが、 次回はプレイヤーが動かす部分を作っていきます。

このあたりの仕様は調べて出来そうなもので対応していくか.