A Roll of the Dice: Building a Small Game Using Windows Graphics Programming
- Separating Abstraction from Implementation
- Dice, and Visual Representations of Dice
- Playing Sound Files with API Calls
- Managing Object State Change with the Observer Pattern and Events
Good programmers combine formal and informal education with a lot of practice. Great programmers do the same things, but they also do a lot more. Great programmers read and write a lot of code. They know about refactoring and software patterns, they employ good habits, and they reserve their creativity for software problems that are unique rather than common. Consistency and simplicity are hallmarks of great programming.
So, let's do some of that practice and code examination. In this article, you'll get a chance to practice a variety of programming skills in building a graphics program. Plus, you can enjoy the output (a fun diversion based on the Milton Bradley game Yahtzee)‚ and use elements from the solution to implement your own dice-based game.
This article is based on elements of a game I wrote called Dihtzee (pronounced “dicey”), a digital version of the Milton Bradley™ game Yahtzee. Dihtzee uses basic graphics programming techniques to create the illusion of rolling dice, and a simple call to an API to play sound. Aside from being an entertaining distraction, Dihtzee uses the Observer pattern to manage all of the complex interactions between game elements. Between the software patterns and the graphics techniques, you'll polish fundamental programming skills while having a bit of fun.
Separating Abstraction from Implementation
For all but the most trivial programs, it is paramount to separate abstraction from implementation. For example, a customer object is not the same thing as a customer presentation object. A customer object probably knows about names, addresses, and credit ratings. A customer presentation object is, more than likely, a GUI that permits a person to interact with the customer object. Without a careful and deliberate abstraction between the two entities, the resulting monolithic customer gobject “GUI object” will likely never be reused, it will be difficult to extend, and it will be expensive to own.
It is important to distinguish between rampant object decomposition and deliberate decomposition. Rampant object decomposition is like excessive database normalization: if you decompose everything into classes (or normalize tables) as much as possible, you will end up with a lot of code to reconstruct related entities and behaviors. By knowing that it is possible to decompose objects further, but electing not to (that is, being very deliberate in your choices), you'll find a balance with just the right amount of decomposition.