
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.h | printf、fgets、fopen |
| stdlib.h | rand、srand、malloc |
| string.h | strcpy、strcmp、memset |
| time.h | time、乱数初期化 |
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 は流れだけを書く司令塔
