Java
2021.12.17
Javaでのゲームの作り方!簡単ゲームのサンプルコード付き【初心者向け】
2022.06.02

プログラミングをしていると、「ゲームを作ってみたい!」と考える方も多いのではないでしょうか。


「ゲームってどうやったら作れるんだろう?」

「そもそもJavaでゲームを作れるのだろうか?」


といった疑問に対して、本記事では簡単なJavaのゲームのサンプルを交えて解説していきます。



1.そもそもJavaでゲーム開発はできるのか?

結論から述べると、Javaでゲーム開発をすることは「可能」です。


しかしながら、以下のポイントからも開発の難易度は非常に高いといえます。

①ゲームに特化した開発機能がない

Javaは、さまざまなデバイスで動作するように設計されたプログラミング言語です。しかし、基本的にはWebアプリケーションやバッチ処理、IoTデバイスの制御といった「裏側」での処理を得意としています。


Javaを用いてウィンドウアプリケーションの開発も可能ですが、ボタンやテキストボックスを用いてデータの入力を行うような業務アプリケーション開発を想定しているため、ゲームに特化していません。


そのため、Javaでゲームを作ろうと考えた場合には、フレームレートやキャラクターの描画などといったさまざま処理をイチから作り上げる必要があります。

②他のゲームエンジンの方が低い難易度でゲーム開発が可能

ゲームに特化したフレームワークであれば、C#を用いて開発する「Unity」や、C++を用いて開発する「Unreal Engine」が有名です。


ゲームのキャラクターや背景といった「アセット」も多く用意されていて、手軽に本格的な3Dゲームを開発できます。


そのため、本格的なゲーム開発をしたいのであれば、これらの学習をした方が早いでしょう。

2.Javaではどんなゲームを開発できる?


Javaを用いることで、どのようなゲームを開発できるのでしょうか。

①Javaで開発されたゲームの例

Javaで開発されたゲームとして、最も有名なのが「Minecraft」です。


現在、Nintendo SwitchやPlayStationで展開されている「統合版」はC++で開発されていますが、基となった「Minecraft Java版」は、その名の通りJavaで開発されています。


Minecraft Java版は、同じくJavaで開発した「Mod」を適用することで自由度高く遊べます。またサーバーを構築することで、複数人プレイも可能です。



3.Javaでゲーム開発する際に必要な知識とは?

ここでは、Javaでゲームをする上で必要になる知識を紹介します。

①Javaの基本文法やオブジェクト指向

Javaに限らず、プログラミング言語を用いてゲーム開発を行う場合には、利用する言語の基本構文や特性を理解する必要があります。


また、ゲームを作る上でオブジェクト指向の概念も重要です。


たとえば、シューティングゲームであれば自機や敵機、弾といった情報はすべてオブジェクトとして管理します。


ゲームを作る上では、これらの管理をするためにもオブジェクト指向の概念が非常に役に立ちますので、きちんと理解しておきましょう。

②開発環境の構築方法

ゲームを開発する場合、Webアプリケーションの開発とは違う開発環境を構築する必要があります。


Webアプリケーションの場合は、そのプログラムが動く「サーバー」を用意するのが一般的です。一方ゲーム開発の場合には、そのゲームが動作するPCやスマートフォンといったデバイスを用意する必要があります。

③ゲーム開発に役立つライブラリについての知識

ゲーム開発をする場合、多くの場合には物理計算などが必要です。


もちろん、それらの計算を楽にするためのライブラリも存在するため、「どんなライブラリが存在していて、どうやって使うのか」ということをあらかじめ知っておくことで、ゲーム開発が一段と楽になります。

4.Javaでのゲームの作り方【サンプルソースコード付き】


Javaでゲームを作るための基本的な知識を紹介したところで、実際に簡単なゲームを作ってみましょう。


今回は、Javaを使って「じゃんけん」するゲームを作っていきます。


起動した際に表示される画面

いずれかのボタンを押した際に変化する画面

① ゲームの設計図となる仕様を決める

はじめに、ゲームの流れや画面イメージといった「仕様」を考えます。ゲームを作る場合は、次の2点に着目してゲームの主軸を立てていきましょう。


・ゲームの流れ(状態遷移やゴール条件)

・画面イメージ

(1)ゲームの流れを考える

まず、大枠となるゲームの流れを考えます。


今回作るのはじゃんけんのゲームですので、次の流れでゲームを作ります。

  1. 相手の手はランダムに決定する
  2. プレイヤーは、「グー」、「チョキ」、「パー」の3つから選ぶ
  3. 相手の手と自分の選んだ手を比較して勝敗を表示し、ゲーム終了
  4. もしあいこなら「1」からやり直す

(2)画面イメージを作る

大まかな流れを考えたら、次はゲームの画面イメージを考えます。


画面上に必要なものは以下の4つですので、これらを配置した画面イメージを考えましょう。

  1. メッセージを表示するラベル
  2. グーのボタン
  3. チョキのボタン
  4. パーのボタン

大まかに、以下のように配置してみることにします。

これをベースに、画面を開発していきましょう。

② クラスの構成を決める

ゲームの流れと画面のイメージができたら、次はクラスの構成を考えます。


Javaはオブジェクト指向の言語であるため、ゲームの責務に合わせて適切にクラスを分けることを考えましょう。


例として、次のような部品を作ることにします。

  1. ジャンケンの「手」を定義するクラス
  2. 勝ち負けといったゲームの定義をするクラス
  3. メインとなる画面を制御するクラス

③ 部品となるクラスを実装する

まずは、部品となるクラスを作っていきましょう。

ジャンケンの「手」を管理するEnum

ジャンケンの「手」に関する内容を管理するクラスを作ります。ジャンケンの手は「グー」、「チョキ」、「パー」の3種類のみですので、Enumを活用してクラスを作ります。

package jp.co.trainocate.camp.samples.enums;

import java.util.Random;

/**
 * ジャンケンの手
 */
public enum Hands {
  /** グー */
  Rock("グー", 0),
  /** チョキ */
  Scissors("チョキ", 1),
  /** パー */
  Paper("パー", 2);

  /** 表示文字 */
  private final String display;
  /** 内部番号 */
  private final int number;

  /**
   * コンストラクタ
   *
   * @param display 表示名
   * @param number  番号
   */
  Hands(String display, int number) {
    this.display = display;
    this.number = number;
  }

  /**
   * ランダムな手を生成
   *
   * @return ランダムに生成した手
   */
  public static Hands getRandomHand() {
    Random rand = new Random();
    return Hands.values()[rand.nextInt(3)];
  }

  /**
   * 表示名を取得
   *
   * @return 表示名
   */
  public String getDisplay() {
    return this.display;
  }

  /**
   * 番号を取得
   *
   * @return 番号
   */
  public int getNumber() {
    return this.number;
  }
}

Enumとして表示した文字列の他に数字を設定していますが、この数字については後述します。

ゲームのプレイ状態を決めるEnum

勝敗が決まった時点でゲームを終了させるため、それ以上ボタンを押せなくする必要があります。そのため、ゲームの進行度合いを管理するためのステータスを表現するためのEnumを作成しましょう。


今回は、選択待ちか終了済みかを表現するEnumを定義します。

package jp.co.trainocate.camp.samples.enums;

/**
 * ゲームのプレイ状況
 */
public enum Status {
  /** 待ち状態 */
  Wait,
  /** 結果発表中 */
  Done
}

④ 画面に表示するクラスを実装する

次に、表示する画面の情報を管理するクラスを実装しましょう。

今回は、Javaの画面表示を行う標準機能である「Swing」を使って画面表示します。

package jp.co.trainocate.camp.samples.window;

import jp.co.trainocate.camp.samples.enums.Hands;
import jp.co.trainocate.camp.samples.enums.Status;

import javax.swing.*;

/**
 * ゲームのメイン画面
 */
public class MainWindow {

  /**
   * ゲームを表示するフレーム
   */
  private final JFrame frame;

  /**
   * メッセージを表示するラベル
   */
  private final JLabel messageLabel;

  /**
   * グー のボタン
   */
  private final JButton rockButton;

  /**
   * チョキ のボタン
   */
  private final JButton scissorsButton;

  /**
   * パー のボタン
   */
  private final JButton paperButton;

  /**
   * プレイ状況のステータス
   */
  private Status playState;

  /**
   * 相手が出した手
   */
  private Hands opponentHand;

  /**
   * コンストラクタ
   */
  public MainWindow() {
    // 画面生成
    this.frame = new JFrame("じゃんけんゲーム!");
    this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // 画面サイズを指定
    this.frame.setBounds(200, 200, 600, 400);

    var pane = this.frame.getContentPane();

    // このcanvasに対して、ボタンやラベルを配置していく
    var canvas = new JPanel();
    // 自由レイアウトに変更する
    canvas.setLayout(null);

    // ラベル
    this.messageLabel = new JLabel("じゃーんけーん・・・");
    this.messageLabel.setBounds(20, 20, 400, 30);
    canvas.add(this.messageLabel);

    // --------------
    // ボタンを作成する
    // --------------

    // グー
    this.rockButton = new JButton(Hands.Rock.getDisplay());
    this.rockButton.setBounds(100, 100, 100, 40);
    this.rockButton.addActionListener((e) -> this.selectHand(Hands.Rock));
    canvas.add(this.rockButton);

    // チョキ
    this.scissorsButton = new JButton(Hands.Scissors.getDisplay());
    scissorsButton.setBounds(250, 100, 100, 40);
    this.scissorsButton.addActionListener((e) -> this.selectHand(Hands.Scissors));
    canvas.add(scissorsButton);

    // パー
    this.paperButton = new JButton(Hands.Paper.getDisplay());
    paperButton.setBounds(400, 100, 100, 40);
    this.paperButton.addActionListener((e) -> this.selectHand(Hands.Paper));
    canvas.add(paperButton);

    // 画面にCanvasを追加
    pane.add(canvas);
  }

  /**
   * 画面表示
   */
  public void show() {
    this.init();
    this.frame.setVisible(true);
  }

  /**
   * ゲームの初期化
   */
  public void init() {
    // 相手の手をリセットし、待ち状態にする
    this.opponentHand = Hands.getRandomHand();
    this.playState = Status.Wait;
  }

  /**
   * 自分の手を選んだ時の処理
   *
   * @param selected 選択した手
   */
  public void selectHand(Hands selected) {

    // 入力待ちでなければ以降の処理はしない
    if (this.playState != Status.Wait) {
      return;
    }

    // 勝ち負けの判定
    switch ((selected.getNumber() - opponentHand.getNumber() + 3) % 3) {
      case 0:
        // 引き分けなので継続
        this.messageLabel.setText("あーいこーで・・・");
        // 手を出しなおす
        this.init();
        break;
      case 1:
        // 負け
        this.messageLabel.setText(String.format("相手が出したのは「%s」なのであなたの負けです。", this.opponentHand.getDisplay()));
        // ゲーム終了
        this.playState = Status.Done;
        break;
      case 2:
        this.messageLabel.setText(String.format("相手が出したのは「%s」なのであなたの勝ちです。", this.opponentHand.getDisplay()));
        // ゲーム終了
        this.playState = Status.Done;
        break;
    }
  }

}

コンストラクタでは、画面に表示するラベルやボタンを定義し、画面レイアウトを追加していきます。


まずは、表示する画面の大きさを600×400とし「フレーム」を作成しましょう。


次に、表示するラベルおよびボタンのオブジェクトを作成し、位置情報を指定してレイアウトに配置していきます。

じゃんけんの判定処理プログラムの解説

グー、チョキ、パーのボタンがクリックされた際にはselectHandメソッドが呼び出され、判定処理を行います。


このプログラムでは、じゃんけんの勝敗判定に次のコードを利用しています。

(selected.getNumber() - opponentHand.getNumber() + 3) % 3

これは、グーを0、チョキを1、パーを2とすることで、引き算だけで勝敗を判定できるロジックです。

例として、勝つパターンを考えてみると、以下のように計算できます。

自分相手計算値
グー(0)チョキ(1)(0 – 1 + 3) % 3 = 2
チョキ(1)パー(2)(1 – 2 + 3) % 3 = 2
パー(2)グー(0)(2 – 0 + 3) % 3 = 2


計算してみると、勝てるパターンはすべて計算結果が「2」になります。

同様に、負けるパターンも計算してみましょう。

自分相手計算値
グー(0)パー(2)(0 – 2 + 3) % 3 = 1
チョキ(1)グー(0)(1 – 0 + 3) % 3 = 1
パー(2)チョキ(1)(2 – 1 + 3) % 3 = 1


どのパターンも計算結果は「1」になります。


判定に関する処理を単純化して処理内容を減らすことで処理速度が上がるため、結果として快適なゲームを作ることにつながります。


ゲームを作る場合には、処理や計算をいかに最適化するかが重要ということを覚えておきましょう。

⑤ ゲームのメインクラスを実装する

最後に、作成したゲーム画面を起動するメインクラスを実装しましょう。

package jp.co.trainocate.camp.samples;

import jp.co.trainocate.camp.samples.window.MainWindow;

public class Main {

    public static void main(String[] args) {
        // ゲームWindowの生成と表示
        MainWindow window = new MainWindow();
        window.show();
    }
}

ここまで来たら、次のようなパッケージ構成でクラスが作成できていますので、最後に確認しましょう。

jp.co.trainocate.camp.samples
 ┣ enums
 ┃ ┣ Hands.java
 ┃ ┗ Status.java
 ┣ window         
 ┃ ┗ MainWindow.java
 ┗ Main.java   

⑥ 完成品を動かして不具合がないか確認する

ここまで完成したら、きちんとゲームとして遊べるかを確認します。


確認する場合には、以下のようなパターンを考えてテストをするようにしましょう。


・3つのボタンがきちんと反応するか
・相手の手がランダムに選出されるか
・勝敗が正常に判定されるか
・あいこの場合にゲームが続行するか


問題なく動作するようならゲームの完成です。



5.Javaでのゲーム開発を学べる本


最後に、Javaでゲームを開発する場合にオススメの書籍を紹介します。

①初心者におすすめ

Javaでゲームの作り方を学習できる初心者向けの書籍を2冊紹介します。
どちらもKindleで購入できるため、スマホやタブレットがあればすぐに読み始めることが可能です。

Javaから楽しく学ぶ!ゲームプログラミング専門学校: ゲームを作りながら学ぶJava入門

Javaを用いたゲーム開発の流れを紹介する書籍です。Javaのインストールから基本的な構文も学習でき、最終的にはパズルゲームが完成します。

Javaでゲームを作ろう1: - シューティングゲーム編 -

シューティングゲームの作り方が学べる一冊です。サンプルコードの一式がダウンロードできるため、Javaでの開発に不安がある人でもコードをみながら学習できます。

②一歩進んだ内容を学びたい人におすすめ

ゲーム開発の基本的な内容を学習したら、今度は本格的な知識を身につけましょう。
Javaに限らず、ゲーム開発全般に役に立つ内容が紹介されている書籍を3冊紹介します。

実例で学ぶゲーム開発に使える数学・物理学入門

シューティングやアクション、レースゲームといった物体が動くゲームには、ほぼ例外なく物理演算が必要です。これらの物理演算を行うための数学・物理学の基本的な知識が紹介されています。

ゲームプランナー入門 アイデア・企画書・仕様書の技術から就職まで

せっかくゲームを作るのであれば、たくさんの人に遊んでもらいたいと思うでしょう。おもしろいゲームを作るためにはゲームの企画が重要です。


ゲームプランナーはその「おもしろさ」をつかさどるポジションです。個人でゲームを作る場合であっても、ゲームプランナーとしての知識は持っておいて損はありません。

ドラゴンクエストXを支える技術ーー 大規模オンラインRPGの舞台裏

ドラゴンクエストXは、スクウェア・エニックスが展開するMMO形式のネットゲーム。さまざまなハードウェアで展開されており、ご存知の方が多いですよね。


この書籍では、その裏側を支えるサーバーの構成や運用についてのノウハウが詰まっています。いずれはネットゲームを作ってみたい、と考えるのであれば、ぜひ読んでみると良いでしょう。



6.プログラミング学習ならトレノキャンプへ


トレノキャンプでは、Javaを実践的に学ぶためのコースをオンラインで提供しています。オンデマンド配信なので、いつでも好きなときに受講が可能です。講座の詳しい内容は下記のバナーをクリックしてご覧ください。

この記事をシェア
おすすめの受講コース
  • Javaエンジニア完全パック -実務に必要なスキルを網羅-
  • はじめてのデータベース ~仕組みの理解とSQL~
  • Javaプログラミング本格入門シリーズ①~データ構造とアルゴリズム~
  • Javaで学習するユニットテスト入門 ~JUnitで理解するテスト手法~