Gem Rally

Abstract
Game Title:Gem Rally
Development Team Members:Kevin Costello, Frank Palermo
Game Genre:Arcade-Style Racing/Driving
Brief Description:To master this arcade-style game, you'll need to race against the clock to collect colorful gems strewn about a large 3D world. Just don't expect to stay on the ground for long, and be sure to watch out for those vicious automated police cars!
Overview
Game Story / Objective: The objective in our game is to drive around the world of each level, collecting as many gems as possible within the allotted time and avoiding enemy cars to the greatest extent possible. Points are awarded for each gem collected (in varying amounts based on the gem's color/rarity).
Game Mechanics + Controls: During gameplay, the enemy cars will attempt to push the player's car off course, into water/lava/etc. hazards, and otherwise frustrate the player's pursuit of gems. If the player is nonetheless able to collect a sufficient number of gems to surpass a pre-defined minimum score for a level, that level is considered beaten. (It is not necessary to collect all gems in order to beat a level, but the exact value of the minimum score is not disclosed to the player).

Once a level is beaten, the player may either attempt to play the level to completion (by collecting every gem in the level during the remaining time), or immediately skip to exploration of the next level via a "level advance" key.

Controls:
  • LEFT/RIGHT - Steering.
  • UP/DOWN - Accel./Brake.
  • B - Turbo Boost (Provides both a quick burst of speed and the vertical lift necessary for jumping the car over obstacles. A mandatory "cooldown period" limits the frequency of its use).
  • A - Level Advance (Proceeds directly to the next level if the minimum score has been met. If the minimum score has not been met, briefly flashes "Not Yet!" on the screen).
  • S - Take Screenshot (Saves a screenshot to the file "screenshot.bmp" in the game folder.
  • SPACE - Pause/Unpause Game
  • ESC - Quit Game
Technology: Physics simulation and collision detection for our game were provided by the Open Dynamics Engine ("ODE"). Sound playback and mixing were provided by SDL_mixer. For further technical information, please see the "CODE" section below.
Aesthetics:Aesthetic choices for this game were intended to create a whimsical or "cartoon-like" feel. Sound effects were deliberately absurd (e.g. a metallic spring snapping for car collisions); physics behaviors were deliberately exaggerated (e.g. cars bouncing off of each other like billiard balls). The level designs take advantage of the intentionally unrealistic physics to extend gameplay off of the ground plane (occasionally to the extent that the game more closely resembles a platformer than a driving game).
Media
Screenshots: The following screenshots provide a rough timeline of our game's development:
(Optional) Download:[Not available at this time.]
Development Summary
CODE: Code for our game is organized in the 'include', 'lib', and 'src' subfolders. Our game's code is based on an extension of the engine provided for Lab 2 and follows much the same organization. In addition to modifying the classes provided by the Lab 2 starter code, the following new classes were created:
  • IEngineCar - Similar to IEngineCharacter, but lacks support for MD2 animations (which were not present in the car models we chose and were thus ignored to improve performance). Car AI, car control/physics, camera control, and various sound triggers are also included here.
  • IEngineGem - Similar in concept to the IEnginePrimitive class, but tailored to support our gameplay by storing scoring information, an enabled/disabled state for each gem, etc.
  • IEngineSkybox - An implementation of a skybox class for the engine.
  • IEngineTerrain - Responsible for loading and rendering the world for each level, including both terrain and features such as buildings and bridges.
Code in main.cpp is responsible for loading level data from XML, running the main game loop, and implementing the logic which determines whether each level has been beaten and controls advance to the next level.

The Makefile/build system is designed to function on both Linux x86 and Mac OS X for Intel, provided that the necessary SDL and SDL_mixer libraries are available. In addition to these, the following third-party libraries are bundled with the project and linked directly into the game executable:

Third-Party Code Used
  • GLFT_Font - Library for rendering TrueType fonts using OpenGL; used under a BSD-style license.
  • Open Dynamics Engine - Library for physics and collision detection; used under a BSD-style license.
  • TinyXML - Library for parsing XML files; used under a zlib/libpng license.
Original Code Written

Apart from these libraries and the 15-466 Lab 2 "starter code", all code included in the project was written "from scratch". In particular, no high-level libraries specifically intended to aid game development were employed.
CONTENT: Content for our game is organized in the 'fonts', 'levels', 'models', 'sounds', and 'textures' subfolders.

Third-Party Content Used
  • fonts - "Silkscreen" font; used under the Open Font License.
  • models - "car.md2" (from "Model Pack 3") and "policecar.md2" (from "Model Pack 7"), both from http://www.md2.sitters-electronics.nl/; used under Creative Commons license.
  • sounds - "Fire2" by "pushtobreak", "knock_1" by "farbin", "SplashEdit" by "duckboy80", "fire2" by "tc630", and "bus_movement_1" by "the_bloke33"; all from The Freesound Project, all used under the Creative Commons Sampling Plus 1.0 license. Edison 4069 "Beautiful Hawaii" (1920) by the Waikiki Hawaiian Orchestra; provided by the University of California, Santa Barbara Library and used under Public Domain.
  • textures - "Arctic" from "Skybox Texture Pack 1" and "Sahara" from "Skybox Texture Pack 2" by Hazel Whorley; used under the Creative Commons Attribution-Noncommercial 3.0 License
Original Content Created

Apart from the content listed above, all content included in the project was created "from scratch", including (but not limited to):
  • levels - All level description XML and BMP files are original.
  • sounds - The "glockenspiel" and "spring" sound effects are original. The theme music used in Levels 1-2 & 4 is based on a previous composition by Frank Palermo.
  • textures - Various material textures including the city buildings, road textures, etc. were created by Kevin Costello.
Reflections
Three Greatest Challenges: Car Controls:

One challenge was to get the controls working with ODE. Although at first we tried to actually make the car consist of a chassis and rotating wheels, this proved to be too difficult to implement. We settled on just a rectangular box that had forces and torques applied to it manually. Accelerating and decelerating just applies a force in the direction the car is facing. Steering just applies a torque to spin the car. Although unrealistic, the car is able to spin around without moving. This was easier to implement, and makes it easier to navigate the worlds.

Because the car was just a rectangle in ODE, we had a difficult time making friction work in a sensible way. In the end, we separated that logic from ODE and manually added frictional forces and torques in the IEngineCar Update function. To simulate the fact that the car was actually on wheels, the "sideways" frictional force was made much stronger than the friction in the direction the car was moving. The exact relationship between our frictional forces and the car's current velocity and direction was developed experimentally. In the end we decided on a sideways force proportional to the velocity, and a backwards force proportional to the velocity squared, with suitable constants. The result was fun to play, and just realistic enough to be functional, but still fits with the overall cartoony/arcade theme of the game.

Level Loader:

Our goal was to make levels easy to create, but still interesting enough to make cool worlds to explore. We decided to make the worlds grid-based, with each square being around 2 car-lengths long. We created several different types of geometry for these tiles, including buildings of various heights, two types of ramps, bridges, and "ceilings" that could be used to make interior levels. This was separated from the ground type. The ground could be one of several textures (road, grass, sand, etc...) or could be a hazard such as lava or water. Separating this from the geometry allowed us a lot more flexibility with regards to what type of terrain is under bridges/ramps or inside buildings. (Otherwise, we would have had to have separate tile types for "bridge over water", "bridge over grass", "bridge over road", etc...)

The levels are actually loaded from two separate bitmaps. One specifies the underlying terrain type, and the other describes the overlaying geometry. These bitmaps can be easily made in any image editing program. The different tile types are specified by the colors of the pixels.

Enemy AI:

At a coarse level, the AI uses a simple A* pathfinding algorithm to navigate the world and locate the player car. Once the enemy gets near the car, it also tries to steer directly towards the player. In order to allow the enemies a fighting chance at catching the player, they had to be given much better turning rates. They also needed special routines to check if they had gotten stuck in a wall, at which point they back up and continue their search for the player. Further more, the AI was allowed to "cheat" by moving really really fast while far away from the player. Once the enemy gets close enough that the player would notice this abnormal speed, it slows down to only slightly faster than the player. Finally, once the enemy actually gets close enough to make contact, it slows down so its power is the same as the player's. This allows the enemies to quickly find the player, ram into them, but then not be so strong that the player is powerless against them. Once contact is made, the player can usually break free and regain control of the car. The result was actually pretty good, especially when there isn't a whole lot of water or lava for the enemies to fall into.

Camera Control (Honorable Mention):

Another challenge was to make the camera follow the player, but also not move inside walls. Although at first we thought about making the camera an ODE object and having it actually react to the level geometry, we ended up doing a much simpler fix instead that worked pretty well. We just specified two different camera positions, the normal "far" position being displaced back a few meters from the car, and the second "near" position being right up next to it. The "near" camera doesn't look as cool, but has the advantage of the camera always being in the same tile as the car, so it will never be obscured by buildings. A small piece of code just checks if the "far" camera will be located in a building tile, and if so, the camera shifts upwards to the "near" position. It's simple, but proved to be very effective.
Three things that went right: Level Look:

We were really happy with the way the look of the game turned out. It was really easy to just modify the tileset and materials textures to get different looking worlds. By changing only a few textures, we could get a city, a castle, a volcanic island range and an arctic world. Our favorite looking level was the city, whose textures were all made from scratch in The GIMP, and really had a good cartoonish feel to them.

Sounds:

The sound effects and music were only added in the final stages of development, but really added a lot to the feel of the game. Impacts felt a lot cooler when accompanied by crashes and thuds. Collecting a gem also results in a fun "ding" sound. Although subtle, it really makes the game more fun.

Physics:

Although the controls were difficult to implement, the end result of the ODE-integration was very good. Ramps, bridges, and water/lava all worked great. Turbo-boosting around levels and interacting with the environment is just a lot of fun.
Three things that went wrong: Enemy Theme/Variety:

We originally wanted to have different types of enemies to fit with the themes of the level. For example, we really wanted to have a pirate ship in the island level. However, we never got around to actually implementing this, and as a result we have police cars driving around castles and islands. It also would have been nice to have different AI behaviors, such as enemies that could fly or shoot bombs at the player.

Menu Screens:

We didn't really have time to implement a good menu interface. It would have been nice to have a level-select option as well as multiple game modes (free play vs timed run, for example) In our game, there isn't a menu, just a title screen that immediately dumps you into the game.

Texture Loading:

Right now the game's performance is limited by the texture mapping. This was mostly due to laziness. The tileset textures are enormous. It would have been much much better for performance and looks if we used smaller textures that were tiled. This is one of the biggest areas of the game that could be improved upon. Luckily, it wouldn't be too difficult to change this. It just had a low priority because the laptops we were using could run the game fine even with the atrocious texture sizes.
Other final thoughts: We wish we had come up with a title sooner so we didn't get listed as "untitled" on the voting ballot. But overall we were very happy with the way the game turned out. We achieved most of our original goals and ended up with a game that was very fun to play.