Player initialization converts the spawn symbol from the map (N/S/E/W) into a
world position and a raycasting-ready camera basis. This state is required
before the first rendered frame.
Camera basis setup
From spawn tile to raycasting vectors
The map stores only `N/S/E/W`. Startup converts that symbol into a centered world position, a
direction vector, and a perpendicular camera plane.
01
find_player(app, lines, map_start)
Runs during validation setup and locates the single spawn tile.
// tile found at (col, row)
player.x = col + 0.5
player.y = row + 0.5
player.orientation = tile_char
`+0.5` centers the player in the cell and avoids wall-boundary ambiguity.
02
init_player_vectors(app)
Converts orientation into `dir` and `plane`, which must stay perpendicular.
NorthN
dir
(0, -1)
plane
(+FOV_FACTOR, 0)
looks upward in map rows
SouthS
dir
(0, +1)
plane
(-FOV_FACTOR, 0)
looks downward in map rows
WestW
dir
(-1, 0)
plane
(0, -FOV_FACTOR)
looks toward lower x
EastE
dir
(+1, 0)
plane
(0, +FOV_FACTOR)
looks toward higher x
03camera basis visualization
North — dir(0, -1) plane(+FOV_FACTOR, 0)
✓
render loop can start
`player.x/y` are centered, `dir ⟂ plane`, and camera vectors are non-zero.
The spawn is found during validation setup with find_player(...).
When the spawn tile is found at (col, row), the player position is centered:
player.x = col +0.5;
player.y = row +0.5;
player.orientation = tile_char;
The +0.5 offset matters because movement and raycasting operate in continuous
world coordinates, not tile indexes. Starting in the center avoids immediate
boundary ambiguity.
The direction vector points where the player looks. The camera plane is
perpendicular to it and controls the horizontal field of view used by raycasting.