|
Map Editor at work with Object palette.
|
Spinning cube menu (ooh! aah!)
|
Getting a special treasure prize
|
Getting hurt, finally
|
|
Game Concept and Goals
Underworld is a single-player, multi-level dungeon game with a third-person overhead perspective, where the player controls a character that journeys through levels and kills monsters in order to find game objective clues, money, and health/energy boosts. Clues guide the player to solving each level to get to the next level. Obtaining access to the next level is based on finding the elemental shard for that level, which requires killing monsters, including a boss, and gaining experience as you travel through the dungeon. The player is a mage that casts spells to do damage to monsters. There are a limited number of monster types that will attack and do damage to the player. Player death is possible, which places the player at the beginning of the current level with loss of all experience and gains since the beginning of that level.
|
Story
Luthin is a young boy being trained for battle in his village of Arimont. After losing his father in a battle with a distant village, Luthin decides that the life of fighting is not the way for him and he desires more peaceful means of living. Luthin’s grandfather, however, seeks the revenge of his own son’s death and insists that Luthin be the means for achieving this. The story begins as Luthin wanders in a different direction from his training field one morning and meets up with a strange old man that offers to help him solve his dilemma. The old man asks for a favor of Luthin first – that he bring him four elemental shards from a nearby dungeon.
Luthin reluctantly agrees, hoping that the old man can indeed help. The old man gives Luthin a staff with a strange, glowing orb on the end of it and tells him that he will be able to communication with him in the dungeon through the orb. As Luthin takes the staff, he is mysteriously transported into the dungeon and begins his adventure of finding the four elemental shards. As Luthin travels the dungeon he comes to realize that fighting is indeed necessary for survival, but he learns to do it in a way that draws upon his own special magical power for the aim of good and helps him become a powerful force in the fight for peace among his people.
|
Game Features (General and Technical)
-
Point-and-click interaction; left-click to move, right-click to cast current spell (toggling with F1, F2, F3)
-
Animated player and monster sprites
-
3D rendered dungeon, angled overhead camera
-
Transparencies for dynamic wall hiding
-
3 spells (fire, ice, heal) that can level up with damage dealt
-
Particle system for projectile spells, effects handling via data-driven spell state (i.e. monster hit by ice spell reads in the slowdown effect and processes it for the spell's duration)
-
Player that can level up with experience from kills
-
On-screen interface showing Level, HP, Energy, Experience, and Spells
-
Data-driven unit data, spell data, textures, and map loading
-
Player and monster pathfinding using A* search
-
Quadtree/Frustum culling
-
Map Editor - terrain, wall, unit, and object placement
-
Monsters - 6 with movement and attack animations
-
Storyline presented through introduction cinematic and in-game dialog
-
Two complete dungeon maps
-
Save/Load game feature accessible through menu interface
-
Collision detection for player and all monsters to avoid object, player, and other monsters
-
Player status display
-
Sprite rendering by y position (avoid weird overlap)
-
Monster AI – track and attack player, return home when health is low
-
Transport between levels through proximity to elemental shard
-
Treasure chests containing gold and status-boosting rings throughout dungeon
-
Elemental shards on each level – one at end of level for transport to next level, one at beginning of level to transport back to previous level
|
User controls – Game
|
Control
|
Action
|
|
Left Mouse Click
|
Move to clicked location (if in game), skip dialog screen (if dialog open), or skip cinematic screen (if cinematic open)
|
|
Right Mouse Click
|
Use current spell in set direction
|
|
F1,F2,F3
|
Select one of three spells
|
|
s
|
Toggle status screen
|
|
ESC
|
Go to menu (if in game), quit (if in menu), skip cinematic entirely (if in cinematic)
|
|
User controls – Map Editor
|
Control
|
Action
|
|
Left Mouse Click
|
Select tile from palette or place tile on map
|
|
F1,F2,F3,F4
|
Go to terrain, wall, unit, or object palette
|
|
Arrows
|
Scroll map
|
|
|
Code
Original source code developed for the game includes:
-
Character animation routines
-
All artificial intelligence routines
-
Save/load game routines
-
Collision detection algorithms
-
Map/Level Editor
-
User interface displays
-
Items and interactions with environment
Source code acquired and used from outside sources includes:
-
Modified GLFont (on-screen text output)
Source and content previously developed:
-
Homebuilt Vector class originally for lab 1, modified and improved through and past lab 2 (contains functionality for storing float x,y,z coordinates, performing dot and cross products, some mathematical and comparison operators)
-
Homebuilt rotator class originally for lab 1, modified slightly for lab 2 (contains camera rotation routines to rotate around a given axis or passing in float angles to rotate around the coordinate axes)
-
Homebuilt quadtree class originally for lab 2, modified
-
Homebuilt frustum class originally for lab 2, modified
|
Content
Original content developed for the game includes:
-
Story line, characters, and dialog
-
All game maps and data
-
Monster, Item, Ability databases
-
Interface, menus, dialog box interface
Content acquired and used from outside sources includes:
-
Textures from http://www.vb3d.com/Textures.html
-
Textures from http://www.grsites.com/textures/
-
Art for opening cinematic from http://www.highend3d.com
-
Dialog character portraits from http://www.planetnintendo.com/goldensun
-
Player and monster sprites from http://www.vgmuseum.com/rips/snes/
-
Music from http://www.vgmusic.com
|
|
Collision Detection
The issue with collision detection was dynamically determining whether a next move would put the player or monster in a spot already occupied by the player (if I am a monster), a monster, or an object such as a treasure chest or shard. AStarPathfinding handled avoiding dungeon walls, however, on the fine-grained movements, it was necessary to check if the next movement was possible, and if not, find an alternate move. The reason this was tricky is because all monsters and player can be moving at each game step, so it is necessary at each step to check the location of the player and each monster relative to all blocking items and other (possibly-moving) beings in the game. When the next move is not possible, a new move must be chosen that also does not conflict with another game object. A complication associated with selecting a next move is that if ALL colliding monsters choose the same next move, collisions can continue to happen and no solution may be found.
The solution was to do the check for collisions at each time step, using the monster attack range or a fixed object distance as an indicator of collision. If collision is detected, a check will be made at a spot a distance away from the goal position equal to the colliding monster’s attack range or fixed object distance in all of the four directions relative to the target spot (+/-X, +/-Y). If no available spot is found, no movement is made and a retry will happen on the next game pass.
The issues and tunable parameters here are:
-
Distance for detecting collision
-
Delta-position for target spot for finding a free spot
-
Making sure new target position is not in a game wall
-
Making sure new target position is not also a collision
-
Avoiding deadlocking of movement due to infinite collisions with no solution found
|
Sprites & 3D
For several reasons (we like sprites, it saves time that can be better spent making a game, they’re easier to get into the game due to availability and format, etc) we decided to have sprites interact with a 3D environment. One problem was that, with the overhead camera view, the sprites need to be tilted slightly to avoid looking like thing strips of paper. This made it difficult to get correct distances, locations, and hitboxes for sprites, because they tended to vary in size. This also caused some headaches in the sprite overlap coding, to ensure that sprites are rendered in the right order.
The sprites also couldn’t fill in their entire frames (i.e. a sprite’s image had 4 rows and 4 columns of frames for animation) since they change ‘size’ while walking or attacking, so there needed to be less of a chance that a spell would appear to miss a monster, but registering as a hit since the actual sprite image was a bit larger than the character within it.
|
|
What Went Right
-
We kept the game technically simple so that we could concentrate on providing a gameplay experience. I think we did a good job of scoping the project for the time we had available.
-
Reusing code, either from labs or previous projects, helped reduce development time.
-
Starting early on the project and continually working on it enabled us to have a working game by the first milestone, and to facilitate tweaks and controls.
What Went Wrong
-
Could have done a better job of documenting code as we went along. In-code comments were there, but a high-level overview of how things worked might have made things go smoother, either in the code or in a separate design document.
-
We did not give ourselves enough time to handle better collision detection and AI, and were scrambling to fill that in. We spent too much time on smaller aspects of the game itself that, while contributing to a better game, took up too much development time.
-
We did not make enough use of CVS, usually using it to make sure code was stored safely somewhere. This was not in itself as much of a problem, but we were often concurrently working on seemingly unrelated things that ended up overlapping, requiring a lot of time spent making sure we were both working on the latest code.
-
While also a ‘What Went Right’, code reuse in simultaneous projects (i.e. working on another game for another course that used the same music manager) often led to necessary changes across all projects. A change from a text file to an XML format requires hours of modifications to every project that uses the format (for consistency, and to also take advantage of better code). This also was juxtaposed with the concurrent development problem mentioned previously.
Lessons Learned
-
Provide a more detailed and specific initial design, listing a set of features that need to be there and a set of features that we’d like to see, and keep those features static unless a drastic event requires handling. This helps keep too much time from being spent on a particular feature, especially if it is not as important as the others. This also helps in avoiding an incomplete project.
-
Do not work concurrently unless planning on making heavy use of a version/source control program, or unless the features are truly orthogonal.
-
Be a fan of the game’s genre. Both of us are big fans of the RPG genre (with some hack-n-slash roots), and this helped us try to figure out what is fun, what interface information is necessary, and how to improve the gameplay and provide a fun experience.
|
|