
STEP02:platform層の実装(画面クリア・効果音・色表現の土台)
STEP02では、ゲーム全体で共通して使う「環境依存の処理」を platform 層として切り出します。
今回のRPGは Visual Studio(Windows)で動かすのが前提ですが、元の rpg1.c では Linux/Mac でも動くように #ifdef _WIN32 で分岐していましたよね。
このSTEPで作る platform 層は、ざっくり言うと次の2つを担当します。
- 画面クリア(Windowsなら cls / Linuxなら clear)
- 効果音(Windowsなら Beep / それ以外なら端末ベル)
そして「色表現(ANSIカラー)」は platform.c に実装するのではなく、common.h 側で定義して全モジュールから使える土台にしておきます。
(なので STEP02 では “platform層 + 色表現の土台(common.h)” という位置づけです)
platform層でやりたいこと(役割の整理)
platform層に置く処理の特徴はこれです。
| 種類 | 例 | なぜplatform層? |
|---|---|---|
| OS依存の処理 | system("cls") / system("clear") | OSでコマンドが違う |
| OS依存のAPI | Beep(周波数, ミリ秒) | Windows固有の関数だから |
| 環境によって動かない可能性 | printf("\a") のベル | 端末設定で鳴らないこともある |
つまり、ゲームロジック(battle/map/itemsなど)がOS差分を気にしないようにするのがplatform層の価値です。
STEP02で登場するファイル
このSTEPで扱うのはこの3点です。
| ファイル | 役割 |
|---|---|
| common.h | 色コード(ANSIカラー)や共通定義、Windowsヘッダの取り込み |
| platform.h | platform層の公開関数(宣言) |
| platform.c | platform層の実装(画面クリア・効果音) |
common.h:色表現の「土台」をここに置く理由
色(ANSIカラー)は、ui.c / map.c / battle.c など、あちこちで使います。
だから platform.c に置くより、共通ヘッダ common.h に置いてしまうのがラクです。
掲載:common.h(該当箇所)
/* common.h */
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#endif
/* =========================================================
ANSIカラー(対応していない端末ではそのまま文字列になります)
========================================================= */
#define RESET "\x1b[0m"
#define RED "\x1b[31m"
#define GREEN "\x1b[32m"
#define YELLOW "\x1b[33m"
#define BLUE "\x1b[34m"
#define MAGENTA "\x1b[35m"
#define CYAN "\x1b[36m"
#define WHITE "\x1b[37m"
#endifここで出てくる命令・要素の解説
| 要素 | 何をしている? | ポイント |
|---|---|---|
| #ifdef _WIN32 | Windows環境のときだけ中を有効にする | Visual Studio では基本 _WIN32 が定義されます |
| #include <windows.h> | Beep などWindows APIの宣言を使えるようにする | Beep を呼ぶなら必要 |
| #define RED "\x1b[31m" | 文字列マクロの定義 | printfに混ぜて色を付ける |
ANSIカラーの使い方(例)
printf(RED "赤い文字\n" RESET); のように、色の開始コード→文字→RESET の順に出します。
platform.h:外に見せるのは2関数だけ
platform層の関数は、他のモジュールから呼ばれるので platform.h で宣言します。
掲載:platform.h
/* platform.h */
#ifndef PLATFORM_H
#define PLATFORM_H
#include "common.h"
void clear_screen(void);
void sfx_beep(int kind);
#endif関数プロトタイプ(宣言)の意味
| 宣言 | 意味 |
|---|---|
| void clear_screen(void); | 引数なしで画面を消す処理 |
| void sfx_beep(int kind); | kind(効果音タイプ)に応じてビープを鳴らす |
※ void を引数に書くのは「引数を取らない」を明示したいときに使います(C言語の書き方として丁寧)。
platform.c:画面クリアと効果音を実装する
ここがSTEP02のメインです。
OS差分を #ifdef _WIN32 で吸収します。
掲載:platform.c
/* platform.c */
#include "platform.h"
void clear_screen(void) {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
void sfx_beep(int kind) {
#ifdef _WIN32
switch (kind) {
case 0: Beep(880, 60); break;
case 1: Beep(660, 60); break;
case 2: Beep(988, 60); break;
case 3: Beep(523, 80); Beep(659, 80); Beep(784, 120); break;
default: Beep(200, 120); break;
}
#else
(void)kind;
printf("\a");
fflush(stdout);
#endif
}clear_screen のロジック解説
system がやっていること
system("cls") は、OSのコマンドを“外部コマンドとして実行する”関数です。
| 命令 | 何をする? |
|---|---|
| system("cls") | Windowsの画面クリアコマンド cls を実行 |
| system("clear") | Linux/Macの画面クリアコマンド clear を実行 |
注意点(設計の考え方)
system は便利ですが、外部コマンド実行なので「本格的なゲーム」では避けたくなることもあります。
でもこの教材の目的は 仕組みを理解しながら作れることなので、まずはこれでOKです。
sfx_beep のロジック解説
kind で効果音パターンを切り替える
kind は「何の効果音か」を表す番号です(ゲーム側から種類を指定して鳴らす)。
| kind | 意味(想定) | Windows側の音 |
|---|---|---|
| 0 | 決定 | Beep(880,60) |
| 1 | 攻撃 | Beep(660,60) |
| 2 | 回復 | Beep(988,60) |
| 3 | 勝利 | 3回鳴らしてそれっぽく |
| その他 | 警告など | 低い音 |
switch の意味
switch (kind) は、if (kind == 0) ... else if ... を読みやすくした分岐です。
| 命令 | 何をする? |
|---|---|
| switch (kind) | kind の値で分岐 |
| case 0: | kind が0のとき |
| break; | switch を抜ける(これがないと次のcaseまで流れる) |
Beep(周波数, 時間)
Windowsの Beep(frequency, duration) はこういう意味です。
| 引数 | 意味 |
|---|---|
| frequency | 周波数(Hz) |
| duration | ミリ秒 |
Linux/Mac側の printf("\a") と fflush(stdout)
| 命令 | 何をする? |
|---|---|
| printf("\a"); | 端末ベル文字(BEL)を出す |
| fflush(stdout); | すぐ表示(出力バッファを吐き出す) |
(void)kind; は「kind未使用の警告を消す」ための書き方です。
Linux/Mac側では kind を使わないので、コンパイラが “未使用変数” 警告を出すのを防いでいます。
platform層を導入すると何が嬉しい?
ここが一番大事なところです。
| もしplatform層が無いと… | platform層があると… |
|---|---|
| battle.c や ui.c の中に #ifdef _WIN32 が散らばる | OS差分は platform.c に集中する |
| あちこちで Beep や system を直接呼び始める | 呼び出しは clear_screen / sfx_beep に統一 |
| 改修が面倒(修正漏れが起きやすい) | 直す場所がplatform.cだけで済む |
つまり 見通しが良くなって、保守がラクになるってわけです。
次のSTEPへのつながり(STEP03の予告)
次の STEP03 では input 層として、
- 行入力 read_line
- 安全な整数入力 read_int_safely
を切り出して、battle/map/ui から「入力まわりの共通処理」を消していきます。
