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