夏にやるのかAdventCalendar第10回目です
#はじめに
今回はタイトルの通シンプルなじゃんけんゲームを作りたいと思います。
私が以前投稿させていただいた、JavaFX導入の記事の続きくらいの認識で読んでいただけると幸いです。
-はじめてのJavaFX ~簡単な導入Hello world的なGUI作成まで~
###環境
-macOS Sierra 10.12.6
-Eclipse Oxygen 4.7.3a(プラグインでe(fx)clipse導入済み)
-Scene Builder2.0
#実際の作成過程
今回は、前回の記事と違う部分として、application以外のパッケージを作る、画像を使う要素が含まれます。
###作りたいモノのイメージ
今回作成するゲームの中の流れは以下のようなものを想定しています。
- 待機画面
- ゲーム開始(「さいしょはグー、じゃんけん...」で入力待機)
- プレイヤーの入力を受けてじゃんけんのリザルト画面へ
- 1の待機画面へ
###じゃんけんで用意する画像
今回はフリーの素材サイトから拝借しました。
-じゃんけん・グーのイラスト
-じゃんけん・チョキ・ピースのイラスト
-じゃんけん・パーのイラスト
###プロジェクト内のパッケージ構成
- application: FXのGUI関係のソースがここに入る
- game: 今回のじゃんけんの処理がここに入る
- pic: じゃんけんの手の画像を入れておく。グー:Rock.png, チョキ:Scissors.png, パー:Papaer.png
###SceneBuilder内の操作
SceneBuilder内で操作をします。
前準備として, 前回と同じ手順でeclipseでJavaFXプロジェクトの作成をしてください。
プロジェクト名は「JankenFX」にします。(任意のものでも構いません)
プロジェクトが生成されたら、applicationパッケージのMain.javaを一部書き換えます。
Scene scene = new Scene(root,400,400);
となっている行を
Scene scene = new Scene(root, 500 ,400);
に書き換えます。前準備は以上です。
前準備が終わりましたら、Form.fxmlをSceneBuilderにて開いてください。
最初は中央には何もない状態ですので、画面左下のBorderPaneをクリック、画面右のLayoutでPref widthを500、Pref Heightを400に設定します。ここまでで、画面中央に白いパネルが出てくると思います。
今回のScene Builderでの作業が終わった段階の状態の画像を先に貼ります。
BorderPaneの場所ごとに行っている操作は下記の通りです
- Top
- Label: タイトルや進行状況に応じた文を表記する。fxidに"label_text"を書いています。
- Center
-HBox: HBox内に入ってるパーツは水平に等しく並べられる。propaties内のAlignmentをCENTERにしています。
HBox内
- ImageView(左): 自分のじゃんけんの手を描写します。fxidに"image_player"を書いています。
- ImageView(右): 相手のじゃんけんの手を描写します。fxidに"image_enemy"を書いています。
- Left
- Label: 自分の手だとわかるように、"あなた"と propatiesのtextに書いています。
- Right
- Label: 相手の手だとわかるように、"あいて"と propatiesのtextに書いています。
- Bottom
- HBox:説明省略
HBox内 - Button (OK): ゲーム画面を進めるためのボタンです。fxidは"button_OK"で、On Actionは"onOKClicked"を書いています。
- Button (グー): じゃんけんで自分の手を出すためのボタンです。fxidは"button_Rock"で、On Actionは"onRockClicked"を書いています。
- Button (チョキ): じゃんけんで自分の手を出すためのボタンです。fxidは"button_Scissors"で、On Actionは"onScissorsClicked"を書いています。
- Button (パー): じゃんけんで自分の手を出すためのボタンです。fxidは"button_Paper"で、On Actionは"onPaperClicked"を書いています。
ここまでの操作、記入を終えたForm.fxmlは下記のとおりです。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="500.0"
xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="application.FormController">
<bottom>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="button_OK" mnemonicParsing="false" onAction="#onOKClicked" text="OK" />
<Button fx:id="button_Rock" mnemonicParsing="false" onAction="#onRockClicked" text="グー" />
<Button fx:id="button_Scissors" mnemonicParsing="false" onAction="#onScissorsClicked" text="チョキ" />
<Button fx:id="button_Paper" mnemonicParsing="false" onAction="#onPaperClicked" text="パー" />
</children>
</HBox>
</bottom>
<top>
<Label fx:id="label_text" alignment="CENTER" prefHeight="80.0" prefWidth="400.0" text="じゃんけんゲーム" BorderPane.alignment="CENTER">
<font>
<Font size="20.0" />
</font>
</Label>
</top>
<center>
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="image_player" fitHeight="188.0" fitWidth="200.0">
<image>
<Image url="@../pic/Rock.png" />
</image>
</ImageView>
<ImageView fx:id="image_enemy" fitHeight="188.0" fitWidth="200.0">
<image>
<Image url="@../pic/Rock.png" />
</image>
</ImageView>
</children>
</HBox>
</center>
<right>
<Label text="あいて" BorderPane.alignment="CENTER">
<font>
<Font size="15.0" />
</font>
</Label>
</right>
<left>
<Label text="あなた" BorderPane.alignment="CENTER">
<font>
<Font size="15.0" />
</font>
</Label>
</left>
</BorderPane>
###Eclipseでのソース作成
作成するプログラムは、FormController.javaの追記とgameパッケージにBattle.javaを作成する2つになります。
今回作成したソースは、筆者の経験量の浅さもあり、無駄のあるソースとなっていると思います。ご了承ください。
####FormController.java
書き換えたものが下記になります。
package application;
import java.util.Random;
import game.Battle;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
public class FormController {
@FXML private Button button_OK;
@FXML private Button button_Rock;
@FXML private Button button_Scissors;
@FXML private Button button_Paper;
@FXML private Label label_text;
@FXML private ImageView image_player;
@FXML private ImageView image_enemy;
private Battle battle= new Battle();
private final Image ROCK= new Image("pic/Rock.png");
private final Image SCISSORS= new Image("pic/Scissors.png");
private final Image PAPER= new Image("pic/Paper.png");
private int hand_player;
private int hand_enemy;
private int result; //じゃんけんの結果をintで保有
private Random rand= new Random(); //相手の出す手をランダムに生成
// 進行状況1(じゃんけんの入力待機)以外のときに、進行状況を進める
@FXML
public void onOKClicked() {
if(battle.getPhase() != 1){
battle.nextPhase();
draw();
}
}
@FXML
public void onRockClicked() {
if(battle.getPhase() == 1) {
hand_player= 1;
hand_enemy= rand.nextInt(3)+ 1;
result= battle.battle(hand_player, hand_enemy, battle.getPhase());
battle.nextPhase();
draw();
}
}
@FXML
public void onScissorsClicked() {
if(battle.getPhase() == 1) {
hand_player= 2;
hand_enemy= rand.nextInt(3)+ 1;
result= battle.battle(hand_player, hand_enemy, battle.getPhase());
battle.nextPhase();
draw();
}
}
@FXML
public void onPaperClicked() {
if(battle.getPhase() == 1) {
hand_player= 3;
hand_enemy= rand.nextInt(3)+ 1;
result= battle.battle(hand_player, hand_enemy, battle.getPhase());
battle.nextPhase();
draw();
}
}
// 進行状況に応じて描画の更新をする
public void draw() {
switch (battle.getPhase()) {
case 0:
label_text.setText("じゃけんゲーム");
image_player.setImage(ROCK);
image_enemy.setImage(ROCK);
break;
case 1:
label_text.setText("さいしょはグー、じゃんけん...");
break;
case 2:
image_player.setImage(changeImage(hand_player));
image_enemy.setImage(changeImage(hand_enemy));
switch (result) {
case 1:
label_text.setText("あなたの勝ちです!!");
break;
case 2:
label_text.setText("あなたの負けです...");
break;
case 3:
label_text.setText("あいこです!");
default:
break;
}
break;
default:
break;
}
}
// じゃんけんの手の画像の更新をする
private Image changeImage(int hand) {
switch (hand) {
case 1:
return ROCK;
case 2:
return SCISSORS;
case 3:
return PAPER;
default:
return ROCK; //例外
}
}
}
続いて、じゃんけんの処理をするBattle.javaです。
package game;
// じゃんけんの処理を行うクラス
public class Battle {
private int phase; //ゲームの進行状況を保有する
// オブジェクトの生成時に進行状況0:最初の待機画面で初期化する
public Battle() {
this.phase= 0;
}
// じゃんけんの処理を行う。自分の勝ちなら1, 負けなら2, あいこなら3をかえす
public int battle(int p, int e, int phase) { //p:自分の手, e,相手の手
if(phase==1) { //進行状況1: 入力待ちのときのみ作動
// じゃんけんの手は、グー:1, チョキ:2, パー:3
if(p==1) {
if(e==1) return 3;
else if(e==2) return 1;
else if(e==3) return 2;
}
else if(p==2) {
if(e==1) return 2;
else if(e==2) return 3;
else if(e==3) return 1;
}
else if(p==3) {
if(e==1) return 1;
else if(e==2) return 2;
else if(e==3) return 3;
}
}
return -1; //例外
}
//進行状況を次の段階へ進める。phaseが3になったら、0へ更新
public void nextPhase() {
phase++;
if(phase>2)phase= 0;
}
//進行状況のゲッター
public int getPhase() {
return phase;
}
}
以上ふたつのクラスの作成と、じゃんけんの手の画像をpicパッケージにコピーアンドペーストが完了すれば、完成になります。お疲れ様です。
#実際に動かす
#おわりに
今回は、前回のハローワールドからの延長線というポジションで、別パッケージのクラスを利用したり、画像読み込みをしてじゃんけんのゲームを作成しました。
利用する画像を変えたり、SceneBuilderでレイアウトをいじったりして、練習材料にしていただけたら幸いです。
ここまで読んでいただきありがとうございました。