メインコンテンツへスキップ

【旧課程】cub3dをCで自作する時のコツ

    【旧課程】cub3dをCで自作する時のコツ

    FDF・fractolに続くMiniLibX課題の集大成が「cub3d」です。名作FPS『Wolfenstein 3D』を生んだ「レイキャスティング(Ray-Casting)」というテクニックを使い、`.cub`ファイルに書かれた2Dの迷路マップを、プレイヤー視点の疑似3D映像としてリアルタイムに描画します。3Dモデルを一切使わず、1本1本の「光線(レイ)」を壁にぶつけて距離を測るだけで立体的な映像が生まれる、という発想の転換が面白い課題です。

    .cubファイルの構造とパース

    `.cub`ファイルには、4方向のテクスチャ画像パス・床と天井の色・マップ本体の4種類の情報が(順不同で、空行区切りで)書かれています。

    NO ./textures/north.xpm
    SO ./textures/south.xpm
    WE ./textures/west.xpm
    EA ./textures/east.xpm
    F 220,100,0
    C 225,30,0
    
    111111111111111111
    100000000000000001
    100000000110000001
    1000000000000000N1
    100000000000000001
    111111111111111111

    コツ: マップは要素の中で唯一「常にファイルの最後に置かれる」という制約があるので、パーサーは「テクスチャ・色の行を読みつつ、それ以外の行が来たらマップの開始とみなす」という流れで実装すると素直です。

    typedef struct s_map
    {
        char    **grid;
        int     width;
        int     height;
        double  player_x;
        double  player_y;
        double  dir_x;
        double  dir_y;
    }   t_map;
    
    int check_walls_closed(t_map *map)
    {
        int x;
        int y;
    
        y = -1;
        while (++y < map->height)
        {
            x = -1;
            while (++x < map->width)
            {
                if (is_floor(map, x, y) && is_open_around(map, x, y))
                    return (0);
            }
        }
        return (1);
    }

    コツ: 課題文で明記されている最重要ルールは「マップは壁で完全に閉じていなければならない」ことです。これを怠ると、レイキャスティングのループが壁に当たらないまま無限に走ってクラッシュします。判定は「床(`0`または`NSEW`)のマスの上下左右を見て、マップ範囲外やスペース文字に接していないか」を全マスについてチェックするだけです。スペース文字(` `)も「マップの内側だが壁ではない不定形の余白」として正しく扱えるようにしておく必要があります(矩形でない迷路も許容されるため)。

    プレイヤーの初期位置と向きは、マップ中の`N`/`S`/`E`/`W`の1文字から読み取ります。

     
     
    日経・NYT・WSJを読み比べる「今日の1トピック」、 気になった記事を掘り下げる「深堀り」を(目標)毎日更新。AI・テック多めです

    あなたへのおすすめ