STEP12:キャラクターと職業の実装-構造体・列挙型・初期化処理

はじめに:RPGの主役はキャラクター

STEP11では、rpg1.c 全体の構造と設計方針を確認しました。
STEP12では、RPGの中心となる キャラクターと職業の実装 に注目します。

RPGでは、

  • 誰が
  • どんな能力を持ち
  • どんな役割で戦うのか

を明確にすることがとても重要です。
このSTEPでは、それを C言語の構造体と列挙型でどう表現しているか を見ていきましょう。

職業を enum で定義する理由

まず登場するのが、職業を表す列挙型です。

typedef enum { HERO = 0, WARRIOR = 1, MAGE = 2, JOB_COUNT = 3 } Job;

この enum が表しているもの

名前意味
HERO勇者
WARRIOR戦士
MAGE魔法使い
JOB_COUNT職業数

JOB_COUNT を含めているのは、
配列サイズやループ処理で使いやすくするためです。

enum を使うメリット

  • 数値の意味がコードから読み取れる。
  • 職業を増やしても管理しやすい。
  • 条件分岐が分かりやすい。

RPGのように「種類」が多いプログラムでは、
enum は非常に相性が良い仕組みです。

Character 構造体の全体像

次に、キャラクターを表す構造体を見てみましょう。

typedef struct {
    char name[20];
    Job job;
    int level;

    int hp, max_hp;
    int mp, max_mp;

    int base_atk;
    int base_magic;

    int weapon_atk;
    int staff_magic;

    int alive;
    int exp;

    int defending;
    Spell spells[SPELLS_PER_CHAR];
} Character;

なぜここまで情報をまとめているのか

キャラクターには、

  • 基本情報
  • 戦闘用ステータス
  • 状態フラグ
  • 使用できる魔法

といった 多くの情報 が必要です。

構造体にまとめることで、

  • キャラ1人を1変数として扱える。
  • 配列でパーティを管理できる。
  • 関数にそのまま渡せる。

という利点があります。

各メンバ変数の役割を整理しよう

Character 構造体の中身を、役割ごとに整理します。

基本情報

変数役割
nameキャラクター名
job職業
level現在のレベル
exp所持経験値

ステータス関連

変数役割
hp / max_hp現在HP / 最大HP
mp / max_mp現在MP / 最大MP
base_atk基礎攻撃力
base_magic基礎魔力

基礎ステータスと現在値を分けているのがポイントです。

装備・状態管理

変数役割
weapon_atk武器による攻撃力加算
staff_magic杖による魔力加算
alive生存フラグ
defending防御状態フラグ

これにより、

  • 装備変更
  • 一時的な防御効果

を簡単に表現できます。

魔法を配列で持たせている理由

Character 構造体の最後には、魔法配列があります。

Spell spells[SPELLS_PER_CHAR];

この設計のメリット

  • キャラごとに使える魔法が明確
  • 魔法選択をループで処理できる。
  • 職業ごとの差別化が簡単

魔法を外部テーブルではなく、
キャラ自身が持つ設計 にしている点が特徴です。

キャラクター初期化処理の考え方

キャラクターは、init_characters 関数で初期化されます。

static void init_characters(Character p[]) {
    p[0] = (Character){ "勇者", HERO, 1, 55,55, 12,12, 8, 6, 0,0, 1, 0, 0,0, {0} };
    p[1] = (Character){ "戦士", WARRIOR,1, 65,65,  8, 8, 12,3, 0,0, 1, 0, 0,0, {0} };
    p[2] = (Character){ "魔法使い", MAGE,1, 45,45, 22,22,  5,12,0,0, 1, 0, 0,0, {0} };
}

初期化で行っていること

  • 職業ごとに異なる初期ステータスを設定
  • レベルは全員1からスタート
  • 装備補正は0から開始

この段階では、
あえてシンプルな初期状態 にしています。

職業ごとの個性をどう表現しているか

初期ステータスを見ると、
職業ごとの役割がはっきり分かります。

職業特徴
勇者バランス型
戦士HP・攻撃力が高い
魔法使いMP・魔力が高い

この違いが、

  • 戦闘時の役割分担
  • 魔法や装備の選択

につながっていきます。

魔法の初期化処理との関係

init_characters の中では、
各キャラに対して魔法初期化関数も呼ばれています。

init_spells(&p[i]);

これにより、

  • 職業に応じた魔法セット
  • キャラごとの行動選択肢

が自然に決まります。

職業 → 魔法 → 戦闘スタイル
という流れが、コード上でもはっきりしています。

alive フラグを使う理由

alive は、

  • 生存しているか
  • 戦闘不能か

を表すフラグです。

HP が 0 になっただけではなく、
alive を明示的に管理することで、

  • 行動不可判定
  • 回復・復活処理

を簡単に制御できます。

STEP12で押さえておきたいポイントまとめ

STEP12で理解しておきたいポイントはこちらです。

  • 職業は enum で安全に管理する。
  • キャラクターは構造体で一元管理する。
  • 基礎ステータスと補正値を分ける。
  • 魔法はキャラが直接持つ設計。
  • 初期化処理で職業の個性を作る。