48-Hour Contest 5: Article III
48-Hour Development Contest: Part II
[Published on GameCareerGuide.com March 19, 2008]
By Bryan DeGrendel
The University of Michigan hosts an annual game development challenge, in which small teams of students have just 48 hours to develop a video game. GameCareerGuide.com is running an exclusive five-part series written by the contestants about their experience making a game in just two days. In Part II, we hear about the second-place game, Better Know a District, a la The Colbert Report.
The University of Michigan hosts an annual game development challenge, in which small teams of students have just 48 hours to develop a video game. The event is run by the campus' game development club, Wolverine Soft.
Better Know A District
My team consisted of fellow University of Michigan students Alex Soule and Steve Dewitt. Alex and I programmed; Alex composed the music; and Steve created the graphics.
This year is my third year participating in the contest. The first contest was held only a few months after I started college. Even though I had been programming for several years, starting with Qbasic back in elementary school, I had little experience in game development. Several poor design choices, including writing the game in Java and Swing, led to an incomplete game that took last place.
My second year didn't go much better. Despite having taken a couple of programming courses and being pared with an excellent programmer and artist, none of us had much game development experience. We brainstormed an excellent idea, but got too caught up in learning how to use our framework, SDL. This game was largely incomplete, and so we took last place yet again.
This year, I was determined to do much better. A few days before the contest, I sat down and made a list of various lessons I learned from the previous contests. Noting several areas that had caused problems, I went through a list of permitted game frameworks. The library I found particularly suitable was ClanLib, a C++ cross platform toolkit that wraps around SDL, OpenGL, and various system libraries. It has an impressive list of features and is fairly well documented. I was able to set it up and create a few test programs before the contest, eliminating a source of serious time problems.
Friday
8:00 p.m. After an hour delay, the contest starts. The theme is "Honoring Stephen Colbert," a very narrow theme and a surprise considering the previous year's theme: "Fight." I meet with Steve, who informs me that Alex will show up later.
We brainstorm on some couches outside the main contest room. For an hour, we talk about various gameplay designs and decide to do an adaptation of a "catch the cat" Flash game called Chat Noir. The game is a turn-based strategy and puzzle game; the goal is to stop a cat from leaving the game board.
We decide to use Colbert's "Better Know a District" as our starting point. The segment features Colbert attempting to interview every member of Congress, one district at a time. The skit has appeared less frequently over time as members of congress have caught on to its satirical purpose. Our game has the player placing fans of The Colbert Report on a game board to box in members of Congress and force them to be interviewed.
We decide to create a level progression, with the goal of having one unique level per congressional district. Ideas that we implement include different AI algorithms and the number of directions that the AI can move. We talk about implementing power-ups -- special board squares that give a bonus to either the player or the AI -- but we end up cutting them due to their complexity.
9:30 p.m. ClanLib will be the framework. I work on creating the basic structure of the program while Steve creates artwork. My development environment of choice is the standard UNIX command line tools. Due to the hobbled nature of the Red Hat Enterprise Linux installations on University of Michigan's engineering desktops, I commandeer the monitor, mouse, keyboard, and power outlet of a desktop and work on my Ubuntu installation on my laptop.
Alex shows up and by a very fortunate coincidence also perfers Linux CLI tools. He has access to a Ubuntu server and works on it by forwarding an X server display.
Before the start of the 48 hours, I had set up an empty subversion repository on my web server to ease the sharing of code. Also, because I had worked with ClanLib before the contest, I had no problems creating the basic structure. Alex initially had some problems compiling and installing ClanLib, mostly due to ClanLib's poorly written configure script and extensive development package requirements.
We create the basic game structure, which remains largely unchanged through out the contest. Here's what we did, in pseudo-code:
10:30 p.m. I work on the first game state, a simple test state that displays a very crude game board. Using a simple picture editor, I quickly create crude placeholder art. I do not encounter any serious problems and create a simple map that responds to mouse clicks by filling in squares, a key part of the gameplay.
Saturday
12:00 a.m. Alex and Steve continue to create art. Meanwhile, I develop a very basic game AI, which checks each direction sequentially and attempts to move if a square is unblocked. Lastly, I write a game state that implements the main menu.
2:00 a.m. With a basic version of the game created, I turn my attention to the actual structure of the game. The basic game structure, as follows, was largely unchanged throughout development:
We encounter a couple of errors involving full screen mode. Until we had actual artwork to use, the program was set to use an 800x600 window. But once we had an idea of how large the art needed to be, we bumped this up to 1,024x768. Since my laptop's max resolution is 1,024x768, I modify the program to run in full screen mode, which I had intended to do from the beginning.
Bug number one: ClanLib segfaults when I quit. A back trace shows the program crashing when switching from full screen back to windowed. There are worse places to segfault, but I am able to quickly fix it by adding an explicit windowed mode statement before deinitializing ClanLib.
The second bug we encounter is far stranger. While in full screen mode under Alex's development computer, the bottom 100 or so pixels are cut off. We are unable to solve this problem, and instead compile for full screen on my laptop and for windowed mode on Alex's desktop.
While ClanLib can create user interface elements, our UI needs are limited to buttons. We decide to implement our own UI. Normally, I'm against duplicating code, but our quick progression and simple needs made this a safe choice. Our button implementation consists of an image and a set of coordinates that designate the bounds. The implementation is quite simple; the only real difficulty lies in getting the coordinates correct. Steve works on setting up button dimensions and their code to switch game states.
4:00 a.m. We finalize the game states and how they connect to each other:
I have a few issues getting all three new classes to work together as well as they did in TestState. However, I am able to resolve any issues before we break for the night.
Steve continues to work on the art and produces several cool backgrounds for MainMenuState, HelpState, and AboutState. Alex continues to work on various issues, including updating dimensions of placeholder art, fixing button dimensions, and replacing placeholder art with final art.
5:00 a.m. The project is in good shape, we agree to meet again at noon.
12:00 p.m. I modify RandomAI to move by randomly selecting a possible neighbor. The key part of the GameBoard is a function that returns a list of squares accessible within one move of a particular square or its neighbors. Later, I'll modify the behavior of GameBoard to randomly sort the list of neighbors before returning, rather than have the AI algorithms randomly pick.
2:00 p.m. The two largest outstanding issues are the lack of levels and the lack of competitive victim movement AI. Because the AI is much easier to implement and is necessary for a complete game, I decide to focus on it first. Considering the small size of the board and my experience implementing it, I chose to use a breadth-first search.
One half of the algorithm is to find a path to an edge square. I test this by moving the victim to the final square, and appears to work without any problems. The second half of the algorithm -- backtracing from a solution path to the victim's current position -- introduces a number of bugs that take quite some to time to fix.
The implementation of breadth-first search is inefficient. Every turn, it does a complete search of the game board, discarding any previous data. However, the small board and length of time between user actions easily covers any speed inefficiencies. Debugging the program on my T23 Thinkpad only causes a slight delay.
4:00 p.m. I finish writing the breadth-first search. We now have something that's playable and is a stone's throw away from being presentable. This is quite an accomplishment, and I'm confused by this strange sensation of being on track.
I start to tackle the largest unimplemented feature, the levels. Writing 435 levels (to match the number of members of congress) by hand is unreasonable, given our time frame. We decide to implement some type of map generation, and I work on cleaning up various classes in preparation.
Alex begins writing the hex board. The hex board is a bit of challenge. For square and octagonal boards, determining which square a mouse click resides on, and drawing the board are fairly easy. However, hexagons don't line up as neatly. Nonetheless, Alex is able to produce a working hexagon board quickly. The AI algorithms don't depend on any board characteristics, and they work immediately on the new board.
5:00 p.m. One interesting difference between the breadth-first and random AI algorithms is how they handle failure. Since the breadth-first algorithm is complete, the algorithm stops the moment there are no winnable paths. However, the random AI has no such foresight and will continue to execute until it is completely trapped and unable to perform any moves.
For consistency, we need to modify one of the algorithms to perform the same as the other. We decide to modify the breadth-first AI to act like the random AI when the game is no longer winnable. There are two reasons behind this decision. The more important one is that it is much easier to make the change to the breadth-first algorithm, and the changes are easily implemented in the game board states. The second reason is physiological. Each match can be roughly split into three stages, 1) building a barricade to try to funnel the victim, 2) building an enclosed area to capture the victim, and 3) trapping the victim until he has no moves left. We notice that the third stage -- even if irrelevant in the grand game since the victim will lose at any rate -- feels like a nice way to get revenge against the computer. It is a sort of falling action after the climax at the end of the second stage.
Next, I create the octagonal classes, state, and board. It's a fairly easy copy from the square board; the only real difference between them is how the victim can move. Nevertheless, I manage to accidentally introduce a bug. This simple bug becomes a challenge to remove, frequently manifesting in that the breadth-first search subtly picks less than optimal paths.
One key property of Chat Noir is how the boards generate, containing a random number of filled squares. I initially thought this "terrain generation" would be difficult to implement. But it's actually fairly simple.
Our generator takes three parameters: fill percentage, width limit, and height limit. The fill percentage is the percentage of the board to be filled by the generator; the width limit is how close a square needs to be to the x edge to be filled; and the height limit is how close a square needs to be to the y edge to be filled. The second two parameters have an unintended advantage. One strategy that players learn is to build a barrier toward the map's edges, which gives the player considerably more time to react to the movements of the victim.
Despite its simplicity, there are a few bugs with the map generator. The generator incorrectly applies the fill percentage, and the generator occasionally places a filled square over the victim. I fix the first bug late in development, but the second goes unnoticed until after the contest.
A majority of the artwork has been created and implemented. Alex and Steve turn much of their attention to play testing and polishing.
9:00 p.m. Alex leaves to see Cloverfield with some friends. A testament to our progress, all three of us could have easily left for an hour or two without serious repercussions or cutting back on sleep.
While Alex is gone, we work on the levels and develop a map definition format to ease our map creation process.
I start writing the map library, while Steve writes the levels. I create a new class named MapLibrary to handle map parsing and storing. It contains an array holding the unique information for every single map: map height and width, generator percentage, height and width limits, board type, AI type, and district name. I am able to get the basic structure and some parsing done, but I can't finish all data parsing that night.
11:00 p.m. Alex returns. WolverineSoft feeds us pizza for dinner.
There are a few places in the game were images of text were not usable, specifically in the MapState's next district name and stats. ClanLib offers two ways of rendering text, using a system font or to parse a very wide image consisting of each character in the font. Our current implementation uses the second method, with the font image being an example included with ClanLib. However, this font is of low quality, and we are unable to apply different sizes or colors to it during execution. I switched our font to use a system font, which do support font sizes and colors. However, I came across an interesting error message:
Congratulations! You just got assigned the task of implementing system fonts for clanSDL :-)
It's not what I want to see, but it's probably the funniest error message I've ever read.
Sunday
3:00 a.m. Progress is strong, so we break early and decide to return at 11.
11:00 a.m. Even with a full night's sleep, it takes me a few hours to finish the map parsing. Luckily, I don't encounter any difficult bugs in the map parsing, despite its complexity.
Next, I catch up and fix the incorrect fill percentage map generation bug.
4:00 p.m. Alex goes to a computer lab to compose music for the game. Despite the short time and lack of keyboard, he produces two good ambient sound pieces.
I add the music to the game, which goes smoothly, one minor bug aside. With the music working, I now add various sound effects that Steve and Alex have either created themselves or found. This also goes smoothly. I'm proud because every legal mouse click has audio feedback, which is in line with good UI development practices. Even though we didn't have any major problems with the audio, we didn't allocate nearly enough time to work on it. A simple bug in the library could have wrecked our progress.
With about an hour left, I check out a copy of the code onto an open Windows desktop. The ClanLib web site provides precompiled Visual C++ dependency libraries, and I'm able to produce a working, redistributable Windows port roughly 15 minutes before the deadline. The process is a bit complicated and time consuming, but I encounter only a single error involving release build. The final product is a debug build, which is less than optimal but sufficient for our purposes.
7:00 p.m. Packaging and uploading the final source appears to be a quick and easy task -- but it seems like everything goes wrong while uploading the Windows executable and source files to my university-hosted web site. Vital files are not included. There is a corrupted zip file. I exceed my disk quota. About a half hour past the deadline, I finally have everything uploaded.
The recommended guidelines state that each project should be demoed on two computers. We had access to two Linux and two Windows machines, and we run a copy on all four. All crises averted, we take turns watching over the game and checking out other games.
No matter how the judging goes, I'm quite happy with our program. It's an excellent idea, with strong implementation and polish. We were quite successful from a technical standpoint as well. Despite more than 120 subversion commits, there were less than a half dozen commits that had major bugs, such as segfaults, and a mere handful of conflicts. The program performed well even my older laptop, and had no memory leaks. This is quite an improvement over my previous two years!
A couple months ago, it took me a good eight hours to program a simple Tetris-clone in Java, despite the simplicity of the project: simple gameplay, minimal graphics, and a language that I understood quite well. I thought it would be unreasonable to expect to complete and polish a game that was three or four times more complex than Tetris in only 48 hours. Our basic game idea followed those same guidelines, selecting a game idea that we knew worked well and had a low level of complexity. I believe that played an important part in our success.
I learned quite a bit about the game just watching people play it. Having played the game extensively over the past 48 hours made me somewhat blind to various problems. In particular, I made a note of several places where the UI was unintuitive, ranging from users not knowing to click the screen after the win/loss message, to buttons not being clear enough, to the premises of the game not being clear. Level design, in particular, was an unfortunate weak point. A last minute tweak to the level progression (in an attempt to make the game more difficult, faster) nearly eliminated the hexagon levels. Additionally, many players remarked that they would have liked if the map types switched more frequently. As an overall testament to the game though, we frequently had more than four players wanting to play and received good remarks from the judges.
10:00 p.m. We win second place out of 14 completing teams! I had a lot of fun, and taking second place is a big redemption in my eyes from the previous two years.
Bryan DeGrendel is a junior at the University of Michigan and a member of the student game development group Wolverine Soft. His team's game took second place in the 48-Hour Game Development Contest.
Original Article on Gamecareerguide.com
[Published on GameCareerGuide.com March 19, 2008]
By Bryan DeGrendel
The University of Michigan hosts an annual game development challenge, in which small teams of students have just 48 hours to develop a video game. GameCareerGuide.com is running an exclusive five-part series written by the contestants about their experience making a game in just two days. In Part II, we hear about the second-place game, Better Know a District, a la The Colbert Report.
The University of Michigan hosts an annual game development challenge, in which small teams of students have just 48 hours to develop a video game. The event is run by the campus' game development club, Wolverine Soft.
Better Know A District
My team consisted of fellow University of Michigan students Alex Soule and Steve Dewitt. Alex and I programmed; Alex composed the music; and Steve created the graphics.
This year is my third year participating in the contest. The first contest was held only a few months after I started college. Even though I had been programming for several years, starting with Qbasic back in elementary school, I had little experience in game development. Several poor design choices, including writing the game in Java and Swing, led to an incomplete game that took last place.
My second year didn't go much better. Despite having taken a couple of programming courses and being pared with an excellent programmer and artist, none of us had much game development experience. We brainstormed an excellent idea, but got too caught up in learning how to use our framework, SDL. This game was largely incomplete, and so we took last place yet again.
This year, I was determined to do much better. A few days before the contest, I sat down and made a list of various lessons I learned from the previous contests. Noting several areas that had caused problems, I went through a list of permitted game frameworks. The library I found particularly suitable was ClanLib, a C++ cross platform toolkit that wraps around SDL, OpenGL, and various system libraries. It has an impressive list of features and is fairly well documented. I was able to set it up and create a few test programs before the contest, eliminating a source of serious time problems.
Friday
8:00 p.m. After an hour delay, the contest starts. The theme is "Honoring Stephen Colbert," a very narrow theme and a surprise considering the previous year's theme: "Fight." I meet with Steve, who informs me that Alex will show up later.
We brainstorm on some couches outside the main contest room. For an hour, we talk about various gameplay designs and decide to do an adaptation of a "catch the cat" Flash game called Chat Noir. The game is a turn-based strategy and puzzle game; the goal is to stop a cat from leaving the game board.
We decide to use Colbert's "Better Know a District" as our starting point. The segment features Colbert attempting to interview every member of Congress, one district at a time. The skit has appeared less frequently over time as members of congress have caught on to its satirical purpose. Our game has the player placing fans of The Colbert Report on a game board to box in members of Congress and force them to be interviewed.
We decide to create a level progression, with the goal of having one unique level per congressional district. Ideas that we implement include different AI algorithms and the number of directions that the AI can move. We talk about implementing power-ups -- special board squares that give a bonus to either the player or the AI -- but we end up cutting them due to their complexity.
9:30 p.m. ClanLib will be the framework. I work on creating the basic structure of the program while Steve creates artwork. My development environment of choice is the standard UNIX command line tools. Due to the hobbled nature of the Red Hat Enterprise Linux installations on University of Michigan's engineering desktops, I commandeer the monitor, mouse, keyboard, and power outlet of a desktop and work on my Ubuntu installation on my laptop.
Alex shows up and by a very fortunate coincidence also perfers Linux CLI tools. He has access to a Ubuntu server and works on it by forwarding an X server display.
Before the start of the 48 hours, I had set up an empty subversion repository on my web server to ease the sharing of code. Also, because I had worked with ClanLib before the contest, I had no problems creating the basic structure. Alex initially had some problems compiling and installing ClanLib, mostly due to ClanLib's poorly written configure script and extensive development package requirements.
We create the basic game structure, which remains largely unchanged through out the contest. Here's what we did, in pseudo-code:
- 1. Initialize ClanLib and various libraries
2. Call program code
- 1. Initialize game data
2. While not quitting
- 1. If escape is pressed, quit
2. Execute a single step of the current game state
3. Change the current if necessary
4. Paint the screen
5. Check for events and any library "maintenance" work
10:30 p.m. I work on the first game state, a simple test state that displays a very crude game board. Using a simple picture editor, I quickly create crude placeholder art. I do not encounter any serious problems and create a simple map that responds to mouse clicks by filling in squares, a key part of the gameplay.
Saturday
12:00 a.m. Alex and Steve continue to create art. Meanwhile, I develop a very basic game AI, which checks each direction sequentially and attempts to move if a square is unblocked. Lastly, I write a game state that implements the main menu.
2:00 a.m. With a basic version of the game created, I turn my attention to the actual structure of the game. The basic game structure, as follows, was largely unchanged throughout development:
- GamePiece: Class representing a single square on the board.
GameBoard: Virtual base class for boards. By the end we had three boards representing squares, hexagons, and octagons where squares limit the victim to four possible movements, hexagons six, and octagons eight.
Algorithm: Virtual base class for victim AI algorithms. At the end of the contest we had two algorithms, one based on a breadth-first search and the other moving randomly.
GameState: Virtual base class for game states.
We encounter a couple of errors involving full screen mode. Until we had actual artwork to use, the program was set to use an 800x600 window. But once we had an idea of how large the art needed to be, we bumped this up to 1,024x768. Since my laptop's max resolution is 1,024x768, I modify the program to run in full screen mode, which I had intended to do from the beginning.
Bug number one: ClanLib segfaults when I quit. A back trace shows the program crashing when switching from full screen back to windowed. There are worse places to segfault, but I am able to quickly fix it by adding an explicit windowed mode statement before deinitializing ClanLib.
The second bug we encounter is far stranger. While in full screen mode under Alex's development computer, the bottom 100 or so pixels are cut off. We are unable to solve this problem, and instead compile for full screen on my laptop and for windowed mode on Alex's desktop.
While ClanLib can create user interface elements, our UI needs are limited to buttons. We decide to implement our own UI. Normally, I'm against duplicating code, but our quick progression and simple needs made this a safe choice. Our button implementation consists of an image and a set of coordinates that designate the bounds. The implementation is quite simple; the only real difficulty lies in getting the coordinates correct. Steve works on setting up button dimensions and their code to switch game states.
4:00 a.m. We finalize the game states and how they connect to each other:
- LoadingState: A simple loading screen. Switches to MainMenuState.
MainMenuState: Four buttons. Switches to MapState, AboutState, or
HelpState. Last button quits.
AboutState: Information about the theme of the game and its authors. Button back to MainMenuState.
HelpState: Message about how to play the game. Button back to MainMenuState
MapState: Picture of the U.S. congressional districts, button back to MainMenuState and then to the next level.
HexState: Level that utilizes a board made up of hexagons. Returns to MainMenuState on win or loss.
SquareState: Similar to HexState but uses a board made up of squares.
OctalState: Similar to HexState but uses a board made up of octagons.
I have a few issues getting all three new classes to work together as well as they did in TestState. However, I am able to resolve any issues before we break for the night.
Steve continues to work on the art and produces several cool backgrounds for MainMenuState, HelpState, and AboutState. Alex continues to work on various issues, including updating dimensions of placeholder art, fixing button dimensions, and replacing placeholder art with final art.
5:00 a.m. The project is in good shape, we agree to meet again at noon.
12:00 p.m. I modify RandomAI to move by randomly selecting a possible neighbor. The key part of the GameBoard is a function that returns a list of squares accessible within one move of a particular square or its neighbors. Later, I'll modify the behavior of GameBoard to randomly sort the list of neighbors before returning, rather than have the AI algorithms randomly pick.
2:00 p.m. The two largest outstanding issues are the lack of levels and the lack of competitive victim movement AI. Because the AI is much easier to implement and is necessary for a complete game, I decide to focus on it first. Considering the small size of the board and my experience implementing it, I chose to use a breadth-first search.
One half of the algorithm is to find a path to an edge square. I test this by moving the victim to the final square, and appears to work without any problems. The second half of the algorithm -- backtracing from a solution path to the victim's current position -- introduces a number of bugs that take quite some to time to fix.
The implementation of breadth-first search is inefficient. Every turn, it does a complete search of the game board, discarding any previous data. However, the small board and length of time between user actions easily covers any speed inefficiencies. Debugging the program on my T23 Thinkpad only causes a slight delay.
4:00 p.m. I finish writing the breadth-first search. We now have something that's playable and is a stone's throw away from being presentable. This is quite an accomplishment, and I'm confused by this strange sensation of being on track.
I start to tackle the largest unimplemented feature, the levels. Writing 435 levels (to match the number of members of congress) by hand is unreasonable, given our time frame. We decide to implement some type of map generation, and I work on cleaning up various classes in preparation.
Alex begins writing the hex board. The hex board is a bit of challenge. For square and octagonal boards, determining which square a mouse click resides on, and drawing the board are fairly easy. However, hexagons don't line up as neatly. Nonetheless, Alex is able to produce a working hexagon board quickly. The AI algorithms don't depend on any board characteristics, and they work immediately on the new board.
5:00 p.m. One interesting difference between the breadth-first and random AI algorithms is how they handle failure. Since the breadth-first algorithm is complete, the algorithm stops the moment there are no winnable paths. However, the random AI has no such foresight and will continue to execute until it is completely trapped and unable to perform any moves.
For consistency, we need to modify one of the algorithms to perform the same as the other. We decide to modify the breadth-first AI to act like the random AI when the game is no longer winnable. There are two reasons behind this decision. The more important one is that it is much easier to make the change to the breadth-first algorithm, and the changes are easily implemented in the game board states. The second reason is physiological. Each match can be roughly split into three stages, 1) building a barricade to try to funnel the victim, 2) building an enclosed area to capture the victim, and 3) trapping the victim until he has no moves left. We notice that the third stage -- even if irrelevant in the grand game since the victim will lose at any rate -- feels like a nice way to get revenge against the computer. It is a sort of falling action after the climax at the end of the second stage.
Next, I create the octagonal classes, state, and board. It's a fairly easy copy from the square board; the only real difference between them is how the victim can move. Nevertheless, I manage to accidentally introduce a bug. This simple bug becomes a challenge to remove, frequently manifesting in that the breadth-first search subtly picks less than optimal paths.
One key property of Chat Noir is how the boards generate, containing a random number of filled squares. I initially thought this "terrain generation" would be difficult to implement. But it's actually fairly simple.
Our generator takes three parameters: fill percentage, width limit, and height limit. The fill percentage is the percentage of the board to be filled by the generator; the width limit is how close a square needs to be to the x edge to be filled; and the height limit is how close a square needs to be to the y edge to be filled. The second two parameters have an unintended advantage. One strategy that players learn is to build a barrier toward the map's edges, which gives the player considerably more time to react to the movements of the victim.
Despite its simplicity, there are a few bugs with the map generator. The generator incorrectly applies the fill percentage, and the generator occasionally places a filled square over the victim. I fix the first bug late in development, but the second goes unnoticed until after the contest.
A majority of the artwork has been created and implemented. Alex and Steve turn much of their attention to play testing and polishing.
9:00 p.m. Alex leaves to see Cloverfield with some friends. A testament to our progress, all three of us could have easily left for an hour or two without serious repercussions or cutting back on sleep.
While Alex is gone, we work on the levels and develop a map definition format to ease our map creation process.
I start writing the map library, while Steve writes the levels. I create a new class named MapLibrary to handle map parsing and storing. It contains an array holding the unique information for every single map: map height and width, generator percentage, height and width limits, board type, AI type, and district name. I am able to get the basic structure and some parsing done, but I can't finish all data parsing that night.
11:00 p.m. Alex returns. WolverineSoft feeds us pizza for dinner.
There are a few places in the game were images of text were not usable, specifically in the MapState's next district name and stats. ClanLib offers two ways of rendering text, using a system font or to parse a very wide image consisting of each character in the font. Our current implementation uses the second method, with the font image being an example included with ClanLib. However, this font is of low quality, and we are unable to apply different sizes or colors to it during execution. I switched our font to use a system font, which do support font sizes and colors. However, I came across an interesting error message:
Congratulations! You just got assigned the task of implementing system fonts for clanSDL :-)
It's not what I want to see, but it's probably the funniest error message I've ever read.
Sunday
3:00 a.m. Progress is strong, so we break early and decide to return at 11.
11:00 a.m. Even with a full night's sleep, it takes me a few hours to finish the map parsing. Luckily, I don't encounter any difficult bugs in the map parsing, despite its complexity.
Next, I catch up and fix the incorrect fill percentage map generation bug.
4:00 p.m. Alex goes to a computer lab to compose music for the game. Despite the short time and lack of keyboard, he produces two good ambient sound pieces.
I add the music to the game, which goes smoothly, one minor bug aside. With the music working, I now add various sound effects that Steve and Alex have either created themselves or found. This also goes smoothly. I'm proud because every legal mouse click has audio feedback, which is in line with good UI development practices. Even though we didn't have any major problems with the audio, we didn't allocate nearly enough time to work on it. A simple bug in the library could have wrecked our progress.
With about an hour left, I check out a copy of the code onto an open Windows desktop. The ClanLib web site provides precompiled Visual C++ dependency libraries, and I'm able to produce a working, redistributable Windows port roughly 15 minutes before the deadline. The process is a bit complicated and time consuming, but I encounter only a single error involving release build. The final product is a debug build, which is less than optimal but sufficient for our purposes.
7:00 p.m. Packaging and uploading the final source appears to be a quick and easy task -- but it seems like everything goes wrong while uploading the Windows executable and source files to my university-hosted web site. Vital files are not included. There is a corrupted zip file. I exceed my disk quota. About a half hour past the deadline, I finally have everything uploaded.
The recommended guidelines state that each project should be demoed on two computers. We had access to two Linux and two Windows machines, and we run a copy on all four. All crises averted, we take turns watching over the game and checking out other games.
No matter how the judging goes, I'm quite happy with our program. It's an excellent idea, with strong implementation and polish. We were quite successful from a technical standpoint as well. Despite more than 120 subversion commits, there were less than a half dozen commits that had major bugs, such as segfaults, and a mere handful of conflicts. The program performed well even my older laptop, and had no memory leaks. This is quite an improvement over my previous two years!
A couple months ago, it took me a good eight hours to program a simple Tetris-clone in Java, despite the simplicity of the project: simple gameplay, minimal graphics, and a language that I understood quite well. I thought it would be unreasonable to expect to complete and polish a game that was three or four times more complex than Tetris in only 48 hours. Our basic game idea followed those same guidelines, selecting a game idea that we knew worked well and had a low level of complexity. I believe that played an important part in our success.
I learned quite a bit about the game just watching people play it. Having played the game extensively over the past 48 hours made me somewhat blind to various problems. In particular, I made a note of several places where the UI was unintuitive, ranging from users not knowing to click the screen after the win/loss message, to buttons not being clear enough, to the premises of the game not being clear. Level design, in particular, was an unfortunate weak point. A last minute tweak to the level progression (in an attempt to make the game more difficult, faster) nearly eliminated the hexagon levels. Additionally, many players remarked that they would have liked if the map types switched more frequently. As an overall testament to the game though, we frequently had more than four players wanting to play and received good remarks from the judges.
10:00 p.m. We win second place out of 14 completing teams! I had a lot of fun, and taking second place is a big redemption in my eyes from the previous two years.
Bryan DeGrendel is a junior at the University of Michigan and a member of the student game development group Wolverine Soft. His team's game took second place in the 48-Hour Game Development Contest.
Note: views and opinions expressed in this article are the author's and are not necessarily those of Wolverine Soft.
