drunken monkeys |
|
Demon monkey fighter
craig donner’s struggle for collision detection
game concept
In all truth, our original
design for dmf was rather vaporous and vague, but we intended to create a
humorous parody on first-person-shooters like quake and doom, with stunningly
appealing graphics that would blow away the competition.
The core of the game was to be centered on combat between monkeys using
wacky weapons, all while running across a terrain or climbing jungle trees.
Additional (unnecessary but planned) features were tribe (team) play
and capture the flag.
We did not actually name the game until the end of the third
week of implementation. Even then, the
game was in Japanese (onizaru, which
roughly translates to devil-monkey), to which Yoway appended “fighter,” giving
our game the English acronym dmf. Actually, we started with “drunken monkey
bomber,” then moved to “fighter.” The
“d” started as “drunken,” then moved to “devil,” and finally transmogrified to
the rolls-off-the-tongue “demon.” Of
course, the whole time we’ve just called it “dmf.”
In the course of implementing
dmf, we tried to make as few compromises as we could on our basic design. We stayed with the first-person-shooter
concept, with the simple goal of killing as many of your fellow players as
possible. Providing a unique twist to
the game, our demonic monkey models and wacky power-ups clinched the comedic
theme that gave the game personality.
There were, however, inevitable
concessions. Although we provided dmf
with a realistic terrain, and even put in some trees at the last minute,
without true collision detection, the monkeys couldn’t climb the trees. We also quickly dropped the idea of shaking
the trees when a bomb explodes nearby.
The lack of true collision detection, however, provided the monkeys with
another mode of movement, namely flying.
Although we didn’t have time to add the jetpack model, flying monkeys
added an entire new dimension to the game, as well as more comedy.
With regard to
implementation, our initial design was to have multiple independent modules,
such as graphics, sound, network, physics, and input. Although sound, physics, and input started and remained separate,
distinct modules, the graphics and network quickly became amorphous blobs of
unbelievable hacks and messy code.
There remained a few
memory management issues between threads that caused random unexpected
crashes. These mostly revolved around
the Input menu, which was strategically not shown at the demo. For the most part, however, each member (or
often pairs of members) could work on a certain module without breaking the
overall game.
Initially, we did not
decide on how do divide the workload of the game; we finally settled on a
client-server model rather than a peer-to-peer model for simplicity’s
sake. The client is essentially a dumb
rendering terminal, sending all actions of the user to the server. The server itself controls the entire game
state, taking data from all users, updating the current game state, and then
sending it back to the clients.
In implementing our
program, there were several pieces that were harder than we expected them to
be. Gladly there were a couple things that turned out to be easier than we expected
as well:
n
Collision detection:
This was the bane of Craig’s existence. For the life of him he couldn’t get
collision detection to work correctly. We would always slowly slip through the
ground.
n
3-D Sound: This turned
out to be a lot trickier than we expected. The DirectAudio library leaves a lot
to be desired in terms of automatically allocating sound buffers. But
eventually we wrote our own sound buffer management system to take care of
this. I was very surprised that there was nothing
in the documentation or the sample code about handling multiple 3-D sound
buffers.
n
Networking: This was a
lot easier than we initially thought. After pouring through all kinds of nasty
Microsoft documentation about the API, we finally just used their example code.
The main problem with Microsoft code, is that it generally works, but they try
to hide why it works under mounds of useless code. Once we had the code
running, we just added our custom messages and let it do its thing.
n
Particle Systems: This
turned out to be incredibly simple given how great it looks on screen. The
entire particle system code is a couple hundred lines of code. Once it was in,
adding particles was a breeze.
n
Character Animation: We
initially thought we would do animation as it is done in Quake-style games,
namely having a separate display list for each frame of animation. To ease the creation of animation frames and
to increase the smoothness of the animation itself, we instead used Milkshape
for skeletal animation. We then loaded
the model files directly into the game and rendered interpolated frames off the
keyframes created in Milkshape. Once
some of the bugs in Milkshape were worked out, doing the animation was actually
easy. To modify the rendering code to
only play specific ranges of keyframes took a bit more work, but was not
terribly time consuming.
n
Trees: We spent a lot
of time trying to figure out how we were going to do trees. Eventually we
settled for some trees that we ripped off from a Nvidia demo, though we don’t
collide with them.
n
Terrain creation: The
terrain went from a blue square to a valley of multicolored polygons, and
finally became a heightmap. We chose a
heightmap because it allowed us to simply create rolling terrains with only a bitmap. The triangles that the game engine actually
rendered were created by using the values of the heightmap as vertices.
n
The Z-Rotation Hack:
One thing we were worried about was how to send player model states such as
which animation to play at a given time, and how other players know if the
player is visible, invulnerable, fast, etc. It turns out that for each monkey
(actually for each entity) we send 6 numbers. The x,y, and z positions, and the
x, y and z rotations. The x and y rotations were used to move around the
player’s camera, but the Z rotation was left unused. So we finally just put
flags into the Z rotation, as they were being ignored anyways. Not quite what
it was envisioned initially, but it worked great J.
Even from the very start, we were unable to fully keep up with
the schedule we created. During the
first few weeks, the graphics, networks, input, and user interface were always
able to keep up with the schedule and at times were able to go beyond the
schedule especially in the graphics department. The graphics, led by Craig, left everyone in the dust since he
managed to complete 2 weeks worth of work for each week of the first 2 weeks. Text messaging was actually done in the 3rd
week as opposed to the 5th since it was useful to test how well the
network and graphics integrated.
However, physics and art lagged seriously since physics lacked a context
in the game for much to be done and everyone was to busy work on the art.
As week 4 came about,
Yoway and Sunny were transferred over to the art department to compensate for
the lack of work that was being done in that department. Physics, by then was decided to be a
stripped down version than what was anticipated earlier since as the game
developed we realized that not much was being done in terms of physics. The pace the graphics had taken in the
earlier weeks had slowed down considerably by the question of how to create the
world structure. In the game specs, the
trees were to be an integral part on the gameplay, but the question of how to
do the actual collision with the tree became an enigma that elluded the
group. Refusing to be bogged down by
this, Craig rushed forward in his usual gusto to include lens glares and a moving
sky that cast shadows on the ground, features that weren’t even on the original
specs.
Since art was started only
at the beginning of the 4th week, everything for the 5th
week that was related with integration between the various departments and art
was delayed. Rotation however, was
completed by John by displaying a set of axes for each of the clients. Player location was also represented by the
axes, and players were able to transmit location updates to the server which it
would then broadcast it back to everyone else.
(This is the first time we first saw actual interactivity with the
players so some of us had the strange idea that we should redo our whole game
concept from monkey fighter to axes fighter)
Also, the world management was completed by John and Kuowen, which would
then be the basis how the server managed entities and how it would transfer
information to the client. Monkey sense
and grappling hooks were however given up on due to the fact that at this point
there was no collision with the the entities and the world (nothing to hook
onto) and that monkey sense would be too much work for too little gain.
With the discovery of the Milkshape loading files, we were able
to start integrating the weapon and monkey models Sunny and Yoway made so
painstakingly from that flawed program.
Rockets matured quickly from 2D bricks to 3D bricks to actual
bananas. The first tree models were
also generated by dumping the data from Nvidia's tree demo. Player death was triggered upon collision
with a banana rocket and afterwards, the player was subsequently respawned at
the origin. (For those who were
wondering why we chose to have "ewarped" as part of the kill message,
the reason was that the moment a player was killed, he was "warped" back
to the origin. The "e" that
prefixed the word came from a non-sensical Kuowen-esque variable,
"eborked", which became our rallying cry as the weeks dragged by.) Zoom mode, was introduced by John so that he
can now snipe at everyone, while safely hidden behind the sun. Name billboarding was also done to do
character differentiation ( and also to make everyone obvious targets for
John's trigger-happy monkeys.) By this
time, of course John became the person that was coordinating all the efforts in
integration since he was the only one that was familiar with everyone else's
code (since he had helped all of us with our code at one point or
another). Craig also began changing
the whole world (yet again) and added multitexturing, a new welcome screen, and
procedural textures. The world ended up
looking much more detailed since now you are able to actually distinguish one
pebble on the ground from another. We
gave up on the ideas on most of week 7's advanced features since we didn't even
have a basic game sequence at this point.
Since we had the
basic structure of the game up, we now can begin implementing some of the more
complex stages of the game sequence.
John added randomized monkey colors, and Sunny allowed for input in the
menu to change the colors through that.
Kuowen then adjusted the input so that multiple changes can be
registered with one press of the keyboard.
An end-game state was finally introduced so that once a set number of
kills has been reached, a message pops up showing the number of kills each
person has inflicted. John added
explosions and rocket trails to each of the rockets to make them look more
realistic. (A trio of bananas flying
towards you without some type of trail just doesn't manage to strike fear into
the hearts of the players) Railguns and
a prelimary coconut bomb were put in to add for more diversity in game play.
The ideas of the
"power-up coming down in parachutes" was introduced from the last
meeting with Professor Voelker due to the ease of implementing them, so we went
right to work with that. The original
idea was for power ups to come from at random points and getting stuck in trees
(provided collision detection worked) so that players will be forced to go into
the trees to collect powerups and also so that John will have to come down back
to the playing arena once in awhile to collect more ammo. Sunny and Yoway contributed to the art for
the powerups and John added the necessary code in the server and client modules
for the power ups to exist. With power
ups, you need some type of count for ammo, so an ammo count was displayed on
the HUD. Before this point, the
collision Craig introduced was still buggy at some areas so his collision
detection was never put into the group workspace (he had his own workspace to
experiment on his own). Instead of
having monkeys slip underneath the ground, a height map collision detection was
provided by John so that the monkeys will appear to walk on land. Monkey animations were also integrated so
that the monkeys animations will match its actions. The integration between sounds and player actions began this week
since we finally had a computer in the lab with a sound card. The Blizzard sound raid Craig, Kuowen, and
Yoway took proved to be very worthwhile as the sounds were just spetacular in
accurately depicting the actions.
We did a huge amount
of work the night and morning before the game demo. We added two more powerups, the Voelker portrait, and the
Wheaties cereal box, which added a whole new dimension to the game play. (Of course when this was introduced,
"Bob", aka John, began monopolizing these new powerups and prevented
anyone from ever killing him again.)
John introduced the "Akira" explosion such that when a rail
trail hit a rail ammo canister, an explosion would engulf the whole playing
area. More background music was added
and we now had interactivity in the "Audio" menu thanks to Kuowen,
John, and Yoway. Correct weapon
animations were also introduced and the weapons now correctly corresponds to
the current action from the player.
Our approach to designing
DMF involved a combination of object oriented programming and package
reuse. Specifically, most modules of
DMF were implemented in some sort of class.
This hid most of the DirectX-specific implementation details from the
other modules, effectively providing a simplified interface for each module to
be accessed by other modules and the entire game engine. There are exceptions however, such as
graphics and world management where global variables become an asset because
they simplify access to data and also provide a small performance boost over
more structured programming.
We ended up using a whole
slew of third-party packages and libraries.
The most significant component of DMF is the graphics engine, which was
written entirely in OpenGL. Using
OpenGL proved to be very helpful in abstracting hardware specifics from the
programmers, and in making graphics generation easier in general because of all
the pre-written functions for performing common graphical actions.
Another reason that we
decided to go with OpenGL is that two of our programmers are quite proficient
in it, specifically, Craig Donner, who designed the “Kokoro Graphics” engine
using a combination of pre-written code and original code.
The lens flare effect was
created by Craig form an online tutorial.
The particle system was written from scratch by John. The textures for the particle system were
stolen. The text library and the 3D
text functions were also stolen. The
procedural textures were derived from the Xterminate Terrain Engine. Height mapping was derived from the OO
engine.
Models were created in
Milkshape 1.5.5, and were loaded using code provided by tutorials on NeHe. Targa texture loaders were stolen. The models for the trees were created by
modifying a tree creation program from Nvidia.
All other aspects of the
graphics engine were written originally by Craig after hours of poring over
papers on the different aspects of graphics engine design, including frustum
culling and the ultimately-not-implemented-but-it-would-have-been-cool octree.
The networking module,
created by Sunny Chow and John Rapp, involved modifying the DirectPlay sample
“simpleclientserver.cpp”. The
DirectPlay API proved to be quite complicated, so this sample code was a
lifesaver.
The input module, created
by Kuowen Lo, also involved using the DirectInput sample code.
The sound module, however,
was not quite as straightforward, because the sample code in the DirectX
documentation was extremely limited in that it did not provide any samples of
positioning multiple sounds in three-dimensional space. So, Yoway Buorn had to write a wrapper class
entirely from scratch using the absurdly complicated DirectSound API. The sample code did, however, provide some
insight into how the wrapper class should be written.
The sound module also
involved implementation of an MP3 player.
The MP3 player class is a wrapper class for DirectShow, provided by some
guy who had some program called Step8.
The wrapper class made playing MP3s very simple, and we did not have to modify
it at all. We simply called the
functions to initialize the MP3 player, then loaded the MP3s and then exposed
the MP3 player interface inside CmonkeyAudio.
Specific to our
implementation in C++, templates were very useful in giving us quick access to
advanced data structures like stacks and lists.
Although very rough at the
start, the use of WinCVS proved to be very helpful in maintaining an always
functioning code base.
The majority of team
communication took place over e-mail and through the use of our website. The DMF website features status report forms
on each aspect of the game design. Each
week, when a team member completed a certain amount of work, he would enter a
status report which would automatically be e-mailed to the rest of the team
members. Anything not related to
development status was just sent over e-mail.
For the most part, the
team moved quite fluidly. On the
not-so-often occasion that someone slipped up, we would place the team member
in question on the stocks, and place him in the middle of Price Center, and
humiliate him in front of millions of his fellow students. This proved quite effective at the most
critical times.
John Rapp proved to be
very useful at times of total confusion.
His ability to increment numbers in VIM using CTRL-A and CTRL-X also
proved a godsend. One particular
occasion stands out. As Yoway was
trying to load syntax highlighting into VIM, he encountered difficulties with
carriage returns not converting correctly when transferred. Luckily, John was there to get Yoway back on
his feet. The game would not have
compiled if it was filled with ^M’s.
Overall, the most
important factor in the development process was individual participation. Several times a week, all of us would come
together at the OSTL lab, and stay there until the wee hours of the day working
on various things. If at any time,
someone was left idle, some task would be found to keep that person busy. If anybody was unable to make it, someone
would be available to take on his tasks.
Milkshape 3.5.5. This program sucks.
DirectSound. This interface sucks.
WinCVS. Sometimes this program sucks.
Craig sued Yoway for two
million dollars.
Given the opportunity to
start this project over from scratch, we would have hidden Kuowen’s stash of
Red Bull from him, so that he would get some sleep and be able to come into lab
with a clean, non-ripped shirt.
We also would have devoted
more time to working out the gameplay and game cycle. It turned our that the last few days, which we spent on creating
power-ups, were the most valuable days throughout the ten week period. The addition of power-ups contributed
greatly to gameplay.
Although we were using
WinCVS to maintain an always-runnable code base, we still had problems with not
keeping logs and with leaving bad code in the repository.
Although the program ran
pretty well most of the time, random crashes would occur because of memory
allocation problems. If we could go
back, we would have implemented mutual exclusion to take care of this.
On the graphics side, we
would have included environmental elements such as rain, falling leaves, wind,
a moving sun, and a variable time of day.
On the audio side, we
actually had an enormous library of really nice sounds. However, we ended up using less than half of
the available sounds. This would have
involved making the game more event driven so that the exact time a sound needed
to be played would have been known.
This also would have involved implementation of certain features that we
did not have time to implement such as the shotgun and the environmental
elements.
course feedback
The Windows API book was
helpful. Writing Solid Code was funny.
Especially the subtitle: “Microsoft’s Secrets to Writing Bug-Free C
Code.” That was really funny. That book probably would have been useful,
but we’re already the best programmers in the world so no problem there.
The order of the day is
graphics. If you do not have a graphics
expert, you will suck. Preferably, you
want someone who has taken MAE 293. You
also want everyone in the group to have some sort of graphics background, even
if that means concurrent enrollment in CSE 167.
One suggestion that stands
out came from Sunny. He suggested that
the class get together and throw a kegger every week, so that students can get
to know each other and provide help to each other on various aspects of game
development, and maybe even get drunk and talk about flying monkeys.
Teaching Assistants who
have taken the advanced graphics course should be available.
All the software provided
was very useful. The MSDN library on
CD’s would have also been helpful. It
would also help to provide a database of links and resources available for the
class. All the models and software that
we used proved to be extremely helpful.
Especially Milkshape, with which we created most of our models.
We also suggest that
professor Voelker start his own warez site.
Specifically, the site should have copies of Lightwave, Photoshop, 3DS
Max, Bryce 3D, SoundForge, CoolEdit, and 3D Exploration. Of course, there is always the option of
purchasing licenses. Maybe the school
could provide funding for all of this.
No, wait, then the Dean will want to be in the intro video.