C言語入門|STEP11:rpg1.c を読み解こう-プログラム全体構成と設計方針の確認

はじめに:実装編のスタートです

STEP1~STEP10では、
バトルRPGを 作りながら理解する流れ で解説してきました。

STEP11からは視点を切り替えて、

  • すでに完成している rpg1.c を
  • 実際のコードを抜粋しながら
  • どんな意図で書かれているのか

実装ロジック中心 に読み解いていきます。

このSTEP11では、まず
プログラム全体の構造と設計の考え方 を押さえます。

rpg1.c はどんな構成になっているのか

rpg1.c は、1ファイルですが
中身ははっきりと役割ごとに分かれています。

大まかな構成は次のとおりです。

区分主な内容
ヘッダ部include、define、enum、struct
ユーティリティ画面制御、入力処理
データ定義キャラ・敵・アイテム
初期化処理キャラ・マップ・魔法
コアロジックバトル、探索、イベント
制御部main 関数

「上から読んでいけば全体像がつかめる」
という、学習向きの並びになっています。

include と define の役割

まず冒頭では、必要なヘッダファイルが読み込まれています。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

これらは何をするものか

ヘッダ主な役割
stdio.hprintf、fgets、fopen
stdlib.hrand、srand、malloc
string.hstrcpy、strcmp、memset
time.htime、乱数初期化

C言語では、
使う関数に対応するヘッダを必ず include する
という基本ルールを、ここで自然に確認できます。

定数を define でまとめている理由

次に目立つのが、多数の define 定義です。

#define MAP_H 25
#define MAP_W 25
#define PARTY_SIZE 3
#define MAX_LEVEL 20

なぜ数値を直接書かないのか

理由はとてもシンプルです。

  • 数字の意味が分かりやすくなる。
  • 変更が一か所で済む。
  • バグを防ぎやすい。

たとえば、
パーティ人数を 4 人にしたい場合でも
PARTY_SIZE を直すだけで済みます。

enum を多用している設計意図

このRPGでは、
enum が非常に多く使われています。

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

enum を使うメリット

メリット内容
可読性数値の意味が明確
安全性間違った値を防ぎやすい。
拡張性職業や種類を増やしやすい。

Job を int で管理するより、
プログラムの意図がはっきり伝わる ようになります。

構造体設計がこのRPGの心臓部

rpg1.c で最も重要なのが、構造体の設計です。

typedef struct {
    char name[20];
    Job job;
    int level;
    int hp, max_hp;
    int mp, max_mp;
    int base_atk;
    int base_magic;
    int alive;
} Character;

なぜ構造体を使うのか

RPGでは、

  • 名前
  • ステータス
  • 状態

ひとまとまりの情報 になります。

構造体を使うことで、

  • キャラ1人分を1変数で扱える。
  • 配列でパーティ管理できる。
  • 関数に渡しやすい。

という利点があります。

GameState 構造体の役割

このプログラム最大のポイントが
GameState 構造体 です。

typedef struct {
    int px, py;
    char map[MAP_H][MAP_W];
    Character party[PARTY_SIZE];
    int inv[ITEM_COUNT];
    int game_clear;
} GameState;

これが何を意味しているか

GameState 1つで、

  • プレイヤー位置
  • マップ状況
  • パーティ情報
  • アイテム所持数

ゲーム全体の状態が完全に表現 されています。

この設計のおかげで、

  • セーブ
  • ロード

が非常に簡単になります。

関数配置の考え方

rpg1.c では、

  • 初期化関数
  • 表示関数
  • 処理関数

用途ごとにまとまって配置 されています。

例として、画面制御関数です。

void clear_screen(void) {
#ifdef _WIN32
    system("cls");
#else
    system("clear");
#endif
}

なぜ関数に分けるのか

  • 同じ処理を何度も書かない。
  • main を読みやすくする。
  • 役割を分離する。

C言語では特に、
main をシンプルに保つこと が重要です。

main 関数は「司令塔」

最後に main 関数があります。

int main(void) {
    srand((unsigned)time(NULL));
    show_title();
    load_map_template(gs.map);
    init_characters(gs.party);

    while (1) {
        draw_map(&gs);
        // 入力処理とイベント分岐
    }
}

main でやっていること

  • 初期化を呼び出す。
  • ループでゲームを進める。
  • 細かい処理は関数に任せる。

つまり main は、
処理の流れだけを書く場所 になっています。

単一ファイルでも整理できる理由

ここまで見てきたように、
rpg1.c は1ファイルですが、

  • define
  • enum
  • struct
  • 関数

が整理されているため、
実質的には複数ファイル構成の考え方 になっています。

この構造を理解しておくと、
15章で行う ファイル分割 がとても楽になります。

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

STEP11では、次の点を理解しておきましょう。

  • rpg1.c は役割ごとに構成されている。
  • define と enum は可読性と安全性のため
  • 構造体がRPGの情報管理の中心
  • GameState がセーブ設計の鍵
  • main は流れだけを書く司令塔