Skip to content
第15回 CSVから作るステージ

1 / 4 CSVの値をStageCellへ変換する

このステップの目的

CSVファイル内に記述された整数値をスコープ付き列挙型 StageCell へ変換し、定義済みの値のみを安全に受け付ける設計を学びます。

生の整数値を直接比較しない設計

CSVファイルには、0, 0, 10, 10, 1 のようにカンマで区切られた数値が並んでいます。
プログラム側で if (cell == 10)if (cell == 1) のように数値を直接比較してしまうと、以下の問題が発生します。

  • 可読性の低下: 101 が何を表すのか、コードを読む側には判別が困難になります。
  • 誤入力の検知不可: 10 と書くべき箇所に誤って 1 と書いても、コンパイラは検知できません。
  • 不正値の混入: CSVに 999 などの存在しない数値が含まれた際、意図しない挙動を引き起こします。

用途ごとに値域を分けた StageCell の定義

これらの問題を解決するため、すべてのマップチップの種類を enum class StageCell : int として定義します。

StageCell.hcpp
namespace dxgame::platformer
{
    enum class StageCell : int
    {
        Empty       = 0,    // 空白(空間)

        // 1〜9: 進行・ゲームルール上の目印
        Goal        = 1,    // ゴール地点
        PlayerSpawn = 2,    // プレイヤーの出現位置

        // 10〜19: 通常の地形(ブロック・足場)
        Brick       = 10,   // レンガブロック
        Moss        = 11,   // コケ付きブロック

        // 20〜29: トラップ(危険物)
        Spike       = 20,   // 棘トラップ(第23回で使用)

        // 90〜99: 敵の出現配置
        EnemySpawn  = 90    // 敵の初期配置位置(第21回で使用)
    };
}

用途ごとに値域を分ける理由

列挙値を 0, 1, 2, 3... と詰めた連番にしてしまうと、後から新しい地形ブロックを追加した際に既存の番号がずれ、作成済みのCSVファイルを書き直す必要が生じます。
用途ごとに「10番台は通常地形」「20番台はトラップ」「90番台は敵」と値域をあらかじめ空けておくことで、既存のCSVデータとの互換性を保ちながら拡張できます。

検証関数 TryParseStageCell() の実装

C++では、単に static_cast<StageCell>(intValue) とするだけでは、列挙型に定義されていない不正な数値(例えば 37)も強制的に変換されてしまいます。
安全性を担保するため、定義されている列挙値のみを確実に受け付ける検証関数 TryParseStageCell() を用意します。

StageCell.cppcpp
bool TryParseStageCell(int value, StageCell& outCell)
{
    switch (value)
    {
    case static_cast<int>(StageCell::Empty):
    case static_cast<int>(StageCell::Goal):
    case static_cast<int>(StageCell::PlayerSpawn):
    case static_cast<int>(StageCell::Brick):
    case static_cast<int>(StageCell::Moss):
    case static_cast<int>(StageCell::Spike):
    case static_cast<int>(StageCell::EnemySpawn):
        outCell = static_cast<StageCell>(value);
        return true;

    default:
        // 未定義の数値は拒否して false を返す
        return false;
    }
}

この関数を通すことで、CSV内に未定義の数値が紛れ込んだ場合でも、プログラムの奥深くに不正なデータが入り込む前に検知できます。

チェックリスト
  • CSVの数値を直接比較せず、enum class StageCell を介して扱う理由を説明できる
  • 用途ごとに値域(0番台、10番台、20番台など)を空けておく設計意図を理解している
  • TryParseStageCell() によって、未定義の数値を安全に検出できる仕組みを説明できる

ゲームプログラミング実践