Tuesday, February 9, 2010

Rewind

As you may have seen in the video I posted below, our sophomore game, Tim-E, let you rewind time dynamically in-game, kind of like in the now-famous Braid. However, the way we rewound is perhaps one of the worst possible ways ever. Being the engine architect, generalist, and naive programmer I was at the time, I attacked the problem in the simplest way I knew how. I stored deep copies of all game objects that were "rewindable" in a new list every frame. There was no maximum, so our memory usage went through the roof. Our performance hit wasn't too bad, though, being a simple 2D game, so we thought everything was fine until we got particles into the game.

We wanted particles to be rewound as well, because that effect is nifty and all, except when you have 500+ particles on the screen, storing all of these every frame becomes really time consuming and memory intensive. So, I figured I'd simplify things a bit by putting a cap on the number of recorded frames and only store critical information: position, rotation, animation frame, and other things that only really needed to be preserved. Then, when you rewound, it would modify the original object to have the stored values. Of course, then I ran into another problem: some objects would get permanently deleted in the present, and when you rewound, it would casually modify the freed memory, corrupting the heap and jacking up the whole game.

In retrospect, this problem would have been incredibly easy to solve: if we had used handles to our game objects, we could have removed the handle from the master game object list so that it would no longer get updated, and when we rewound, it could have freely updated the game object without any problems. The object would still have been freed when the recorded frame was eventually deleted thanks to the cap, and everything would have been good. Instead, I chose to attempt to find every special case that broke rewind and fix it. It cost me at least three weeks of debugging time when I could have been implementing new gameplay features.

Of course, hindsight is 20/20 and now I see I approached the problem from the wrong angle entirely. I did not design our architecture with rewind in mind; while it was dynamic and composition-based, implementing rewind in a robust, flexible, extensible way would have been to add a messaging system that recorded inverse transforms of each gameobject-transforming message. For example, if a change velocity message containing a vector increment was sent to the player, a new message with the negative vector could be automatically stored. All of these messages could be stored in a queue associated with the game object, and when the game object was permanently deleted, all the messages could have been deleted as well. This type of system would have been much more robust and error-proof, as well as extensible with our architecture.

There are many other things I would change if we were to make Tim-E again, but that is the nature of learning though practice. Perhaps if I could just keep all the knowledge I have now and just rewind...?

Saturday, February 6, 2010

Gameplay and Iteration

As I mentioned before, every year at Digipen. we team up in groups of three to five and make a game from scratch, building it from the ground up. Last year, my team and I made a game called Tim-E, an action platformer where you play a robot that has the power to control time. I had been avoiding making a post on this because I wanted to get a newer video up, but we haven't had time to make one this year. Shown below is a video when we were at beta (roughly 3 weeks before the final version).


Over the two semesters we worked on it, we iterated through a lot of design ideas. In fact, while our original idea was essentially the same, many of the specific mechanics we had planned ended up wildly different. We had planned to make the game about a secret agent who wielded a sword made out of particles, but creating good animations were too time-consuming and challenging for us to continue down that path. Eventually we decided on switching our main character to a robot that had loose "fists" that it could use to attack enemies. Even the time abilities our character had we changed for more intuitive powers.

For example, before we changed a lot of our design, when using the fast time power, everything would move much faster, and when attacking, the player shot a concentrated burst of particles in front of him, damaging any enemy within a short range. After playtesting, we realized that though the player could move and attack faster, having the enemies move and attack faster as well turned the ability into a detriment, and caused players to avoid using it. We decided to completely change the power, and instead made it a type of boost, where the player could boost quickly in a direction controlled by the arrow keys, and, if they hit an enemy, would initiate a spinning fist attack. After more playtesting, this turned out to be the best decision we could have made; this power turned out to be everyone's favorite.

While I would like to say that playtesting drove our gameplay, we only got the chance to playtest a lot nearing the end of development. The playtesting feedback we did get was extremely valuable, and helped our game immensely; for instance, in the beta version (shown in the video), the floor tiles the player stepped on changed different colors, including to be red in some cases. Many people thought that the colors meant something, and that red was dangerous; after realizing this, we changed the coloring so that the tiles only turned green. We also used this idea for our final boss, who would spawn columns of damaging particles out of the floor, and colored the dangerous tiles red to indicate which ones would be the most dangerous.

Playtesting feedback like that was incredibly valuable, and I only wish that we would have started sooner; finding that people liked the fast forward power the most early on may have ended up changing our whole design, and that, I suppose, is what this whole post is about. If we had started playtesting earlier, we would have ended up with a different game. A better game. One that was more fun to play, because people would have told us what they liked, and we would have given them more of it. I think that if you start with an idea, implement the bare bones of it, let people tell you what they think is fun, and use that for the next iteration of the game, the game will be stronger than the original design every time. Design ideas can look great on paper; we thought that making the slow time power make your gravity force less so that you can have more control and time in the air was a good idea, but everyone's response was "Why does slow make you fly?" It was unintuitive, and the playtesters told us that.

Think about if every game was developed by listening to playtesters. Obviously, some people can have some really weird and unrealistic ideas, but, barring those, a group consensus will basically always be right. It takes a good designer to design a fun game, but it takes a great designer to listen to people say what they think needs to change about the design. Great games have great designers. Great games have been playtested and polished into shining jewels. My passion is to make polished games, and I hope we'll reach that goal this year.

Wednesday, January 20, 2010

Hello World

Welcome to my humble blog, where I'll be posting periodically about the game myself and the rest of my team is working on. First a bit about myself: I'm a junior at Digipen Institute of Technology, a school for programmers (not computer scientists). Digipen is essentially a trade school for game development, so we end up writing quite a bit of code around the course of a year. We study traditional concepts like data structures and algorithms, but also more specialized fields like real-time graphics and low-level assembly. Although many people try to focus on a particular discipline, like architecture or AI programming, I prefer to be more like a jack of all trades, good at everything, unlike a lot of people who focus so entirely on their field that they don't know much about other things. As part of our curriculum at Digipen, we team up into groups of three to five programmers, and create a game over the course of two semesters. My role on the team this year has been to do what no one else has time to do - input, sound, AI, logic, debugging help, testing, integration, and whatever else needs to get done for deadlines. It has worked out really well so far, and I look forward to see what the future will bring!