Java
デザインパターン
ゲーム制作
ゲームプログラミング
Breed

【Breed】RPGのモンスターなどのキャラクターを作成するときに使うデザインパターン

RPGなど、キャラクターを扱うゲームを制作するときにに役に立つデザインパターンの情報です。
有名なGoFデザインパターンの23種類の中に含まれているものではありません。
サンプルコードはJavaで書いておりますが、UnityやC++など他の言語でも応用可能です。

モンスタークラス

登場人物をオブジェクト指向のプログラムで作る時の一例をここで示しておきます。
まず、親クラス(あるいはインターフェース)としてキャラクターのモデルクラスを定義し、それを継承する形で、主人公やその仲間、モンスターなどのクラスを定義します。

//キャラクターを表す抽象クラスのフィールドの定義の一例
public abstract class Character{
  //名前
   protected String name;
  //ヒットポイント 
   protected int hp;
   //ヒットポイント最大値
   protected int maxHp
   //攻撃力
   protected int attackPower;
   //その他ゲームで必要になるステータス(ここでは省略)
      ....
}
//キャラクタークラスを継承したモンスター『スライム』を表すクラス
public class Slime extends Character{
  //スライム(名前 スライム,HP 7/7,攻撃力 10のモンスター)を新規作成するコンストラクタ
  Slime(){
      super.name = "スライム";
      super.hp = 7;
      super.maxHp = 7;
      super.attackPower = 10;
      //以下略
      ...
   }
}

課題

さて、ここで、実際に普段遊ばれているゲームを想像していただきたいのです。

敵が登場する場合、同じ種族の敵が複数同時に登場することは珍しくありません。
『スライムA』『スライムB』『スライムC』なんて一体ずつを識別するためのアルファベットなどを割り振られながら。

また、モンスターが仲間になるRPGがあった場合、モンスターごとに個性が与えられることがあります。オス/メスだとかのんびり屋さん/せっかちのような性格だとか、少しずつ能力値が違ったり、あるいはプレイヤーが個別に名前をつけられたら愛着がわくかもしれません。

そういった要素を作りこむ場合には、『スライム』という種族としての個性以外に『スライムA』としての個体としての個性を与えなければなりません。

また、別のケースを考えてみましょう。
たとえば、モンスターが151種類登場する大作ゲームを考えてみましょう。
そういったものを作る場合、いくつモデルクラスをいくつ作らないといけないでしょうか。親クラスが1つとして、それに加えて、151種類のモデルクラスを作る必要が出てきます。そうなるとソースコードの量が膨大になっていき、開発だけでなく、保守運用も大変になっていきます。

Breedパターン

これらを解決するデザインパターンがBreedパターンです。Breedとは英語でそのまま種族のことです。最大HPや攻撃力、モンスター名など、種族固有の数値は種族クラスのインスタンスをフィールドとしてキャラクターに持たせます。

//種族クラス
public class Breed{
   //種族の名前(スライム,ドラゴン,勇者,魔法使いなど)
   private String name;
   private int maxHp;
   private int attackPower;
   //以下略
   ...
}
public class Character{
   //種族クラスのインスタンスをフィールド変数にする
   private Breed breed;
   //キャラクターの名前(スライムA,ロト,サトシなど)
   private String name;
   private int hp;
   //以下略
   ...
}

メリット

このパターンを採用することにより、スライムやドラゴンという種族を示す数多くのクラスが不要になり、すべて種族クラスのインスタンスになります。つまり、クラスの数はモンスターの種類の数だけ必要だったのが、キャラクタークラスと種族クラスの2つにまで減ります。

種族の名前と個体の名前を明確に分けて管理することができるので、スライムが複数同時に出てくる時にアルファベットを割り振るのも簡単になります。

また、150種類モンスターが居る状態で151匹目を追加したいとき、プログラムのソースコードを一行も書き換える必要がなくなります。外部のリレーショナルデータベースへ、あるいはJson形式で設定ファイルに新規データを追加するだけでいいのです。もちろん、外部データをBreedインスタンスに復元するロジックをあらかじめ組んでいる必要はありますが。これによって、プログラムが読めない人にも保守運用を任せられるようになります。

//json形式,後から容易にデータを追加可能
[
{名前:"スライム",maxHp:7,attackPower:10, ... },
{名前:"ドラゴン",maxHp:1000,attackPower:100, ... },
];

筆者は、プレイユーザーがモンスターを自分で設計できるゲーム(たとえばRPGツクールのようなものを思い浮かべると分かりやすい)を作ろうとしていたのですが、モンスターのデータをデータベースに外部化するように作らないと、モンスターデータをユーザーが後から追加できないという壁にぶち当たり、そのときにBreedパターンが役に立ちました。

参考資料

Game Programming Patterns ソフトウェア開発の問題解決メニュー impress top gearシリーズ