
STEP13:成長システムの実装-経験値・レベルアップ・成長テーブルの仕組み
はじめに:成長があるからRPGは楽しい
RPGの面白さの大きな要素が、
キャラクターが少しずつ強くなっていくこと です。
STEP13では、
- 経験値の管理
- レベルアップの判定
- 職業ごとの成長差
といった 成長システムの実装ロジック を、
実際の rpg1.c のコードを見ながら解説します。
経験値とレベルの基本設計
まず、このRPGでの成長の考え方を整理しましょう。
| 要素 | 内容 |
|---|---|
| レベル | キャラクターの強さの段階 |
| 経験値 | レベルアップのためのポイント |
| 最大レベル | 20 |
キャラクターは、
- 戦闘に勝利すると経験値を獲得
- 一定量を超えるとレベルアップ
という、王道の仕組みになっています。
次のレベルに必要な経験値の計算
まず登場するのが、必要経験値を返す関数です。
static int need_exp(int level) {
return level * 20;
}この式の意味
| レベル | 必要経験値 |
|---|---|
| 1 → 2 | 20 |
| 2 → 3 | 40 |
| 3 → 4 | 60 |
レベルが上がるほど、
次に必要な経験値も増える という設計です。
シンプルですが、
- 調整しやすい
- 分かりやすい
という、学習向きの実装です。
レベルアップ処理の全体像
次に、レベルアップの処理を見てみましょう。
static void level_up(Character* c) {
if (c->level >= MAX_LEVEL) return;
c->level++;
Growth g = g_growth[c->job][c->level];
c->max_hp += g.hp;
c->hp += g.hp;
c->max_mp += g.mp;
c->mp += g.mp;
c->base_atk += g.atk;
c->base_magic += g.mag;
}何をしている関数か
この関数は、
- レベルを1上げる。
- 職業とレベルに応じた成長量を取得
- ステータスを加算
という処理をまとめています。
成長テーブルを使う理由
成長量は、計算式ではなく
テーブル(配列)で管理 されています。
typedef struct { int hp, mp, atk, mag; } Growth;
static const Growth g_growth[JOB_COUNT][MAX_LEVEL + 1] = {
/* 職業ごとの成長量 */
};なぜテーブルなのか
| 理由 | 内容 |
|---|---|
| バランス調整 | 数値を見て直感的に調整 |
| 職業差 | 職業ごとに個性を出せる |
| 拡張性 | 新職業を追加しやすい |
RPGでは、
数値調整そのものが設計 になるため、
テーブル管理はとても相性が良い方法です。
職業ごとの成長の違い
成長テーブルを見ると、
職業ごとの差がはっきりしています。
| 職業 | 成長傾向 |
|---|---|
| 勇者 | 全体的にバランス型 |
| 戦士 | HPと攻撃力が大きく伸びる。 |
| 魔法使い | MPと魔力が大きく伸びる。 |
これにより、
- 同じレベルでも役割が違う。
- パーティの役割分担が生まれる。
というRPGらしさが実現されています。
現在HP・MPも一緒に増やす理由
レベルアップ時に、
c->max_hp += g.hp;
c->hp += g.hp;と、最大値と現在値を同時に増やしています。
その理由
- レベルアップ直後に強くなった実感がある。
- 回復しないと使えない、という不満を防ぐ。
プレイヤー体験を考えた、
やさしい設計 になっています。
経験値をパーティ全員に配る処理
戦闘後の経験値配布は、
add_exp_party 関数で行われます。
static void add_exp_party(Character p[], int exp) {
for (int i = 0; i < PARTY_SIZE; i++) {
if (!p[i].alive) continue;
p[i].exp += exp;
while (p[i].exp >= need_exp(p[i].level)) {
p[i].exp -= need_exp(p[i].level);
level_up(&p[i]);
}
}
}ここで重要なポイント
- 生存しているキャラだけが対象
- 余った経験値は次のレベルへ持ち越し
- 一気に複数レベル上がる可能性もある。
while を使っていることで、
大量の経験値でも正しく処理できます。
MAX_LEVEL を超えない安全設計
レベルアップ関数の冒頭には、
次のチェックがあります。
if (c->level >= MAX_LEVEL) return;これにより、
- 配列の範囲外アクセス
- 想定外の数値増加
を防いでいます。
上限を決めておく ことは、
安定したプログラムの基本です。
成長処理を関数にまとめるメリット
成長処理を level_up にまとめていることで、
- バトル処理がスッキリする。
- 修正が1か所で済む。
- ロジックの再利用ができる。
というメリットがあります。
RPGのような規模のプログラムでは、
成長処理は必ず独立させる のが定石です。
STEP13で押さえておきたいポイントまとめ
STEP13の重要ポイントはこちらです。
- 経験値とレベルは明確に役割分担する。
- 必要経験値は関数で計算する。
- 成長量はテーブルで管理する。
- 職業ごとの差別化を数値で表現する。
- レベルアップ処理は安全に設計する。
