Java Basic GUI作成 〜コマンド画面 フォーカス移動させる修正を行う〜

イントロダクション

前回は、コマンド画面の入力チェック部分を作成しました。
今回は、入力チェックに引っかかった場合の処理を実装します。

設計

入力チェックに引っかかった場合、何も実装していないと
カーソルは移動してしまうので、それを動かないように修正します。
・入力した時点でのカーソルの位置を取得する
・入力したキーが入力禁止の場合にカーソルの位置を戻す
※上下のボタンを押下した時に移動しないようにする

実装しているコードはGitからダウンロードできます

しかし、中途半端になっているのが現状です。動きとしては下のような感じで動きます。

前回のソースコード

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;
    /** コマンドの入力開始文字 */
    private static final String CMD_START = "Cmd $ ";
    /** 改行コード */
    private static final String LINE_SEPARETOR = System.getProperty("line.separator");

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);
        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();
    }

    /**
     * TextAreaを作成して返却する
     * @return TextArea
     */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());
        // 初期表示文字を設定する
        area.setText("Hello user please input command!" + LINE_SEPARETOR + CMD_START);
        // テキストエリアの文字列数
        int textLen = area.getText().length();
        area.positionCaret(textLen);

        return area;
    }

    private EventHandler<KeyEvent> createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                // 入力を無効にする
                if (isDisabledInput(evt)) {
                    System.out.println("*** isDisable ***");

                    return;
                }
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // Enter キーを謳歌した時の処理、テキストエリアを取得する
                    TextArea src = (TextArea) evt.getSource();
                    // テキストエリア内の文字列を全て取得
                    String allText = src.getText();
                    // "Cmd $ "の文字列の位置を取得
                    int startPoint = allText.indexOf(CMD_START);

                }
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
                System.out.println("Input: " + evt.getCharacter());
            }
        };
    }

    /**
     * キーボードより入力したキーで受け付けないものを<BR/>
     * 判定する
     * @param evt
     * @return true: 受け付けない入力  /  false: 受け付ける入力
     */
    private boolean isDisabledInput(KeyEvent evt) {
        boolean isDisable = false;
        // 入力許可キーのKeyCodeリスト
        List<KeyCode> acList = createAcceptList();

        // チェック処理: 入力禁止するキーの有無をチェック
        return acList.contains(evt.getCode());
    }
    /**
     * プロパティファイル、キーを指定して対象のプロパティを<BR/>
     * 取得する
     *
     * @param propNane プロパティファイル名
     * @param key プロパティのキー
     * @return プロパティの値
     */
    @Depulicated // 使用しないメソッド
    private String getTargetProperty(String propNane, String key) {
        String propStr = null;
        return propStr;
    }

    /**
     * チェック用のリストを作成して返却します<BR/>
     * 入力禁止のKeyCodeを追加
     * @return チェック用のリスト

 続きを読む Java Basic GUI作成 〜コマンド画面 フォーカス移動させる修正を行う〜

Java Basic GUI作成 〜コマンド画面を作る〜

イントロダクション

前回は、IntelliJ IDEAの使い方を兼ねて、Javaでの画面作成を
行いました。プログラムの作成はこちらです。
今回はその続きで、コマンドを入力してその値を返却する実装をやりたいと思います。

ちなみに、画面の作成にはJava言語を使用してJavaFXというライブラリを使用します。つまり、フレームワークを使用するということですね。

JavaFXは、プログラムでHTMLのように文字列を表示するラベルや、ボタン、テキストフィールド、テキストエリア、イメージなどを表示できます。アニメーションも作成できるすぐれものです。

現状

JavaFXを使用して、テキストエリアを表示、コマンドプロンプトのように「$ Cmd」と表示するプログラムができている状態です。
今回の記事では、エンターキーを押下したときの動き(アクション)を実装しようというところです。

プログラムの内容としては、area.setOnKeyPressed(createKeyPressEvent());の部分で渡しているメソッドcreateKeyPressEvent()の処理を実装しようというところです。

処理概要

  1. メインメソッドが動きApplication#launch()が起動する。
  2. CmdViewクラスのstartメソッドが動き、画面の描画を行う。
  3. startメソッドの処理中にある「createKeyPressEvent()」で操作時の処理を実装。

ソースと動画

実装しているコードはGITにあります。

そして、実行したら最終的には、こんな感じです。この記事ではここに向けてプログラムを作っているところです。

設計〜修正する場所〜

現状は以下のようになっています。

public class CmdView extends Application {
    /** 画面の横サイズ */
    private static final int VIEW_WIDTH = 300;
    /** 画面のたてサイズ */
    private static final int VIEW_HEIGHT = 300;

    @Override
    public void start(Stage primary) {
        TextArea area = createTextArea();
        Group root = new Group();
        root.getChildren().add(area);

        Scene scene = new Scene(root, VIEW_WIDTH, VIEW_HEIGHT);
        primary.setScene(scene);
        primary.show();
    }

    /**
    * TextAreaを作成して返却する
    * @return TextArea
    */
    private TextArea createTextArea() {
        TextArea area = new TextArea();
        // 縦横の幅を設定する
        area.setPrefWidth(VIEW_WIDTH);
        area.setPrefHeight(VIEW_HEIGHT);
        area.setOnKeyPressed(createKeyPressEvent());
        return area;
    }

    private EventHandler createKeyPressEvent() {
        return new EventHandler<KeyEvent>() {
            public void handle(KeyEvent evt) {
                if (KeyCode.ENTER.equals(evt.getCode())) {
                    // Enter キーを謳歌した時の処理、テキストエリアを取得する
                    TextArea src = (TextArea) evt.getSource();
                    System.out.println("Press Enter: " + src.getText());
                }
                // チェック用のコンソール出力処理
                System.out.println("EventType: " + evt.getCode());
                System.out.println("Input: " + evt.getCharacter());
            }
        };
    }
    /** メインメソッド */
    public static void main(String[] args) {
        launch();
    }
}

現状は、画面にテキストエリアを表示しただけなので、ユーザー的には
おもしろくありません。。。

なので、「ここに入力したらなんかする」という部分を作成しようと思います。
具体的には、コマンドプロンプトのように「Cmd $ 」を表示して「入力待ちですよ」ということを示したいと思います。

実装概要

今回は、以下のような機能を作成しようと思います。

  • 文字を入力して、エンターキーを押下したときに処理を実行
  • 初期表示は「Hello user please input command!」という文字列
  • 矢印キーの上下は操作不能
  • 一番下の行には「Cmd $ 」という文字列を入れる

※$の後にスペースがあります

つまり、初期表示を行い、入力はコマンドの1行のみ。
そして、今回は赤文字のメソッドcreateKeyPressEventを追加修正します。

追加修正箇所

上記のコードに追加・修正した部分が下のコードになります。

/**
 * キーボードより入力したキーで受け付けないものを<BR/>
 * 判定する
 * @param evt
 * @return true: 受け付けない入力  /  false: 受け付ける入力
 */
private boolean isDisabledInput(KeyEvent evt) {
    boolean isDisable = false;
    // 入力許可キーのKeyCodeリスト
    List<KeyCode> acList = createAcceptList();
    // チェック処理: 入力禁止するキーの有無をチェック
    return acList.contains(evt.getCode());
}

/**
 * チェック用のリストを作成して半客します<BR/>
 * 入力禁止のKeyCodeを追加
 * @return チェック用のリスト
 */
private List<KeyCode> createAcceptList() {
    List<KeyCode> acList = new ArrayList<KeyCode>();
    acList.add(KeyCode.UP);
    acList.add(KeyCode.DOWN);
    return acList;
}

チェック用のリストを作成して、そのリストに入力したキーが
含まれる場合は、trueを返すメソッドです。(二つのメソッドを使用)
今回は、入力チェック部分を作成しました。

作成したメソッドは、下のようにイベントハンドラの部分で使用します。
言葉を変えていうならば無視したい操作と受容したい操作を判別するということです。
実装としては、以下のようになります。

無視したい処理があるとき=isDisabledInputの返り値がTRUEになります。
このメソッドでTRUEが返るときに操作を無効にします。

if (isDisabledInput(evt)) {
    System.out.println("*** isDisable ***");
    resetCursor(src);
    return;
}

まとめ

画面が表示されているだけだったところに、操作を限定するようにチェックを追加、指定の操作以外はできないようにプログラムを修正しました。

でわでわ。。。

Java Basic インターフェース・抽象クラスの作り方

イントロダクション

抽象クラスを使って見ようと思います。まずは抽象クラスってなに?と疑問に思う人もいると思うので簡単に説明しますと

抽象クラス

普通のクラスに抽象メソッドを持てるようにしたクラスです。何が違うのか?というと必ず子クラスを作る必要があり、このクラスは、newてきません。

どう使うんだ?と思う人もいるかもですが例えば、
抽象クラスのモンスタークラスを作ったとしましょう。

しかしモンスターの種類はたくさんあります。そして攻撃の方法も多岐にわたります。

こんな時「攻撃」メソッドを抽象メソッドにして子クラスのスライムクラスで、「攻撃」メソッドをオーバライドしてやればモンスターの攻撃でも、スライムの攻撃にすることができます。

下の動画は、抽象メソッドを持つインターフェイスクラスを使って、抽象メソッドのexecuteを実行するけど、処理内容が色々ある処理を実行しました。

やってみた!CommandIF(自作インターフェース)を作る

余計な音が入っています。

インターフェース・クラスの作成方法

/** インターフェースの作成 */
public interface A {
   // 抽象メソッドを定義します。
   public abstract void test01();
   // 上と同様
   public void test02();
   // 引数など書き方は普通のメソッドと一緒
   public String test03(int i);
}

抽象クラスの作成方法

/** 抽象クラスの作成 */
public abstract class A {
    // 抽象メソッドはインターフェースと同じ
    public abstract void test01();
    // 通常のメソッドの実装もOK
    public void test02() {
       System.out.println("Hello");
    }
    public A() {
       // コンストラクタ
    }
}

上の抽象クラスは、親クラスとして定義して、こクラスで似た様な処理
なんども同じ処理を呼び出したいときに使用します。

/** 子クラスサンプル */
public B extends A {
    // 親クラスの抽象メソッドをオーバーライドする必要がある
  @Override
    public void test01() {
     // 親クラスのメソッドを呼び出す
        test02();
    }
    // そのほかのメソッドなど
}

上記の様に親子関係を作成し、「A家」でtest01()の伝統を引き継いでいく・・・
みたいな感じです。
GOFのデザインパターン」などを見ると参考になると思います。

インターフェースと抽象クラスの違い

インタフェースは、実体のあるメソッドを持てない。抽象クラスは実体のあるメソッドを持てる。

/** 抽象メソッドは実体がない */
public abstract virtualMethod();

/** 実体のあるメソッド */
public void realMethod() {
    System.out.println("Real method")l;
}

ポリモーフィズム

ポリモーフィズムは、一つのメソッドでいろいろなデータ型を使えるようにするということです。
具体的には、メソッドの引数にインタフェースを宣言して作成してみましょう。

public void porimo(List<? extends Object> list) {
    /// 何かしらの処理
}

自作のCommandIF(インタフェース)を使用したポリモーフィズムの実行動画があります。

関連ページ一覧

<Java Basic>

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜「四則計算」
  3. Java Basic Level3 〜About String class〜「Stringクラス」
  4. Java Basic Level 4〜Boolean〜「TrueとFalse」
  5. Java Basic Level 5〜If Statement〜「IF文の書き方など」
  6. Java Basic Summary from Level1 to 5「Level1〜5までの複合技」
  7. Java Basic Level 6 〜Traning of If statement〜「IF文の練習」
  8. Java Basic Level8 〜How to use for statement〜「For文の使い方」
  9. Java Basic Level 8.5 〜Array〜「配列について」
  10. Java Basic Level 10 〜While statement 〜「While文について」
  11. Java Basic Swing〜オブジェクト指向〜「オブジェクト指向の考え方1」
  12. Java Basic Swing Level 2〜オブジェクト指向2〜「同じく、考え方2」

<クラスの種類>

http://zenryokuservice.com/wp/2018/05/14/java-basic-%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A8%E3%81%AF-inputsreamreader%E3%80%9Cstep2_1%E3%80%9C/

<インターフェース>

http://zenryokuservice.com/wp/2018/06/01/java-basic-%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%83%BB%E6%8A%BD%E8%B1%A1%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9/

<実装サンプル>

http://zenryokuservice.com/wp/2018/06/16/java-bassic-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91-%E3%80%9C%E3%82%B5%E3%83%B3%E3%83%97%E3%83%ABrpgmain%E3%82%AF%E3%83%A9%E3%82%B9%E3%80%9C/

http://zenryokuservice.com/wp/2018/05/20/java-basic-%E3%83%9F%E3%83%8B%E3%82%B2%E3%83%BC%E3%83%A0%E4%BD%9C%E6%88%90-%E3%80%9C%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%82%B2%E3%83%BC%E3%83%A0%E3%80%9C/

Java Basic ミニゲーム作成 〜Step3_2〜

イントロダクション

前回は、説明が不十分な感じでした。
とりあえずで"bye"と入力すると終了するコンソールアプリを作成しました。
今回は、タイトル表示までやりました。
ただし、Mainクラス単体では動きません。。。

使用するクラス

必要なクラスは以下になります。

RpgMain
ViewStatus
TitleView

RPGMainクラス

RPGMainでゲームの処理をstaticで作成しています。つまりは、メインメソッドから直接呼び出せる形で実装しています。
※RpgMain#view()メソッドは使っておりません。今後の実装を考えて作っておりますので今後修正する可能性が大きいです。
※2024/01/11現在ではXMLを読み込む形になりました

<実行動画>

/** 
 * ゲームを起動する </br>
 * 標準入力の受付、「bye」コマンドでAPを終了する</br>
 * 
 * @param args プログラム引数
 */
public static void main(String[] args) {
    // 初期化処理
    init();
    try {
        // ゲーム起動(GameLoop開始)
        gameLoop();
    } catch(IOException ie) {
        ie.printStackTrace();
        System.exit(-1);
    }
    // リソースの解放
    terminated();
}

作成したもの

処理の概要

メインメソッドでは、大まかに下のような処理をしています。

  1. 初期化処理
  2. ゲームループ
  3. 終了処理

ここのポイントは、ゲームループです。

ゲームループは、一定の処理を行い、それに対応して様々な画面への反映を行います。下のような処理を行います

  1. 入力を受ける
  2. データの更新を行う
  3. 画面の更新を行う

処理内容:メインメソッド

  1. 初期化 #init
    • RpgMainクラスを生成(new)して
    • メンバメソッドinitialize()で初期画面の標準入力を受け付ける
    • ファイルの読み込み&出力 ※ラムダ式を使用してみました
    • 初めの画面管理オブジェクト生成
/**
 * このゲームでは初期化は必ず1回なのでstaticをつける</br>
 * static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
 * ※JVM => Java Virtual Machine
 */
private static void init() {
    // mainメソッドと同様にクラスをnewする必要あり
    game = new RpgMain();
}
  1. ゲームループ #gameLoop
    • 無限ループ開始
    • コマンド実行処理(Mainクラス) ※画面管理オブジェクトのexecuteを実行
    • 更新後の画面を表示
/**
 * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
 */
private static void gameLoop() throws IOException{
    /*
     *  <ゲームループ> 
     *  1.入力
     *  2.データ更新、
     *  3.レンダリング(今回はコマンドなので文字出力)
     *  4.「bye」コマンドでゲームを終了する
     */
    while(true) {
        // 1. 入力を受け取る
        String command = game.listenInput();
        // command変数がnullになる可能性があるため定数.equals()の形にする
        if(TERMINATE_GAME.equals(command)) {
            break;
        }
        // 2-1.処理を実行する(タイトル、その他初期表示する
        status = game.execute(command);
    }
}
  1. 終了処理 #terminated
    • リソース(クラス)のメモリ解放
/**
 * ゲームのリソースを解放する
 */
public static void terminated() {
    // クラスの解放を行う
    game = null;
    System.out.println("This game terminated!, See you next time!!");
}

「static」をつけているのは、Mainメソッドから
直接呼ぶ様にしたかったからです。→メインメソッドとクラスのメンバメソッドを分けると見やすいと思ったため。

ViewStatusクラス

このクラスは、抽象クラスで、今後作成していく表示する画面を実行するためのクラスです。大まかに今回の実装のかなめになるクラスです。
ViewCommandはインターフェースですが、インナークラスとして実装しています。
※正しくは、インターフェース・クラス

このクラスの使い方としては、各画面クラス(TitleViewクラスなど)で以下のメソッドをオーバーライドしてやれば、コマンドに対応した処理を実行する
というような実装を行いました。

/** 画面の表示処理 */
public abstract void views();
/** 使用するコマンド */
public abstract Optional<Map<String, ViewCommand>> createCommands();
/** ViewStatusをセットする */
public abstract void setViewStatus(ViewStatus status);
/**
 * 画面のステータスクラスを示す。<BR>
 * コマンドの実行は内部インターフェースViewCommand<BR>
 * の実装クラスが行う<BR>
 * 【使い方】
 * 1. このクラスを継承して全ての抽象メソッドを実装します。
 * 2. コンストラクタでcreateViewStr()を呼び出して画面(文字列)を
 *    デザインしたファイルを指定してください読み込んで表示します。
 * 
 * @author takunoji
 */
public abstract class ViewStatus {
    /** 自クラスを保持する */
    protected ViewStatus status;
    /** コマンド管理 */
    protected Map<String, ViewCommand> commands;
    /** 表示する画面(文字列) */
    protected List<String> viewStrList; 

    /**
     * インナークラスのインターフェース
     * @author takunoji
     */
    public interface ViewCommand {
        /** コマンドの実行
         * Nullが返却されるときは画面の遷移なし 
         */
        public abstract ViewStatus execute();
    }

    /**
     * コンストラクタ<BR>
     * 使用するコマンドをMapに設定する
     */
    public ViewStatus() {
        Optional<Map<String, ViewCommand>> optCommands = createCommands();
        // 取得した結果がNullの場合はからのMapを返す
        commands =  optCommands.isPresent() ? optCommands.get() : new HashMap<String, ViewCommand>();
    }

    /**
     * コマンド実行処理<BR>
     * RpgMainクラスで標準入力を受けてコマンドマップに<BR>
     * 登録されているViewCommandのexecuteを実行する<BR>
     * Mapに登録されていない時は何も実行しない
     * @param input
     * @return
     */
    public ViewStatus execute(String input) {
        Optional<ViewCommand> command = Optional.ofNullable(commands.get(input));
        // commandがからの場合は何もしない
        command.ifPresent(cmd -> setViewStatus(cmd.execute()));
        return this;
    }

    /**
     * ファイルを読み込み画面を描画する(文字列)
     * @param filePath
     */
    protected void createViewStr(String filePath) {
        Path path = Paths.get(filePath);
        List<String> lines = null;
        try {
            lines = Files.readAllLines(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        lines.stream().forEach(System.out::println);
        // viewの文字列を保存します
        this.setViewStr(lines);
    }

    /** 作成、ファイルから読み込んだView文字を保存する */
    public void setViewStr(List<String> viewStrList) {
        this.viewStrList = viewStrList;
    }
    /** 作成、ファイルから読み込んだView文字を取得する */
    public List<String> getViewStr() {
        return this.viewStrList;
    }

    /** 画面の表示処理 */
    public abstract void views();
    /** 使用するコマンド */
    public abstract Optional<Map<String, ViewCommand>> createCommands();
    /** ViewStatusをセットする */
    public abstract void setViewStatus(ViewStatus status);
}

TitleViewクラスについて

そして、初めの画面管理オブジェクトのTitleViewは「ViewStatus」という抽象クラスを実装しています。
抽象クラスについてはのちに説明いたしますが、インターフェースとクラスの中間にいるクラスです。

具体的に、抽象メソッドと実装するメソッド両方を持っております。
インターフェースと違いimplemensではなく「extends」(継承)する必要があります。
さらにちょっと厄介なインナークラスにインターフェースを作成しています。

ViewStatus以外で、使用することのないインターフェースなのでそうしたのですが、普通は外部に作成します。
クラスが増えない様に、インナークラスにしたのですがやっぱり微妙でした、なんかのタイミングで修正しようと思います。

インポートするときはxxxxViewStatus.ViewCommandの様にやります。

まとめ

以下のクラスを使用しました。それぞれの役目を割り当てています。

  • RpgMain: ゲームを動かす。メインメソッドを起動するためのクラス。
  • ViewStatus: 抽象クラス、このクラスを継承したクラスはすべて、画面状態を示すクラスとして使用する。
  • TitleView: タイトルを表示するステータス(状態)を表現するクラス。

ここまでで、とりあえずは実装をどんどん拡張する準備が整った形です。
具体的には、「ViewStaus」クラスを継承して新しいクラスを作成するということです。

現状では、TitleViewクラスのみですが、これを増やしていけば一つのアプリが作れるかもしれません。

とりあえず、今回はここまでにします。でわでわ。。。

次回は、ミニゲーム作成-〜コンソールゲーム〜/

です。

関連ページ

前回

http://zenryokuservice.com/wp/2018/05/20/java-basic-ミニゲーム作成-〜コンソールゲーム〜/

インターフェースについて

http://zenryokuservice.com/wp/2018/06/01/java-basic-インターフェース・抽象クラスの作り方/

ページ一覧

http://zenryokuservice.com/wp/2018/09/29/mapping-of-java-bassic~java-basicの記事一覧~/

Java Basic ミニゲーム作成 〜Step3_1〜

イントロダクション

はじめにコンソール画面を使用してミニゲームを作成しようと思っています。
標準入力(コンソール画面に入力する)を使用して行いますので、参考までに標準入力のサンプルを載せておきます。

標準入力の動き

最終的に作成したもの

ミニゲームを作る

  • ミニゲームの作成を行います。
    処理の概要としては、以下の通りです。( version0.1)
=====補足==========
<基本設計レベル>
[詳細設計レベル]
==================

<初期処理>
画面状態管理Obj
リソースの読み込み
[テキストで表示する絵を読み込み変数に保存]→テキストファイル

[新規で追加するファイルも読み込める様に工夫する]

<選択→決定処理>
ゲームタイトル画面の「スタート」「コンテニュー」の選択をする

以下の様に表示する

START:S
CONTINUE: C
<イントロダクションの表示処理> イントロダクションのテキストファイルを読み込み ストーリーの序章を表示して、ゲームを開始できる様な文章を表示する

この仕様で実装します。

  1. 画面状態管理クラスの作成

    • シンプルにMap型のフィールド変数を作成します。
  2. リソースの読み込み、単純にテキストファイルの読み込みです。

※今後はプロパティファイルなど読み込む予定です。(XMLもやるかも?)リメイクの方(Github)で使用しています。

※未実装です

  1. これもテキストファイルを読み込みゲームの序章を表示します。

今回は、ここまでを実装します。

土台にするのは以前の実装です。
クラス名はブログの都合上変えてあります。
そして「画面状態」は今回初登場の「Map」インターフェースを使用して管理します。

<<元にするソースについて>>

ゲームの基本的な処理フロー

初期化→ゲームループ→終了

上記のメソッドを実装してあります。

まとめると

  1. ゲームの起動準備「init();」
  2. 入力→画面の更新をループする「gameLoop()」
  3. ゲームの終了「terminated()」

上記の3つの処理の中で、ゲームを進行させていくと言うことです。が実装してみないとイメージがわかないと思います。※イメージが湧く人は頭のいい人です。筆者は試行錯誤済みです。

そして、「3つの処理」というのは「」の中に書いてある各メソッドのことを指します。

  • init()
  • gameLoop()
  • terminated()

それぞれの処理は以下のようになります。
<init: 初期処理>

/**
* このゲームでは初期化は必ず1回なのでstaticをつける</br>
* static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
* ※JVM => Java Virtual Machine
*/
private static void init() {
    // mainメソッドと同様にクラスをnewする必要あり
    game = new RpgMain();
}

ここで実行しているのはコンストラクタになります。

/**
* ぶっちゃけてここで初期化(init)処理をやっても良い</br>
* 最終的にプログラムの設計者の判断に委ねられる</br>
*/
public RpgMain() {
    // メンバメソッドなのでコンストラクタで呼び出す
    initialize();
}

そして、inittialize()メソッドを実行しています。フィールド変数にTitleViewクラスを代入(セット)しています、

/**
* 入力、出力のためのオブジェクトを生成</br>
* RpgMainクラスが存在しないならば使用できない様にするので</br>
* このメソッドはメンバメソッドにしてある</br>
*/
public void initialize() {
    // 入力受付クラス
    read = new BufferedReader(new InputStreamReader(System.in));
    // *** titleの表示 *** //
    // ViewStats生成
    status = new TitleView();
}

<gameLoop: 初期処理>

/**
 * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
 */
private static void gameLoop() throws IOException{

    /*
    *  <ゲームループ> 
    *  1.入力
    *  2.データ更新、
    *  3.レンダリング(今回はコマンドなので文字出力)
    *  4.「bye」コマンドでゲームを終了する
    */
    while(true) {
    // 1. 入力を受け取る
    String command = game.listenInput();
    // command変数がnullになる可能性があるため定数.equals()の形にする
        if(TERMINATE_GAME.equals(command)) {
            break;
        }
        // 2-1.処理を実行する(タイトル、その他初期表示する
        status = game.execute(command);
    }
}

ここでは、「String command = game.listenInput();」で標準入力を受け取っています。
そして受けた文字列から実行するコマンドを実行して処理後にTitleViewクラスを受け取っています。

<terminated: 終了処理>

/**
* ゲームのリソースを解放する
*/
public static void terminated() {
    // クラスの解放を行う
    game = null;
    System.out.println("This game terminated!, See you next time!!");
}

サンプルコードは一番上の「ミニゲーム」の部分にリンクしています。

コンソールゲームで初めのタイトルが表示される様なものです。初めはこれからストーリーをつけて。。。と考えていたのですが、ストーリーができず。。。保留状態です。。。※作成しました。作成したものは上部にYOutube動画があります。

実装したコード

この記事の上部にあるリンク先にはGithubで見ることができます。関連クラスも同様にアップロードしてあります。

/**
 * コマンドラインRPGのメインクラス</br>
 * <ul>
 * 機能リスト
 * <li>1.必要なリソースを読み込む #init</li>
 * <li>2.ゲーム起動(コマンド入力) #gameLoop</li>
 * <li>3.リソースの解放</li>
 * <li>ゲーム終了(このメインメソッドの終了)</li>
 * </ul>
 * @author takunoji
 */
public class RpgMain {
    /** フィールド変数で自信を管理 */
    private static RpgMain game;
    /** 定数: AP終了コマンド */
    public static final String TERMINATE_GAME = "bye";
    /** 入力を受付るオブジェクト */
    private BufferedReader read;
    /** 画面状態管理オブジェクト */
    private static ViewStatus status;

    //////////////////////////////////////
    // staticメソッドの定義
    //////////////////////////////////////
    /** 
     * ゲームを起動する </br>
     * 標準入力の受付、「bye」コマンドでAPを終了する</br>
     * 
     * @param args プログラム引数
     */
    public static void main(String[] args) {
        // 初期化処理
        init();
        try {
            // ゲーム起動(GameLoop開始)
            gameLoop();
        } catch(IOException ie) {
            ie.printStackTrace();
            System.exit(-1);
        }
        // リソースの解放
        terminated();
    }

    /**
     * このゲームでは初期化は必ず1回なのでstaticをつける</br>
     * static -> 静的メソッド=> クラス内にあるがJVMから直で参照される
     * ※JVM => Java Virtual Machine
     */
    private static void init() {
        // mainメソッドと同様にクラスをnewする必要あり
        game = new RpgMain();
    }

    /**
     * この処理もinit()と同様に必ず1回なのでstaticをつける</br>
     */
    private static void gameLoop() throws IOException{

        /*
         *  <ゲームループ> 
         *  1.入力
         *  2.データ更新、
         *  3.レンダリング(今回はコマンドなので文字出力)
         *  4.「bye」コマンドでゲームを終了する
         */
        while(true) {
            // 1. 入力を受け取る
            String command = game.listenInput();
            // command変数がnullになる可能性があるため定数.equals()の形にする
            if(TERMINATE_GAME.equals(command)) {
                break;
            }
            // 2-1.処理を実行する(タイトル、その他初期表示する
            status = game.execute(command);
        }
    }

    /**
     * ゲームのリソースを解放する
     */
    public static void terminated() {
        // クラスの解放を行う
        game = null;
        System.out.println("This game terminated!, See you next time!!");
    }

    //////////////////////////////////////
    // コンストラクタ、メンバメソッドの定義
    //////////////////////////////////////
    /**
     * ぶっちゃけてここで初期化(init)処理をやっても良い</br>
     * 最終的にプログラムの設計者の判断に委ねられる</br>
     */
    public RpgMain() {
        // メンバメソッドなのでコンストラクタで呼び出す
        initialize();
    }

    /**
     * 入力、出力のためのオブジェクトを生成</br>
     * RpgMainクラスが存在しないならば使用できない様にするので</br>
     * このメソッドはメンバメソッドにしてある</br>
     */
    public void initialize() {
        // 入力受付クラス
        read = new BufferedReader(new InputStreamReader(System.in));
        // *** titleの表示 *** //
        // ViewStats生成
        status = new TitleView();
    }

    /**
     * 入力受付を開始、入力結果を取得する</br>
     * @return 入力文字列(コマンド)
     * @throws IOException
     */
    private String listenInput() throws IOException {
        return read.readLine();
    }

    /**
     * コマンドの実行を行う<BR>
     * 1.
     * @param input
     * @return
     */
    private ViewStatus execute(String input) {
        status = status.execute(input);
        return status;
    }

    private void view() {
        if(status != null) {
            status.views();
        }
    }
}

[rakuten ids="book:19065927"]

関連ページ一覧

Java Basic

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement 
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜