この記事では、Javaを使用してテキストベースのRPGゲームを構築する過程を通じて、オブジェクト指向プログラミングの基本概念を学ぶことができます。テキスト装飾、ゲームエンジンの設計、コマンド処理、プレイヤーの管理など、RPGゲーム開発の主要コンポーネントを段階的に解説しています。
はじめに
この記事のコードをコピペしてEclipseで出力結果を確認してみよう!
※ゲームの開発過程はクリックすると表示されます。
キャラクター作成
以下の機能を実装していきます。
- プレイヤーキャラクターのクラス設計
- 基本ステータス(HP、MP、攻撃力など)の実装
- レベルアップシステムの導入
- その他の実装
- テキストの色設定
- 複数クラスに分割
※クリックするとコードが表示されます。
ANSIColors.java:テキストの色を定義するクラス
/**
* ANSIカラーコードを定義するクラス
* このクラスは、コンソール出力時に使用できる ANSI エスケープコードを定数として提供します。
*/
public class ANSIColors {
public static final String RESET = "\u001B[0m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String YELLOW = "\u001B[33m";
public static final String CYAN = "\u001B[36m";
public static final String BRIGHT_PINK = "\u001B[95m";
}
RPGGame.java:テキストベースRPGゲームの開始点
/**
* テキストベースRPGゲームのメインクラス
* このクラスはゲームの開始点となり、ゲームエンジンを初期化して起動します。
*/
public class RPGGame {
public static void main(String[] args) {
// ゲーム開始メッセージをシアン色で表示
System.out.println(ANSIColors.CYAN + "テキストベースRPGを開始します..." + ANSIColors.RESET);
// ゲームエンジンのインスタンス作成と起動
GameEngine gameEngine = new GameEngine();
gameEngine.start();
}
}
GameEngine.java:ゲームのメイン処理を管理するクラス
import java.util.Scanner;
/**
* ゲームの中核となるエンジンクラス
* ゲームのメインループ、入力処理、初期化、終了処理を管理します。
*/
public class GameEngine {
private static final String EXIT_COMMAND = "exit";
private final Scanner scanner;
private final CommandProcessor commandProcessor;
private final Player player;
private boolean isRunning;
/**
* GameEngineのコンストラクタ
* 必要なオブジェクトの初期化を行います。
*/
public GameEngine() {
this.scanner = new Scanner(System.in);
this.player = new Player("勇者");
this.commandProcessor = new CommandProcessor(player);
this.isRunning = true;
}
/**
* ゲームを開始するメソッド
* 初期化、メインループ、終了処理の順に実行します。
*/
public void start() {
init();
gameLoop();
cleanup();
}
/**
* ゲームの初期化を行うメソッド
* ウェルカムメッセージと操作方法を表示します。
*/
private void init() {
System.out.println(ANSIColors.GREEN + "テキストベースRPGへようこそ!" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "ゲームの操作方法:'help' と入力してください。" + ANSIColors.RESET);
}
/**
* ゲームのメインループ
* ユーザーからの入力を受け付け、処理を行います。
*/
private void gameLoop() {
while (isRunning) {
System.out.print("> ");
String input = scanner.nextLine().trim().toLowerCase();
processInput(input);
}
}
/**
* ユーザー入力を処理するメソッド
* 終了コマンドの場合はゲームを終了し、それ以外はCommandProcessorに処理を委譲します。
*
* @param input ユーザーからの入力文字列
*/
private void processInput(String input) {
if (EXIT_COMMAND.equals(input)) {
isRunning = false;
System.out.println(ANSIColors.YELLOW + "ゲームを終了します..." + ANSIColors.RESET);
} else {
commandProcessor.processCommand(input);
}
}
/**
* ゲーム終了時の後処理を行うメソッド
* リソースの解放とお別れメッセージの表示を行います。
*/
private void cleanup() {
scanner.close();
System.out.println(ANSIColors.GREEN + "プレイしていただきありがとうございました!" + ANSIColors.RESET);
}
}
CommandProcessor.java:ユーザーコマンドを処理するクラス
/**
* ユーザーコマンドを処理するクラス
* 入力されたコマンドに応じて適切な処理を実行します。
*/
public class CommandProcessor {
private final Player player;
/**
* CommandProcessorのコンストラクタ
* @param player 操作対象のPlayerオブジェクト
*/
public CommandProcessor(Player player) {
this.player = player;
}
/**
* 入力されたコマンドを処理するメソッド
* @param command ユーザーが入力したコマンド文字列
*/
public void processCommand(String command) {
switch (command) {
case "help" -> displayHelp();
case "status" -> player.displayStatus();
case "train" -> trainPlayer();
default -> System.out.println(ANSIColors.RED + "不明なコマンドです。'help' と入力してコマンドのリストを表示してください。" + ANSIColors.RESET);
}
}
/**
* ヘルプメッセージを表示するメソッド
* 利用可能なコマンドとその説明を表示します。
*/
private void displayHelp() {
System.out.println(ANSIColors.CYAN + "利用可能なコマンド:" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "help - このヘルプメッセージを表示" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "status - キャラクターのステータスを表示" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "train - トレーニングを行い経験値を獲得" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "exit - ゲームを終了" + ANSIColors.RESET);
}
/**
* プレイヤーのトレーニングを実行するメソッド
* ランダムな経験値を獲得し、プレイヤーのステータスを更新・表示します。
*/
private void trainPlayer() {
int expGained = (int) (Math.random() * 50) + 10; // 10から59の間でランダムな経験値を生成
player.gainExp(expGained);
player.displayStatus();
}
}
Player.java:プレイヤーを管理するクラス
import java.util.EnumMap;
import java.util.Map;
/**
* プレイヤーキャラクターを表すクラス
* プレイヤーの属性、レベル、経験値、ステータスを管理します。
*/
public class Player {
private final String name;
private int level;
private int exp;
private final Map<Stat, Integer> stats;
/**
* プレイヤーのステータスを表す列挙型
*/
public enum Stat {
HP, MAX_HP, MP, MAX_MP, ATTACK, DEFENSE, SPEED
}
/**
* Playerのコンストラクタ
* @param name プレイヤーの名前
*/
public Player(String name) {
this.name = name;
this.level = 1;
this.exp = 0;
this.stats = new EnumMap<>(Stat.class);
initializeStats();
}
/**
* 初期ステータスを設定するメソッド
*/
private void initializeStats() {
stats.put(Stat.HP, 100);
stats.put(Stat.MAX_HP, 100);
stats.put(Stat.MP, 50);
stats.put(Stat.MAX_MP, 50);
stats.put(Stat.ATTACK, 10);
stats.put(Stat.DEFENSE, 5);
stats.put(Stat.SPEED, 5);
}
/**
* 経験値を獲得するメソッド
* @param amount 獲得する経験値の量
*/
public void gainExp(int amount) {
exp += amount;
System.out.printf(ANSIColors.GREEN + "%sは%d経験値を獲得しました!%n" + ANSIColors.RESET, name, amount);
checkLevelUp();
}
/**
* レベルアップの条件を確認し、必要に応じてレベルアップを行うメソッド
*/
private void checkLevelUp() {
int expToNextLevel = level * 100;
while (exp >= expToNextLevel) {
levelUp();
expToNextLevel = level * 100;
}
}
/**
* レベルアップの処理を行うメソッド
* ステータスの増加と経験値の調整を行います。
*/
private void levelUp() {
level++;
exp -= (level - 1) * 100;
increaseStat(Stat.MAX_HP, 10);
increaseStat(Stat.MAX_MP, 5);
increaseStat(Stat.ATTACK, 2);
increaseStat(Stat.DEFENSE, 2);
increaseStat(Stat.SPEED, 1);
setStat(Stat.HP, getStat(Stat.MAX_HP));
setStat(Stat.MP, getStat(Stat.MAX_MP));
System.out.printf(ANSIColors.BRIGHT_PINK + "%sはレベル%dになりました!%n" + ANSIColors.RESET, name, level);
}
/**
* 指定されたステータスを増加させるメソッド
* @param stat 増加させるステータス
* @param amount 増加量
*/
private void increaseStat(Stat stat, int amount) {
stats.put(stat, stats.get(stat) + amount);
}
/**
* プレイヤーのステータスを表示するメソッド
*/
public void displayStatus() {
System.out.println(ANSIColors.CYAN + name + "のステータス:" + ANSIColors.RESET);
System.out.println(ANSIColors.CYAN + "レベル: " + ANSIColors.YELLOW + level + ANSIColors.RESET);
System.out.println(ANSIColors.CYAN + "経験値: " + ANSIColors.YELLOW + exp + "/" + (level * 100) + ANSIColors.RESET);
for (Stat stat : Stat.values()) {
System.out.printf(ANSIColors.CYAN + "%s:" + ANSIColors.YELLOW + " %d%n" + ANSIColors.RESET, stat.name(), stats.get(stat));
}
}
/**
* 指定されたステータスの値を取得するメソッド
* @param stat 取得するステータス
* @return ステータスの値
*/
public int getStat(Stat stat) {
return stats.getOrDefault(stat, 0);
}
/**
* 指定されたステータスに値を設定するメソッド
* @param stat 設定するステータス
* @param value 設定する値
*/
public void setStat(Stat stat, int value) {
stats.put(stat, value);
}
/**
* プレイヤーの名前を取得するメソッド
* @return プレイヤーの名前
*/
public String getName() {
return name;
}
/**
* プレイヤーのレベルを取得するメソッド
* @return プレイヤーのレベル
*/
public int getLevel() {
return level;
}
}
※ブログ表示の仕様上、設定した文字色とは異なります。実際に実行して文字色を確認してください。
※設定した文字色は旧式のPC環境下のコンソールでは機能しない可能性があります。
テキストベースRPGを開始します...
テキストベースRPGへようこそ!
ゲームの操作方法:'help' と入力してください。
> help
利用可能なコマンド:
help - このヘルプメッセージを表示
status - キャラクターのステータスを表示
train - トレーニングを行い経験値を獲得
exit - ゲームを終了
> train
勇者は12経験値を獲得しました!
勇者のステータス:
レベル: 1
経験値: 12/100
HP: 100
MAX_HP: 100
MP: 50
MAX_MP: 50
ATTACK: 10
DEFENSE: 5
SPEED: 5
> train
勇者は46経験値を獲得しました!
勇者のステータス:
レベル: 1
経験値: 58/100
HP: 100
MAX_HP: 100
MP: 50
MAX_MP: 50
ATTACK: 10
DEFENSE: 5
SPEED: 5
> train
勇者は35経験値を獲得しました!
勇者のステータス:
レベル: 1
経験値: 93/100
HP: 100
MAX_HP: 100
MP: 50
MAX_MP: 50
ATTACK: 10
DEFENSE: 5
SPEED: 5
> train
勇者は31経験値を獲得しました!
勇者はレベル2になりました!
勇者のステータス:
レベル: 2
経験値: 24/200
HP: 110
MAX_HP: 110
MP: 55
MAX_MP: 55
ATTACK: 12
DEFENSE: 7
SPEED: 6
>
ANSIColors.javaの解説
このコードは、ANSIカラーコードを定義するJavaクラスです。ANSIカラーコードは、コンソールやターミナルでテキストの色を変更するために使用されます。
※ANSIカラーコードは旧式のPC環境下のコンソールでは機能しない可能性があります。
public class ANSIColors {
// クラスの内容
}
これは ANSIColors
という名前のpublicクラスを定義しています。publicは、このクラスが他のクラスからアクセス可能であることを意味します。
クラス内部では、以下のような定数が定義されています:
public static final String RESET = "\u001B[0m";
public static final String RED = "\u001B[31m";
public static final String GREEN = "\u001B[32m";
public static final String YELLOW = "\u001B[33m";
public static final String CYAN = "\u001B[36m";
public static final String BRIGHT_PINK = "\u001B[95m";
これらの行は、各色のANSIエスケープコードを定義しています。
public
: この修飾子は、定数が他のクラスからアクセス可能であることを示します。static
: この修飾子は、定数がクラスに属し、インスタンス化せずに使用できることを意味します。final
: この修飾子は、定数の値が変更できないことを示します。String
: これは定数の型で、文字列であることを示します。
各定数の値は、ANSIエスケープシーケンスです:
\u001B
: これはエスケープ文字を表します。[XXm
: これは色を指定するコードです。例えば、31m
は赤色を意味します。
特に重要な点:
RESET
: この定数は、テキストの色をデフォルトに戻すために使用されます。- 他の定数(
RED
,GREEN
など)は、それぞれ特定の色を表します。
このクラスを使用すると、次のようにコンソール出力の色を変更できます:
System.out.println(ANSIColors.RED + "This text is red!" + ANSIColors.RESET);
この行は、”This text is red!”というテキストを赤色で出力し、その後テキストの色をリセットします。
よく使用される ANSI カラーコード:
色名 | 通常 | 明るい |
---|---|---|
黒 | \u001B[30m | \u001B[90m |
赤 | \u001B[31m | \u001B[91m |
緑 | \u001B[32m | \u001B[92m |
黄 | \u001B[33m | \u001B[93m |
青 | \u001B[34m | \u001B[94m |
マゼンタ | \u001B[35m | \u001B[95m |
シアン | \u001B[36m | \u001B[96m |
白 | \u001B[37m | \u001B[97m |
加えて、以下の特殊なコードも頻繁に使用されます:
- リセット:
\u001B[0m
- 太字:
\u001B[1m
- 下線:
\u001B[4m
これらのコードを組み合わせることで、テキストの色や書式を変更できます。例えば、赤色の太字テキストを作成するには、\u001B[1;31m
のように組み合わせて使用します。
RPGGame.javaの解説
このコードは、テキストベースのRPGゲームを開始するためのJavaプログラムのメインクラスです。
public class RPGGame {
// クラスの内容
}
これは RPGGame
という名前のpublicクラスを定義しています。このクラスがプログラムのエントリーポイントとなります。
public static void main(String[] args) {
// メインメソッドの内容
}
この部分はJavaプログラムのエントリーポイントです。プログラムが実行されると、まずこのmain
メソッドが呼び出されます。
public static void
: これらの修飾子は、メソッドが公開されており、クラスに属し、戻り値がないことを示します。String[] args
: コマンドライン引数を受け取るための配列です。
メインメソッド内の処理:
System.out.println(ANSIColors.CYAN + "テキストベースRPGを開始します..." + ANSIColors.RESET);
この行は、シアン色のテキストでゲーム開始メッセージを表示します。
ANSIColors.CYAN
: テキストをシアン色に設定します。ANSIColors.RESET
: テキストの色をデフォルトに戻します。
GameEngine gameEngine = new GameEngine();
この行はGameEngine
クラスの新しいインスタンスを作成し、gameEngine
変数に代入します。
gameEngine.start();
最後に、gameEngine
オブジェクトのstart()
メソッドを呼び出し、ゲームを開始します。
重要なポイント:
- メインクラス(
RPGGame
)の定義 main
メソッドの実装- ANSIカラーを使用したコンソール出力
GameEngine
オブジェクトの作成と使用
このプログラムは、ゲームエンジンを初期化し、ゲームを開始するための基本的な構造を提供しています。実際のゲームロジックはGameEngine
クラス内で実装されています。
GameEngine.javaの解説
このコードは、テキストベースRPGのゲームエンジンを実装したJavaクラスです。
- クラス定義と変数:
public class GameEngine {
private static final String EXIT_COMMAND = "exit";
private final Scanner scanner;
private final CommandProcessor commandProcessor;
private final Player player;
private boolean isRunning;
// ...
}
EXIT_COMMAND
: ゲーム終了コマンドを定義する定数scanner
: ユーザー入力を読み取るためのScannercommandProcessor
: ユーザーコマンドを処理するオブジェクトplayer
: プレイヤーオブジェクトisRunning
: ゲームが実行中かどうかを示すフラグ
- コンストラクタ:
public GameEngine() {
this.scanner = new Scanner(System.in);
this.player = new Player("勇者");
this.commandProcessor = new CommandProcessor(player);
this.isRunning = true;
}
ゲームエンジンの初期化を行います。Scannerの作成、プレイヤーの作成、コマンドプロセッサの初期化を行います。
- ゲーム開始メソッド:
public void start() {
init();
gameLoop();
cleanup();
}
ゲームの初期化、メインループ、終了処理を順番に実行します。
- 初期化メソッド:
private void init() {
System.out.println(ANSIColors.GREEN + "テキストベースRPGへようこそ!" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "ゲームの操作方法:'help' と入力してください。" + ANSIColors.RESET);
}
ゲーム開始時のメッセージを表示します。
- ゲームループ:
private void gameLoop() {
while (isRunning) {
System.out.print("> ");
String input = scanner.nextLine().trim().toLowerCase();
processInput(input);
}
}
ゲームのメインループです。ユーザー入力を受け取り、処理します。
scanner.nextLine()
:ユーザーからの入力を1行読み取ります。.trim()
:取得した文字列の先頭と末尾にある空白文字(スペース、タブ、改行など)を削除します。これにより、ユーザーが誤って入力した余分な空白を除去できます。.toLowerCase()
:文字列をすべて小文字に変換します。これにより、大文字小文字の違いを無視してコマンドを処理できるようになります。
- 入力処理:
private void processInput(String input) {
if (EXIT_COMMAND.equals(input)) {
isRunning = false;
System.out.println(ANSIColors.YELLOW + "ゲームを終了します..." + ANSIColors.RESET);
} else {
commandProcessor.processCommand(input);
}
}
ユーザー入力が”exit”の場合はゲームを終了し、それ以外はコマンドプロセッサに処理を委譲します。
- 終了処理:
private void cleanup() {
scanner.close();
System.out.println(ANSIColors.GREEN + "プレイしていただきありがとうございました!" + ANSIColors.RESET);
}
Scannerを閉じ、終了メッセージを表示します。
重要なポイント:
- ゲームループの実装
- ユーザー入力の処理
- コマンドパターンの使用 (CommandProcessorクラスを通じて)
- ANSIカラーを使用したテキスト装飾
このGameEngineクラスは、テキストベースRPGの基本的な構造を提供し、ユーザー入力の受け取りとコマンドの処理を管理しています。
CommandProcessor.javaの解説
このコードは、テキストベースRPGのコマンド処理を担当するCommandProcessor
クラスを定義しています。
- クラス定義と変数:
public class CommandProcessor {
private final Player player;
// ...
}
player
: コマンドの対象となるプレイヤーオブジェクト
- コンストラクタ:
public CommandProcessor(Player player) {
this.player = player;
}
Player
オブジェクトを受け取り、フィールドに設定します。
- コマンド処理メソッド:
public void processCommand(String command) {
switch (command) {
case "help" -> displayHelp();
case "status" -> player.displayStatus();
case "train" -> trainPlayer();
default -> System.out.println(ANSIColors.RED + "不明なコマンドです。'help' と入力してコマンドのリストを表示してください。" + ANSIColors.RESET);
}
}
このメソッドは入力されたコマンドに応じて適切な処理を実行します。
switch
文を使用して、各コマンドに対応する処理を呼び出しています。- ラムダ式 (
->
) を使用した新しいswitch式の構文を採用しています。 - 不明なコマンドの場合は、エラーメッセージを表示します。
- ヘルプ表示メソッド:
private void displayHelp() {
System.out.println(ANSIColors.CYAN + "利用可能なコマンド:" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "help - このヘルプメッセージを表示" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "status - キャラクターのステータスを表示" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "train - トレーニングを行い経験値を獲得" + ANSIColors.RESET);
System.out.println(ANSIColors.YELLOW + "exit - ゲームを終了" + ANSIColors.RESET);
}
利用可能なコマンドとその説明を表示します。ANSIカラーを使用して、テキストを装飾しています。
- トレーニングメソッド:
private void trainPlayer() {
int expGained = (int) (Math.random() * 50) + 10;
player.gainExp(expGained);
player.displayStatus();
}
- ランダムな経験値(10〜59)を生成します。
- プレイヤーに経験値を付与し、ステータスを表示します。
Math.random()
についてMath.random()
: 0.0以上1.0未満のランダムな小数を生成します。* 50
: 生成された乱数を50倍します。結果は0.0以上50.0未満の値になります。(int)
: 小数を整数に変換します(小数点以下を切り捨て)。+ 10
: 最後に10を加算します。- 結果として、
expGained
には10以上60未満(10〜59)のランダムな整数が代入されます。
重要なポイント:
- コマンドパターンの実装:各コマンドに対応する処理を一箇所にまとめています。
- switch文を使用したコマンド分岐
- カプセル化:
player
オブジェクトを通じてプレイヤーの操作を行っています。 - ANSIカラーを使用したテキスト装飾
このクラスは、ユーザーからのコマンド入力を解釈し、適切な処理を実行する役割を果たしています。これにより、ゲームの主要な機能(ヘルプ表示、ステータス確認、トレーニング)が実現されています。
Player.javaの解説
このコードは、RPGゲームのプレイヤーを表現するPlayer
クラスを定義しています。
import java.util.EnumMap;
import java.util.Map;
※Map
と enum
(列挙型) の組み合わせを使用して EnumMap
を初期化し、その後は EnumMap
の機能を活用してプレイヤーのステータス管理を実装しています。この方法により、型安全性が確保され、効率的なステータス管理が可能になっています。
- クラス定義と変数:
public class Player {
private final String name;
private int level;
private int exp;
private final Map<Stat, Integer> stats;
public enum Stat {
HP, MAX_HP, MP, MAX_MP, ATTACK, DEFENSE, SPEED
}
// ...
}
name
: プレイヤーの名前level
: プレイヤーのレベルexp
: 現在の経験値stats
: プレイヤーのステータスを保持するマップStat
: ステータスの種類を定義する列挙型
private final Map<Stat, Integer> stats;
Map
: キーと値のペアを保存するデータ構造です。<Stat, Integer>
: このマップはStat
型のキーとInteger
型の値を持ちます。final
: このマップの参照は変更できません(ただし、中身は変更可能です)。
この構造により、各ステータス(HP、MP、攻撃力など)とその数値を効率的に管理できます。
Map<Stat, Integer>
と enum Stat
を組み合わせる利点:
- 各ステータスとその値を簡単に関連付けられます。
- 新しいステータスの追加が容易です(enum に追加するだけ)。
- ステータス名のタイプミスを防ぎ、コードの安全性が向上します。
- ステータスに関連する操作(取得、設定、更新など)を一貫した方法で行えます。
この設計により、プレイヤーのステータス管理が効率的かつ安全に行えるようになっています。
- コンストラクタ:
public Player(String name) {
this.name = name;
this.level = 1;
this.exp = 0;
this.stats = new EnumMap<>(Stat.class);
initializeStats();
}
プレイヤーを初期化し、初期ステータスを設定します。
this.stats = new EnumMap<>(Stat.class);
new EnumMap<>(Stat.class)
: 新しいEnumMap
インスタンスを作成しています。Stat.class
を引数として渡すことで、このEnumMap
がStat
列挙型をキーとして使用することを指定しています。EnumMap
はStat
型のキーとInteger
型の値を持つマップです。
EnumMap
の特徴:
- キーが列挙型に限定されるため、型安全性が高くなります。
- 内部的に配列として実装されているため、通常の
HashMap
よりも効率的です。 - キーの自然順序(列挙定数の宣言順)で要素が管理されます。
- ステータス初期化:
private void initializeStats() {
stats.put(Stat.HP, 100);
stats.put(Stat.MAX_HP, 100);
// ...
}
- このメソッドは、
stats
EnumMap に各ステータスの初期値を設定しています。 stats.put(Stat.キー, 値)
: EnumMap に新しいキーと値のペアを追加します。
- 経験値獲得とレベルアップチェック:
public void gainExp(int amount) {
exp += amount;
System.out.printf(ANSIColors.GREEN + "%sは%d経験値を獲得しました!%n" + ANSIColors.RESET, name, amount);
checkLevelUp();
}
private void checkLevelUp() {
int expToNextLevel = level * 100;
while (exp >= expToNextLevel) {
levelUp();
expToNextLevel = level * 100;
}
}
gainExp メソッド:
このメソッドは、プレイヤーが経験値を獲得する際に呼び出されます。
exp += amount;
: プレイヤーの現在の経験値(exp)に、獲得した経験値(amount)を加算します。System.out.printf(...)
:- 経験値獲得のメッセージを表示します。
ANSIColors.GREEN
: メッセージを緑色で表示します。%s
: プレイヤーの名前(name)が入ります。%d
: 獲得した経験値(amount)が入ります。%n
: 改行を表します。ANSIColors.RESET
: テキストの色をデフォルトに戻します。
checkLevelUp();
: レベルアップの条件を確認するメソッドを呼び出します。
checkLevelUp メソッド:
このメソッドは、プレイヤーの経験値が次のレベルに必要な量に達しているかを確認し、レベルアップの処理を行います。
int expToNextLevel = level * 100;
- 次のレベルに必要な経験値を計算します。
- 現在のレベルに100を掛けた値が、次のレベルに必要な経験値となります。
while (exp >= expToNextLevel) { ... }
- プレイヤーの現在の経験値が、次のレベルに必要な経験値以上である限り、ループが続きます。
- これにより、一度に複数レベルアップする可能性にも対応しています。
- ループ内の処理:
levelUp();
: レベルアップの処理を行うメソッドを呼び出します。expToNextLevel = level * 100;
: レベルアップ後、次のレベルに必要な経験値を再計算します。
- レベルアップ処理:
private void levelUp() {
level++;
exp -= (level - 1) * 100;
increaseStat(Stat.MAX_HP, 10);
increaseStat(Stat.MAX_MP, 5);
increaseStat(Stat.ATTACK, 2);
increaseStat(Stat.DEFENSE, 2);
increaseStat(Stat.SPEED, 1);
setStat(Stat.HP, getStat(Stat.MAX_HP));
setStat(Stat.MP, getStat(Stat.MAX_MP));
System.out.printf(ANSIColors.BRIGHT_PINK + "%sはレベル%dになりました!%n" + ANSIColors.RESET, name, level);
}
private void increaseStat(Stat stat, int amount) {
stats.put(stat, stats.get(stat) + amount);
}
レベルアップ時にステータスを増加させ、メッセージを表示します。
レベルと経験値の調整:
level++
: プレイヤーのレベルを1増やします。exp -= (level - 1) * 100
: 現在の経験値から、レベルアップに必要だった経験値を引きます。これにより、余剰の経験値が次のレベルアップに持ち越されます。
ステータスの増加:
increaseStat
メソッドを呼び出し、ステータスの増加をします。
- 最大HP: 10増加
- 最大MP: 5増加
- 攻撃力: 2増加
- 防御力: 2増加
- 速度: 1増加
HPとMPの回復:
setStat
メソッドを使用して、HPとMPを最大値まで回復させます。getStat
メソッドで最大値ステータスの値を取得して、setStat
メソッドで指定されたステータスに値をセットします。
レベルアップメッセージの表示:
- レベルアップのメッセージを表示します。
ANSIColors.BRIGHT_PINK
を使用して、メッセージを明るいピンク色で表示します。%s
にプレイヤーの名前、%d
に新しいレベルが入ります。ANSIColors.RESET
でテキストの色をデフォルトに戻します。
increaseStat メソッド:
- メソッドの定義
private
: このメソッドはクラス内部でのみ使用可能です。void
: このメソッドは値を返しません。Stat stat
: 増加させるステータスを指定するパラメータです。int amount
: 増加させる量を指定するパラメータです。
- メソッドの本体
stats.get(stat)
: 指定されたステータス(stat
)の現在の値を取得します。stats.get(stat) + amount
: 現在の値に増加量(amount
)を加算します。stats.put(stat, ...)
: 計算結果を新しい値として、指定されたステータス(stat
)に設定します。
- ステータス表示:
public void displayStatus() {
// プレイヤー名の表示
System.out.println(ANSIColors.CYAN + name + "のステータス:" + ANSIColors.RESET);
// レベルの表示
System.out.println(ANSIColors.CYAN + "レベル: " + ANSIColors.YELLOW + level + ANSIColors.RESET);
// 経験値の表示
System.out.println(ANSIColors.CYAN + "経験値: " + ANSIColors.YELLOW + exp + "/" + (level * 100) + ANSIColors.RESET);
// 各ステータスの表示
for (Stat stat : Stat.values()) {
System.out.printf(ANSIColors.CYAN + "%s:" + ANSIColors.YELLOW + " %d%n" + ANSIColors.RESET, stat.name(), stats.get(stat));
}
}
プレイヤーの現在のステータスを表示します。
- 各ステータスの表示:
for
ループを使用して、すべてのステータスを順番に表示します。Stat.values()
でStat
列挙型のすべての値を取得しています。stat.name()
でステータスの名前を、stats.get(stat)
でその値を取得しています。System.out.printf()
を使用して、フォーマットされた文字列を出力しています。%s
: ステータス名%d
: ステータス値%n
: 改行
- EnumMap の活用:
stats.get(stat)
で EnumMap から各ステータスの値を取得しています。
- ユーティリティメソッド:
public int getStat(Stat stat) {
return stats.getOrDefault(stat, 0);
}
public void setStat(Stat stat, int value) {
stats.put(stat, value);
}
public String getName() {
return name;
}
public int getLevel() {
return level;
}
ステータスの取得と設定を行うメソッドです。
getStat メソッド:
- 目的: 指定されたステータスの値を取得します。
- パラメータ:
Stat stat
– 取得したいステータス - 戻り値: 指定されたステータスの値(整数)
- 特徴:
public
: クラス外からアクセス可能stats.getOrDefault(stat, 0)
: 指定されたステータスが存在しない場合、デフォルト値として0を返します。これにより、NullPointerExceptionを防ぎます。
setStat メソッド:
- 目的: 指定されたステータスに新しい値を設定します。
- パラメータ:
Stat stat
– 設定したいステータスint value
– 設定する値- 戻り値: なし(void)
- 特徴:
public
: クラス外からアクセス可能stats.put(stat, value)
: 指定されたステータスに新しい値を設定します。
getName メソッド:
- 目的: プレイヤーの名前を取得します。
- パラメータ: なし
- 戻り値: プレイヤーの名前(String)
- 特徴:
public
: クラス外からアクセス可能- 単純にnameフィールドの値を返します。
getLevel メソッド:
- 目的: プレイヤーの現在のレベルを取得します。
- パラメータ: なし
- 戻り値: プレイヤーのレベル(整数)
- 特徴:
public
: クラス外からアクセス可能- 単純にlevelフィールドの値を返します。
まとめ
- キャラクター作成:
Player
クラスを通じて、RPGの基本となるキャラクター管理システムを実装 - ANSIColors: コンソール出力に色を付けることで、ユーザーエクスペリエンスを向上させる方法
- RPGGame: メインクラスとしてゲームの起動と終了を管理する方法
- GameEngine: ゲームのメインループと状態管理を担当するクラスの設計と実装
- CommandProcessor: ユーザー入力を解釈し、適切なアクションを実行するシステムを構築
- Player: 列挙型とEnumMapを使用して、効率的なステータス管理とレベルアップシステムを実装
このプロジェクトを通じて、オブジェクト指向プログラミングの重要な概念(カプセル化、継承、ポリモーフィズム)を実践的に適用する方法を学びました。
さらに、このプロジェクトはゲーム開発の基本的なアーキテクチャを示しており、より複雑なゲームシステムへの拡張の基礎となります。コマンドパターンの使用、状態管理、ユーザー入力の処理など、ゲーム開発特有の設計パターンも学ぶことができました。
コメント