Falldown 3D (screenshots at bottom)
Alden Tai
CPE 471 Fall 2010
Zoe Wood
Project Description:
Falldown 3D is a fast-paced puzzle game based on
the TI calculator's 2D version of the game (link).
The point of the game is to navigate each level's maze and
descend to the next, while moving fast enough to avoid the death panel, which
is quickly speeding up.
Project Goal/Idea:
The goal of this project was to take something that was previously implemented in 2D and redo it in 3D, with proper game physics and controls as comfortable as the original.
Main Game Features:
- An easy-to-move ball that can bounce off walls and the floor!
- An infinite amount of randomly-generated levels with varying complexities and different textures!
- A visible death panel that speeds up through the course of the game!
- A keyboard menu interface with text, allowing you to (re)start the game, see the high
scores, and quit.
- A rotating camera that circles the game boards when not in gameplay, and snaps back to the game position when the game is resumed.
Keys:
w or Up Arrow - Move ball up
a or Left Arrow - Move ball left
s or Down Arrow - Move ball down
d or Right Arrow - Move ball right
Up/Down Arrow - Navigate menu
Enter - Select menu option
Specifics and Extra/Other Features:
- Ball Physics, Collision Detection, & Simple Shadow
- The ball has its own velocity vector, which is manipulated depending on
if it is falling or not, and if a key is pressed or not. Natrual friction occurs when no key is pressed, and the velocity vector is decreased by a factor until it reaches near 0. Having a velocity vector with constant acceleration allows my ball to appear to have realistic physics.
- Whenever the ball updates its velocity, it calls a member function of the MazeBoard class it's on and passes its future position. The member function checks where the ball will be, and returns different values depending on which walls it collided with. If the ball detects a collision, it will reflect the velocity in that direction, and the ball will rebound off the wall as expected. Similar calculations are used for when the ball falls through a hole and bounces.
Since the ball only navigates in a maze (2D), it is unnecessary to check every single wall of every single level, and a shortcut to collision detection is easy to use and appropriate (for a fast-paced game).
- The ball was sometimes hard to see when it was bouncing, so I added in an extremely simple shadow underneath it. The shadow is just a black, 2D circle drawn on the level beneath the ball.
- Maze Generation & Recycled MazeBoards
- To create random mazes, I used a modified Prim's Algorithm (for minimum spanning trees), treating each cell of the maze as a node, and walls (or the lack of a wall) as tree edges. Since Prim's Algorithm gives me a minimum spanning tree of the nodes, I can be confident that any cell has a path to every other cell (so there will be no completely enclosed boxes).
- The game actually only has four MazeBoards, even though there are an infinite amount of maze levels. When the ball completes a level, the MazeBoard that it was on will disappear using stipple (as described above), and then it will reset its maze pattern (if it is the "first" MazeBoard, then it will increase the number of columns and rows, so the next group of MazeBoards will be more complex). The MazeBoard will then reappear beneath the old ones with its new maze, and continue to move with the group.
- Camera Angle, Fake Transparency, & Rotating/Returning Camera
- Since there is only 1D navigation (on the X axis) in the 2D version, a fixed camera can be appropriate. However, in the 3D version, since the mazes and navigation are now in 2D, I needed to create a camera that would both allow the user to see where he or she is in the maze, and also see a preview of the future levels.
To do this, I needed to keep the camera slightly above and outside the maze, and somehow erase the level above the current one (or else it would clip most of the current level).
- I used glPolygonStipple() to simulate a dissolve effect for the disappearing level, and the same to make a new level reappear at the bottom. Polygon stipple is a very basic way to do transparency, which simply does not render certain pixels for a given object, based on a given stipple pattern. My disappearing and reappearing effect is produced by keeping an array of stipple patterns, each with an increasing frequency of 1's (thus each is more opaque than the last). When my disappear or appear functions are called, the Draw function for my MazeBoard will draw the board with a stipple applied, and over a few seconds will choose a more or less opaque (depending on if it's disappearing or appearing) pattern until it reaches complete opacity or complete transparency (invisible).
- The camera only needs to be in the fixed x and z directions when the game is actually being played (so the controls are still logical). However, when the game is not being played, I made the camera rotate around the current level and zoom slightly closer and further away. Resuming the game and resetting the rotation amount to the original position was way too choppy (it confused me when I resumed the game), so I made the camera visibly rotate back to the game position when it is resumed.
- Text & Fiddling with the Projection Matrix
- I used an API for rendering fonts in OpenGL called glFonts. It uses a program to create a small file with a given font which can be applied as an alpha-enabled texture in the actual OpenGL program. In the program, it maps each letter to its position in the texture and can display the correct letter. I modified the TextOut2 function in the API so that it is only for 2D text, and can be told to center or right-align the text.
- Actually displaying the text on the screen turned out to be quite difficult, for two reasons. The first is that I needed to juggle the projection matrix in my display() function so that it drew the MazeBoards and ball in perspective mode, but drew the text in orthographic mode (since I wanted text at the front of the screen). The second reason is that since the font textures used alpha, I needed to pay careful attention to the order that I drew the letters in.
References:
Note: I did not (need to) use tutorials for the physics engine, camera, or projection matrix.
Screenshots:
Main menu:
Playing the game:
Finishing a level:
Game over:
Paused game & level appearing at bottom: