Doom levels make good use of both indoor and outdoor spaces. To support these outdoor spaces, I spent this evening adding support for skyboxes to my raycasting engine. After all, they are really just the same old indoor spaces with a ceiling that looks magically like the sky.
The obvious approach in 3D would be to use a cube map, however in 2.5D we can get away with something much more simple. Since the player cant look up or down, we can create an wide image strip that wraps around the player for the entire 360 degrees. As the player turns around we just have to figure out which part of the strip to show them.
To begin with I found a simple cube map online and began making a few modifications. For starters, I could dispense with the top and bottom segments leaving me just with the strip that can wrap around the player and secondly I tweaked the hue to give it a more hellish red colour. Lastly I scaled it to a more software friendly 512x128 pixels to be more cache friendly and also give it a more grungy doom look. I'm software rendering so my textures cant be too big.
My idea was simple, if we ever try to render a ceiling tile with an invalid texture index, we will instead jump to the skybox rendering code for the pixels covered by the tile. Since the skybox texture is drawn based only on the players direction, those invalid ceiling tiles will appear to be magic windows through to the sky, and it will look like they never even existed.
To map a screen column to a column in the skybox, I generate a direction vector from the camera origin to our column on the camera plane and using the atan2 function on the components we can use the result to index the skybox (after some slightly magic scaling and wrapping code).
Since the ray-casting engine renders to the screen in columns, it is more cache friendly to rotate the skybox by 90 degrees, so I can first find the row in the skybox texture for my column of pixels on the screen, and then simply march along the x axis in the texture as I walk along the y axis of the screen. This replaces a multiply in the loop with an add and keeps the entire skybox row in the cache while we need it. Simple.
Have a look at the skybox in action:
I spent a few minutes today on my lunch break doing some weapon mock-ups for my DOOM Challenge entry.
For some authentic visuals, I chose to video myself wielding a toy gun, before digitizing it and adjusting it to suit my needs. From what I gather this is fairly similar to how id did the weapons for DOOM.
I bought a really cheap little Nerf gun from a local supermarket to use as the basis for the games pistol, and below you can see a screen grab from one of the video frames. Three frames were taken overall, to give a nice range of motion for the weapon recoil when firing. Bringing the grabs into Gimp, the background was removed and the gun desaturated, to remove the toy blue and orange colours. The bitmaps were then down-sampled and palletized using the original DOOM palette.
Finally, this was thrown over a screen-shot to check it for visual fit. It looks pretty cool to me, so I'll add some muzzle flash, and try to integrate it into the game. Of course i'll need to throw on a good measure of weapon bob when your walking for that full doomy goodness.
When I saw this Challenge pop up, I had no choice but to pick up my dev tools and participate.
I have fond memories of booting up my fathers 486 pc, feeling the warm static of the CRT as it came to life, and hearing a little pop as speakers for the soundblaster16 card turn on. When the DOS prompt settled on the screen it was time to launch the shareware version of Doom!
This was such a powerful and emotive game for myself when I was a child, I wanted to dive into that world again and bring it to life once more for myself.
For my entry into this GameDev Challenge I will be programming the game in C++, from scratch using a ray-casting approach. I want to try and stick loosely to some of the constraints of the period to make things more of a challenge for myself. 320x240 resolution, software rendering, adlib music, etc.
At this I have spent around two weeks working a few hours each evening on the project when I can.
Currently the features I have implemented are:
- Raycasting engine with variable floor and ceiling heights
- Lightmapping for all surfaces
- Sliding collisions on all geometry
- Depth sorted/tested sprite rendering
- Perspective correct texture mapping for floors and ceiling
- Texture mip-mapping
- Depth fog/darkening
As place-holder artwork I am using some of the original doom textures and sprites, however they will soon be removed and replaced with handmade artwork in line with the competition rules.
Next tasks are:
- An entity system for all active objects
- Potential fields path finding for enemy AI
- Line of sight test for enemies
Will update soon...