【旧課程】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文字から読み取ります。