Game Programming Patterns – Epic Notes

Programming patterns are the tools in a programmer’s tool box. The more usable tools a programmer has the better work he or she can do. Don’t be the man with the hammer, where every problem looks like a nail. Programming patterns are mental models a programmer can draw from when architecting solutions to problems. Game Programming Patterns by Robert Nystrom tackles the practical problem of organizing, structuring and architecting a game’s code base. It’s not always the most glamours or sexy problem to work on, but glue and organization is where a programmer will spend much of the work day. It’s often the hardest part, especially as codebases grow with many contributors. Robert has a very pragmatic approach. Being a perfectionist in the real world is often not very productive. The book reviews some of the patterns from the classic book “Design Patterns: Elements of Reusable Object-Oriented Software” by the Gang of Four as well as many other game programming patterns. Game Programming Patterns is written in a very fun style with lots of game related examples. Some of the patterns covered are very basic game programming concepts like “Double Buffer”, “Game Loop” and “Update Method”. Others are much more advanced. Bellow are some of my take aways from the book.

Epic Ideas:

Don’t overuse Singleton.

Use Abstract Class, Interfaces and Layers of Indirection when there is an actual use case. Don’t use them in a speculative way, just in case they are needed in the future.

Don’t optimize prematurely.

Prototype and Discover with throw away code, just be sure to through it away.

The Command pattern is great for implementing undo/redo.

Favor simplicity.

Be careful with scripting languages. (I’ve been on more than one project where large efforts had to be made to undo scripting languages gone wild in a game).

Deep, complex inheritance hierarchies are out of fashion.

Pattern’s Covered by the Book:

Command

Flyweight

Observer

Prototype

Singleton

State

Double Buffer

Game Loop

Update Method

Bytecode

Subclass Sandbox

Type Object

Component

Event Queue

Service Locator

Data Locality

Dirty Flag

Object Pool

Spatial Partition

10 Software Engineering Adages

As of writing this, I’ve been working as a software engineer in the game development industry for about 15 years. The game industry provides a unique challenge by combining many areas of computer science and software development. Here are 10 adages or rules of thumb that I have learned over that time. If you have any questions, comments or want more detail about the subject matter in this document, please visit http://danhamel.com and let me know!

1 – Favor Simplicity

One of my favorite tenants of Computer Science is K.I.S.S. When I was taught it in school it stood for Keep It Simple Stupid. I hear people say a more politically correct version these days, Keep It Super Simple. Albert Einstein said “Everything should be made as simple as possible, but no simpler.”. When you are weighing the tradeoffs between two approaches, don’t underestimate the negative impact of complexity. As the code base grows it becomes increasingly difficult to keep things simple, but doing so tends to pay dividends in the long run.

2 – Be Meticulous With Dependencies

In order to create software that is capable of scaling, you must pay careful attention to dependencies. Keep modules decoupled if possible. Don’t be lazy with includes. Continuously factor common functionality into shared modules. Keep well defined interfaces between modules. For game development a common approach is to organize the modules into a few layers like core, engine and game. Modules are able to depend on lower level and sibling modules, but never on high level modules. For instance a module in engine could use and depend on a module in core or another module in engine, but never a module in game. Ask yourself the question “If I want to lift this code and send it to a friend to use, what is the minimum amount of code I need to send to allow them to build it?”. If you end up dragging the entire code base along for the ride when sharing a low level module, it’s a sign the dependencies are not clean.

3 – Refactor Changing Code Often

Modern software development and game development in particular tends to be very feature driven. We want to continually push the product forward. New code committed to a project can often times be transient, and serves only to push the product forward in the right direction. IMHO this is the best way to write software. Take a direct path to create working software with a minimal implementation and iterate. Quickly failing forward to arrive at the best outcome. When developing software this way, you must continuously refactor. Rewrite systems when the requirements change. Be diligent about removing dead code. Pull redundant code into shared modules when that makes sense. As the product matures it will become clear what code is going to be around long term, focus on improving the quality of that code.

4 – Abstraction Layers and Interfaces

It’s usually useful to hide how a module works (its private implementation details) behind a public interface. The case study all beginning computer science students learn as motivation for this, is to be able to change how a module is implemented without having to change other code that happens to use the module. The module could also be swapped out with a different one that implements the same public interface. The calling code can use a well encapsulated module without being concerned about any of the gory implementation details. Here are some other examples where clearly defined interfaces are extremely valuable:

Application Logic and Display or User Interface

Cross Platform and Platform Specific Code

Interfaces for Automated Testing

Releasing a Library or SDK for other Engineers

5 – Automated Testing

In the days of boxed software, it was easier to muscle your way through a project, burning the midnight oil and crunching for a big release. These days software is often continuously delivered to the customers. We need automation to do the bulk of testing and validation to ensure the software is in a state that is good enough to deploy out to our users. Here is an example of what that might look like:

Local Testing: Before an engineer exposes her changes to others, unit tests and integration tests should be run on their local desktop machine. Unit tests are code written against the interfaces of application code to verify system behave as expected. In a perfect world this is possible, and tests are not restricted to being ran on a build farm only. Failing tests should be resolved before moving on.

Pre Flight Testing: The next phase is to build and run unit/integration tests on code that is proposed for commit, but has not actually been committed to source control yet. This can be done as a Pull Request in Git or a Shelf in Perforce. The build farm should pick up the changes, build and test them as if it was a committed change and report the results back to the author. It’s good policy not to merge any changes that do not pass this phase.

Build Farm Creates Release Artifacts: Once a change is merged or committed to source control, the build farm takes over, building and unit testing the change. If the code build and unit tests pass, an artifact is created and stored. An artifact is a built and packaged version of the software that can be retrieved, unpacked and executed.

Integration Testing: When new artifacts are posted, the build farm performs automated integration testing. That is, tests are run on the entire application, emulating the way a user would interact with the software. If all of these tests pass, the artifact can be tagged as passing integration testing.

Manual Testing: At this stage, a human can retrieve the latest artifacts that have been tagged as passing automated testing and begin manual testing. If manual testing looks good the artifacts can be tagged as passing manual tests, and are safe to deploy to users.

6 – Do a Deep Dive on Existing Code

Typical day to day life for a software engineer often times involves modifying an existing code base. Problems that seem really strange and difficult to track down can to seem really trivial once you understand how the code you are touching works. I’ve been a contractor for the last 6 years so I’m continuously learning new code bases. It is tempting to just take a stab in the dark with a quick code change in attempt to close the assigned task. And sometimes you get lucky and that works out, but I’ve found it’s almost always worth the investment to take the time to learn as much as you can about the code you need to modify and the surrounding systems. Sometimes this means setting breakpoints and stepping through the code, adding lots of temporary logging or just sitting down and actually reading through the code. If there any other engineers around that are familiar with the code base, try to get an hour of their time to give you a high level overview of the code. For me personally all this discovery work can be pretty painful. My ego wants to just dive in and start trying to fix the problem. But making myself do research until I have a deep understanding of the code in question pays dividends quickly.

7 – Measure First

This is one of the interview questions I used to ask to gauge how much experience a potential hire has. “Say you are tasked with improving the performance of a game or application. What would you do?”. Junior engineers would always just jump right into telling me what they would optimize. For instance, “I would use hash tables instead of linear searches”. The correct answer here is to measure first. Invest the time to gather as much performance data as you can. Write your own timing systems and/or research and use a profiler. The more metrics you gather the more accurately you will be able to identify the problem areas of the code. Once you know where the problems are, fixing them often becomes easy.

8 – Keep Poking

There are times when things just aren’t clicking. Maybe I have been trying to fix a bug for a couple of days, and nothing seems to work. It can be really frustrating and programming can feel like cruel and unusual punishment. I think this feeling is why most people quit coding. They hit this wall in school or on the job and think, “computer science isn’t for me”. We all run into this from time to time. When I find myself here, there are a few strategies I use.

Sleep On It: The brain works best in the morning after it’s well rested. Sometimes staying up late and pounding your head against the wall just doesn’t work. Take your mind off the problem, quiet you thoughts, get some rest and try again in the morning.

Shelve It: If schedule allows, time box how long you are willing to spin your wheels. Move onto a different problem and come back to it. Sometimes a fresh run at it will help you look at the problem in a new light.

Try Different Approaches: If you are stumped, try writing code to gather as much data related to the problem as possible. Write unit test code, write logging code, document the existing code or write a new application that tries to reproduce the problem with a more narrow scope.

Find a Second Pair of Eyes: If possible drag a second person in and explain everything you know about the problem to them. Sometimes just going through this exercise of talking out loud helps solve the problem. Or perhaps the second engineer can give some insight that leads to the solution. Don’t be afraid to ask for help. Even the most rock star engineers I know will do this instead of spinning their wheels for days at a time.

All of these tactics are meant to keep you moving, something will eventually click and you will have that ah ha moment.

9 – Use Internet Resources

I’m not ashamed to admit it, I rely pretty heavily on things like StackOverflow.com these days. In fact I will sometimes go as far as to let it influence decisions on what technologies to use. Google’s search is so good, you can find answers to nuts and bolts sort of questions really effectively. Break the problem down into small chunks, and use internet resource to help solve those problems one at a time. How to: GET a json payload from a REST endpoint in Python, Sort a STL vector, read a file in java for Android … just do a search in Google! Solve the small problems one at a time to keep making progress.

10 Have a Strict Code Style Guide

I’m usually lax about how another engineer chooses to implement something. There are many ways to solve a given problem. A lot of the time it’s not worth being a perfectionist about the nitty gritty details. It’s far better to be pragmatic and focus on finding solutions to problems actually reported by customers. All that being said, I have found it to be very beneficial to have a fairly strict coding style guide, and stick to it. If everyone on the team can converge on a specific style guide it removes resistance to reading, writing and comprehending the code. That leads to fewer bugs. Having a strict style guide also makes it easier to grep/search through the code and that will prove very useful.

What I’ve Been Up To

I have offered creative companies software engineering services for approximately fifteen years. I have worked in many aspects of software engineering with an emphasis on data pipelines, computer gaming, 3D rendering and large projects. In addition to having a technical software engineering background, I can provide architecture-level and project-level decision making to ensure the success of projects. I have a BS in computer science from Portland State University. Thank you for looking at my resume.

2009-Current Hypnos Entertainment – San Jose, CA
SR SE

 

  • League of Legends for Riot Games
  • Technology for SCEA.
  • Star Wars: The Old Republic (MMO)
  • Unannounced project for NCsoft (MMO)2001-2009 Electronic Arts – Redwood City, CA
    SR SE I
  • Dead Space – I provided core engineering on many aspects of EA’s cross game engine, pipeline and framework. I focused on the lighting pipeline, runtime lighting, runtime performance on PS3 and Xbox 360 and TRCs.
  • Tiger Woods PGA Tour 2007 – Lead the engineering efforts for our terrain rendering and pipelines on Xbox 360 and Playstation 3. I refactored rendering code and pipelines to support a new platform to our Xbox 360 code base, the PS3. I worked closely with the lead environment artist and art manager to create smooth pipeline for next gen outdoor environments. I coordinated effort with several other engineers working on different aspect of environment rendering and pipelines, many of these I implemented myself. Over the course of the project I was responsible for continuing evaluation of the environment feature set and scope management. I lead efforts for measuring and addressing rendering performance throughout the project.
  • Tiger Woods PGA Tour 2006 – Helped quickly port our existing Xbox game to Xbox 360. At that point helped design a new terrain pipeline, as well as did several passes of re-architecture of the game code. I was given the role of picking up whatever tasks needed to get done to keep the project running smoothly, as well as help and direct internal and external engineering resources.
  • Tiger Woods PGA Tour 2005 – On 2005 I was made Xbox lead and had ownership of character animation. The involved implement new animation features as well as managing efforts from multiple parties related to character animations. I was also the point person for Xbox specific issues.
  • Tiger Woods PGA Tour 2004 – During this cycle I had ownership over the entire tools chain for the game. This include all of the exporters for 3 platforms, as wells as the world building tools, character animations tools and build systems. I also added some character animation systems like secondary animation. To help final the project I picked the online module and UI for the EA messenger.
  • Tiger Woods PGA Tour 2003 – My main focus during this cycle was tools. I helped extend the world building tool and created new tools for character animation.2001 Ascension Entertainment – Portland, OR
    Lead Programmer / Project Lead

    I was the sole programmer on a two month publisher demo. The demo was a 3rd person 3D hover-boarding/shooter game. I fully designed and implemented the system in C++ using the Lithtech SDK, and did it within time and budget.

    I also coordinated efforts from several other parties on the demo. I created two month schedules for on level designer and one artist on the demo. As well as creating documentation for the demo.

    I was responsible for delivering each of the three milestones, along with documentation.

    1999 – 2001 – Cryo Studios NA – Portland, OR
    Programmer / Level Designer

    I worked in C/C++ creating extensions and debugging an existing 3D game engine. I worked on several aspects of the game engine including: Rendering, Collision, Physics, UI, Animation, Input and Sound.

    I also worked as a level designer, using an in-house scripting language writing scripts that provided the glue between the artwork and the game engine. My tasks also included camera placement, collision data placement and cinematic sequences.

    Cryo Studios NA provided a fun working environment that facilitated very creative work. During the time I was working at Cryo NA, we shipped one title, Hellboy, a 3D adventure game based on the hit comic book “Hellboy”. We where working on the pre-production phase of our next title when Cryo France (owners of Cryo NA) announced they where closing Cryo NA.

    1996 – 1999 – Pistachio, Inc. – Portland, OR
    Software Engineer

    At Pistachio I had the opportunity to work on several different system on different platforms. I also got the work on every phase of the software lifecycle, from concept to implementation to tech support and bug fixes.

    My first task was maintenance of STS. STS was a very large database application that school districts used to asses students on standardized test. SRS handled very large databases, scanned in tests, calculated RIT scores and generated several reports. There where a large number of user interfaces to make things easy for the users. I added several major additions to SRS as well as fielding support calls and fixing bugs in the system.

    I was also involved in created LTDS which was a tool used to update tests from a legacy system, or create new tests from scratch. I did most of the work on the editor, including user interface, databases access and test item rendering.

    Advanced Stock Screener – Android App

    Advanced Stock Screener is a personal side project that runs on Android. This project demonstrates many things including Java, Android UI, threads, network functionality, Facebook integration and a MySQL DB via a PHP layer.
    Advanced Stock Screener

PairWise Android and iOS Apps and Web Service

PairWise helps beer and food junkies select great beer and food pairings! Check it out at pairwise.co!