Friday, February 24, 2012

Ping Pong

The next game on the agenda is Ping Pong. It should be familiar to most people who play games. Pong, the most well known incarnation of this game, was the first commercially successful video game. The gameplay is simple. Two paddles move vertically across the screen in an effort to bat a ball toward the opposite paddle. A player scores a point when the other paddle misses the ball and allows it to travel off screen. A victory is achieved if one player reaches a preset score.

Implementation should be straightforward, but the desired result of creating Ping Pong is not simply to have a Pong clone. The core deliverable of the project is the framework. The purpose of Ping Pong is to test and demonstrate the framework's effectiveness. It exists to give context to the framework. Accordingly, the framework will be the focus of this development iteration.

Three modules will be emphasized as I develop Ping Pong: graphics, input, and game management. The graphics module will handle drawing to the canvas. It will include two primary components: a library of functions to handle creating and drawing shapes and a management component that allows the developer to register drawable items without having to worry about drawing directly. Future versions of the module will include the ability to draw images, sprites, and effects, but the current iteration will focus entirely on shapes (such as a line, rectangle, sphere, or polygon).

The input module serves to alleviate the problems associated with Javascript's event system. Javascript's single-threaded nature clashes horribly with the browsers' asynchronous event system. The effect is not as profound in simple web apps, but in a real-time simulation such as a video game, events must be carefully and methodically managed to utilize user input effectively. The current iteration will include support for keyboard input. Mouse input will be added in later development cycles.

The game management module will be at the core of any framework application. It manages the game's flow from initialization to the game loop to termination. It handles timing in the game loop, makes it possible to pause the game, and keeps everything running smoothly and predictably. The single-threaded asynchronous issues described before will be handled by the game management module, as well. Further, navigation from real-time gameplay to menus (perhaps a simple pause screen or a complex configuration menu)  or other forms of gameplay (such as moving from an overworld map to a game level) will be managed by the game module. It is intended to be flexible enough to handle any type of activity, whether it be a menu, gameplay loading screen, or anything else.

In addition to these modules, smaller modules may be created for utility functions and other tasks. For instance, object oriented Javascript is made easier by helper functions. These will be encapsulated in a util.lang module. Other utility modules will be added as needed.

Each of the framework modules will be developed alongside the Ping Pong game itself. As the requirements of the game are drawn out, the modules and their functions will be written to aid in the implementation of the game.

Sunday, February 12, 2012

Hangman Postmortem

*Note: In software development, particularly game development, a postmortem is a discussion of the games development after completion. Postmortems enumerate triumphs and pitfalls encountered during development. They're used to reflect on the completed work and make observations on how development in future projects can be improved. Given the morbid nature of Hangman, I thought the meaning of postmortem in this case should be clarified. It is not an attempt at dark humor. It is the vocabulary used by professionals in the game development field. 

Hangman, the first game of the thesis, is complete. You can play it on my student webspace. Hangman is a simple game, and it was fairly easy to develop. It served as a good warmup for developing the framework at large. Further, I learned several important lessons while developing the game.

I chose Hangman for the first game due to its simplicity. Developing a game without complicated control flow or convoluted rules allowed me to focus on refreshing my knowledge of the Javascript language, the DOM API, and application design (particularly design issues specific to Javascript). It also allowed me to familiarize myself with HTML5 syntax, the canvas API, and other new concepts. References I found useful throughout Hangman's development are listed near the end of this post. 

Design and Implementation

The design included three modules: graphics, words, and hangman. The hangman module contained the the primary game logic. The graphics module contained functions for drawing to the canvas. Both modules were similar in length. The words module simply contained an object with an array of words that can be used as guess words in the game. The words module served to make adding additional words easy, precluding the need to search for a words array to modify mixed in the game logic code. 

The graphics module defined a list of functioned used to draw to the canvas. The module helps separate concerns, keeping all the drawing code separate from the game logic. Each function performs a single drawing task, but it significantly improves the maintainability and readability of the game logic since drawing a shape or a text string requires several steps using the canvas API. If the logic needs to print a message to the canvas, it can simply call printMessage(msg) rather than obnoxiously calling several functions of the canvas API. 

The hangman module is the entry point to the game from the browser. It defines the game's control flow and rules. The control flow is simple. It begins by initializing the game state. This step involves choosing a random word from the word list, setting or resetting variables (such as the number of guesses and the list of unguessed letters) to their initial value, and starting the next phase by connecting an event handler to process keyboard events. 

The next step is the game loop--it continues to run until a terminating condition is met. Unlike a standard real-time video game, however, an iteration of the Hangman game loop only executes when an event occurs. The game doesn't update unless the user presses a key on the keyboard. This portion of the game flow is contained in an event handler registered on the document. When a key press occurs, the handler processes the event and checks whether a valid key was pressed. Then it checks the letter against what has already been guessed. If the letter is valid and guessable, the logic determines whether it is a good guess or bad. Finally, it updates the canvas to show the new game state. 

The final step occurs when a terminating condition is met in the game loop. The player can either win or lose to exit the loop. When all the letters in the mystery word are guessed, the loop exits and prints a win message. When the player exhausts his six guesses and the hangman is complete, the loop prints a lose message and exits. The game then rests in a stopped state until the user presses a key. When any key is pressed, the game loops back to the initialization step and play resumes with a new mystery word. 

Lessons Learned

1. Learning the canvas API.
The API is deep and complex, but using its basic functions is easy. By the end of development, I would like to be intimately familiar with the entirety of canvas, but a developer can accomplish a lot just knowing the basics. For Hangman, the rectangle, arc, and path drawing functions were the most useful. 

2. The canvas text API is weak.
Unfortunately, the canvas text API is not very powerful. It manages text much as CSS would--you set properties on the context that correspond to CSS font properties to modify the way the text is drawn. Some properties are conspicuously missing, however. The line-spacing property would have been handy, but there was no way to set it. Further, positioning the text accurately is impossible because there is not a way to poll the text's dimensions. The API will return the length in pixels of a string drawn to the canvas, but it will not return the height or other dimensions. 

For now, the text API will suffice. Creating my own text library would be an unanticipated and laborious task. However, to make the text manageable in the future, I will need to write some functions to make positioning reasonable, though not perfect. Further, using any non-monospaced font adds horrible complications to text positioning. Only monospaced fonts such as courier should be used in games.


3. Input Processing Is Non-trivial.
Processing user input is difficult. Hangman's input processing was easier because it only used the keyboard, it limited the valid keys to the alphabetic a-z, and the game flow was asynchronous. Even with these simplifications, the program had to determine the key pressed from a key code using a key map, filter invalid keys, and involve the convoluted DOM even handler functions.


The next iteration of development will require an input module. The module will be developed incrementally. The first step will be to simply encapsulate the key map functionality implemented in Hangman. The key map will need to be expanded to include non-alphabetic keys such as numbers and punctuation. Further, the module will need to accommodate the problems that arise when the game flow is not asynchronous. These problems and their solutions will be discussed in more depth in upcoming blog entries. 


4. Modules Are Necessary.
I was aware that modules would be necessary prior to beginning development. However, I was unsure of how to provide modules to a language without a built-in module system. I considered rolling my own solution, but that job would have been difficult. I decided to avoid reinventing the wheel by using RequireJS, an AMD-compliant module library. I was afraid it would add unnecessary baggage to the HTML doc that loads the script in the form of additional script tags, but RequireJS is easy to use and unobtrusive. 


5. i18n Is Non-Trivial.
I attempted to make Hangman ready for i18n. However, several roadblocks prevented this goal from reaching fruition. First, though I made it possible to easily add alternate-language word lists, I did not make an easy way to swap the lists. Further, I did not consider making the messages printed to the users easily replaceable. Even if the word list was swapped, the international user would be confused by the English instructions and feedback used in the game. In the next iteration, this problem will be fixed by a string table mechanism. 

References
HTML5 Canvas by Steve and Jeff Fulton, O'Reilly Press. (available on Safari)