|
Schrödinger’s Cat emerged from the wreckage of the fall quarter design green-lighting process in much the same state as the other projects—frustrated, disappointed, and very, very, confused. Since mentally and bureaucratically committing myself to the game design program at UC Santa Cruz in the declaration of major process (a frighteningly distant four years ago) my one true aspiration was to do something with procedural level generation. As each of my lower and upper division classes came to an end, my hopes would brilliantly flare up that maybe this final project would be the one where I would finally get a chance to try my hand at something procedural, and every time those hopes would be unceremoniously extinguished by the harsh realities of my abilities, time constraints, team members, and/or the structure of the course itself. So, it shouldn’t have come as a surprise when I found that my dream would be dashed one last time before I bid farewell to the world of academia.
I had spent all summer resolving that no matter what the outcome of my senior design capstone course, my project would involve some kind of autogenrative feature. When the time came to actually produce the game idea that my team would pitch, having been instructed specifically not to do any designing on it before that very moment, this was the only idea I had prepared to bring to the table. My circle of friends was largely in the same boat; each had at best only a few neat mechanics in mind. So, we did what we could to lash together a game design from these disparate pieces, and the end result was an unwieldy Frankenstein of a game called Penetration. As I stood before the judges, pitching for all I was worth, it was apparent that they could see the seams, and they were not impressed. When the dust settled, our design was red-lighted, and so was the only other pitch in the class that made use of procedural level generation. Ironically, I had spoken with the lead of that other team shortly before, and we both agreed that even if our games’ didn’t make it, anything would be better than getting stuck on that game with the cat and the laser pointer.
Schrödinger’s Cat was pitched as a physics based puzzle platformer, something like Cut the Rope with lolcats. Inspired by YouTube videos and personal experience, the idea was to capture the fun of playing with a cat who’s freaking out and chasing your laser pointer, essentially tricking him into solving puzzles and completing traditional platforming challenges. I thought the concept was just simple enough and just quirky enough to be a success, and I was totally sold on the story (“What’s REALLY going on in Schrödinger’s Box anyway?”), but it was certainly not the kind of game I’d ever play, let alone make myself.
Nevertheless, Penetration needed some warm bodies, and in order to secure them, I had formed a group with the same guys who were pitching Schrödinger’s Cat, the mutual understanding being that if either game fell through, the team would stick together to work on the other. In all honesty, I would have been more than willing to throw this arrangement out the window, but my friends were not, and I figured if I was going to be in it for the long haul, better to spend the late nights coding with people who’s company I knew I enjoyed than to take a chance on strangers.
Yet my safety pitch had not escaped the green-lighting process unscathed. Where Penetration had been simply rejected, Schrödinger’s Cat had been approved with conditions—-the judges felt the cat’s AI was a daunting enough task on its own, and asked us to strip away everything else from the design, leaving us with a half-baked Nintendogz clone that had a laser pointer for some reason. This satisfied none of us. Through a bit of back and forth between our team and the committee, we settled on the current design: a platformer with the AI of the cat still the central component, but, relying on the fiction of the gameworld and the real Schrödinger’s Cat’s quantum theme, building our puzzles around killing the cat in inventive ways rather than on physics. We felt using death as a tool rather than a hindrance was something of an unexplored space in games, and one which felt natural given the subject matter-—since Schrödinger’s Cat is both alive and dead while inside the Box, any harm that comes to him during the course of the game can be written off as a mere projection of a quantum probability for which neither the player nor designer needs to feel responsible. Further, the possibilities for brutal violence assuaged any fears that the game might be written off as “for kids.”
We knew from the first pitch that this would be a casual game, i.e., bite sized levels focused on getting the cat from point A to point B (or, in our case, Box A to Box B), and the indirect control via the laser pointer lent itself naturally to a touch based interface, so the decision to develop for smartphone was inevitable. After some wavering between devices we settled on iPhone, influenced more than a little by another team’s decision to pursue iOS development.
As mentioned, our team initially formed out of convenience, but each of our interests and specialties came together to compliment each other in a unique way. We had a former astrophysics major on our team who excelled at applying scientific reasoning to each of our problems. The often unnecessarily elaborate methods which would emerge from this reasoning was thankfully tempered by the more pragmatic outlook of our more dyed in the wool programmers, who would take these ideas and incorporate them into a more traditional software design. We also had a pair of sound designers, including myself, upon whom rested the burden of producing and integrating a catalogue of sound effects and background music for our game. Our team also included a webmaster/server admin who handled the creation of our website and our automated build testing server, and a dedicated level designer.
Our team was required to have a leader, and that responsibility fell to me due to lack of interest in the role from any of our other members. Though the bulk of our design decisions were handled either as a committee, with each member having equal input, or autonomously by individuals, there were several occasions during which I had to step in and cast the deciding vote, if only to set aside the debate temporarily in order to continue making progress. In these instances, my authority was largely respected.
Our game was developed using the Airplay SDK, a collection of libraries for C and C++ designed to expedite creating applications for various mobile devices, including iOS, Android, and webOS. Our biggest motivation in selecting this SDK was that there was another team developing with it. This allowed us to establish a reciprocal relationship between our two teams, effectively making us study partners as we learned the ins and outs of the platform, as well as giving us an extra set of brains to bounce design patterns off of as we worked towards the most effective way of integrating with the libraries. Airplay abstracts away most of the intricacies of developing on ARM devices, greatly reducing the complexity of software development, especially across platforms (we had both iPhone and ‘Droid owners on our team), and allowed us to program in C++, the language we were all most familiar with. The SDK is also fully integrated with Visual Studios on Windows and XCode on Mac OS X, another great boon since we had members of both camps on our team.
I had had some of the best experiences of teamwork in my life working on this project. There’s simply something to be said for looking over at the people you’re slaving along side of and seeing the look of dedication, if not exasperation, or perhaps futility, and knowing you’re right there with them. As team leader, I had several unique opportunities to take the reins and lay out a game plan, and to have teammates willing to work it out with me, give me the input I needed to make it an effective one, and see it to its fruition, is a gift for which I am humbly grateful.
I fulfilled a number of roles on the team, each of which gave me a chance to explore a different element of software engineering. I designed the original decision engine element of the AI and was also the primary author of its implementation, as well as iterating on the interaction between A* path finding and the rest of the AI module. I was part of authoring the original UML for our project, giving me some valuable software design experience. I’m perhaps the most knowledgeable member of the team on the subject of the Airplay SDK, having designed and implemented the modules which rely most heavily on its resource management system, and spearheading our descents into its memory management system as we tracked down memory leaks and optimized our game. I also gained valuable experience as a sound designer and audio programmer, producing some of our music and sound effects and integrating them into the game.
Though I have my qualms with the structure of the game design program at UC Santa Cruz, if not the courses themselves, I will say that it was a unique opportunity to be able to pick the brains of some of the industry’s best and brightest during the guest lectures and critiques. One of the single best lectures I’ve heard in my four years here was given by Carl Schnurr on methods of quantifying design.
The facilities provided in the game lab were very good. There was enough space (as long as the entire class wasn’t trying to fit in) and enough tools to get our work done (computers, fast Internet connection, etc.), and the layout was both functional and comfortable.
With the exception of a fleet of reader/graders in the first quarter who gave questionable, often contradictory, feedback, every faculty member, both TAs and professors, have felt genuinely invested in and concerned for our progress and went to great lengths to give us every chance to succeed. It was an honor and a privilege to have had them as a resource, and I am endlessly grateful for their commitment.
From the outside, I had a clear vision of the quirky but accessible style this game could capture, and the final product is a resonable approximation. The level of polish isn’t what I would’ve expected, but to hear people talk about quantum events and the behavior of the cat (concepts that could easily make absolutely no sense) naturally making sense in the context of the game, it’s gratifying to know that those elements have been communicated.
It my not be everything I’d hoped for, and it may not have procedural levels, but it’s a game, and we made it.
"Don’t make an art intensive game," they said. "In a six month development cycle, there’s simply not going to be enough time to get all the art assets needed and to a level of polish expected by modern game players unless you embrace a more simplistic style, come up with novel solutions which don’t require (or mask the absence of) significant instancial resources, or have an entire army of artists working for you." In our class, we had groups which attempted all three of these approaches, and ours which attempted none of them—-we needed to produce a non-trivial amount of polished artwork, as the believability of the protagonist is as much a result of his visual aesthetic as the work we did on his AI (if not more so).
Further, we embarked on the road of acquiring these assets far too late. Our school lacks the infrastructure to simply “get” artists for game design teams as they do at other schools, so we were left to turn to people we know. For the first quarter we only had one artist, and we instructed him to exclusively produce cat animations, with the hope that he’d be done by the end of the quarter, allowing the next for focusing on the gameworld. The end of the quarter came, and he had a sinlge walking animation completed.
Our panic at this point was only compounded by the nagging of our professors to see this task handled, and we scrambled to get it all in, hiring on more artists and prioritizing their tasks, but the cuts were inevitable. What we should have done was put together a real plan for our artist(s) as detailed as the plans for our programming tasks, or at least finer in scope than “for two and a half months do X.” I've learned that a good plan should enumerate, in great detail, how much is expected and how much time it will take (compare these two against each other to make sure they’re reasonable!). Further, a good plan is incomplete without a backup plan. Finally, all the planning in the world is useless if you don't follow it--make sure the plan is being followed at every step, and adapt to compensate for shortcomings. It's also important not to ignoree the early warning signs; e may have had a much more polished game if we had reached out for help at the first sign things were going astray instead of at the last possible minute.
Our project was completed under the agile software development methodology paradigm using Scrum. In this system, project requirements are broken down into individual tasks which a single person can complete in a few hours. Members of the team volunteer for these tasks, complete them, and report back on their status at regular intervals. The theory is that they go off and work and only report their task as Done (with a capital D) when it’s at production quality.
However, when dealing with student programmers, this theory rarely sees fruition. In nearly every case where we followed this model of a single coder to a single task, he would return and triumphantly claim his task Done...and then a pair of other team members would have to refactor it. Bug fixes are a fact of life and no one should ever expect code to work perfectly on its first iteration, but when the actual specifications of a task or requirement, previously agreed upon coding conventions, and reasonable design and legibility standards have all been neglected (not through any malicious or negligent behavior, but through honest human shortcomings) there’s something amiss. What’s worse is that problems like these compound each other as one block of illegible code gets surrounded by others, and duplicate functionality emerges as it becomes easier to write new code than to read the old. Perhaps we could have done a better job of enumerating our tasks in the first place, or been more explicit in requiring proper coding and design standards, but when two people code together at least there’s a chance one of them will call the other on his flagrant disregard for common courtesy.
Far too often we failed to get a working build in time for our weekly playtesting sessions. The net result is that we either playtested the same old build (often one with only the most basic functionality) for weeks at a time, or we simply playtested the broken one. In the former case, after about the second week the testers’ feedback can’t help but fade into white noise as they repeat the same bug reports and half implemented features over and over again, and in the latter there’s potentially nothing to report at all-—the game is completely broken and unplayable.
In a perfect world we could have had the playtesting sessions happen on our own timeline, that is, no playtesting until we have a build worth showing if the previous build has already been tested to death. Unfortunately, we were held to a quota of playtests per week which, for scheduling reasons, had to happen at the same time every week. In the end, I can’t help but feel we wasted most of these. We should have been programming with playtesting in mind all along. Given the strict schedule we had, we could have treated each playtesting session as a deadline for which a build was due that was playable to the point of answering at least one concrete design question.
From the outset, there was contention over some core elements of our AI design. The two elements that needed to come together were the cat’s decision making process (what he decides he wants to be playing with at any given time and how he plays with it) and how he traverses our simple 2D platform worlds (how he gets to what he wants to play with). Given the simplistic nature of the level geometry, some members of the team felt that a simple directional imperative would be sufficient (i.e., if I’m left of my goal, go right, if I’m right of my goal, go left) while one member felt that anything less than an implementation of A* path finding would be insufficient. Both groups felt their solution was the more elegant and easier to implement, yet both had a hazy answer to the question of how the cat would jump. Jumping between platforms could be handled with some reasonable extensions to the underlying system in either case, but we wanted the cat to be able to jump after anything on the map, as a real cat would when it’s playing with something. After a lot of arguing, we were seduced down the path of A*. We knew the net result would be something like sandblasting a soup cracker (paths will almost always be entirely composed of straight lines and our grid is only 16x16), but we thought the knowledge that our paths would always be optimal would be comforting, and we had been eagerly convinced by our A* proponent that jumping would be much more fluid with that system.
Cut to a month later, and we were still chasing down bugs in the behemoth of code that was unleashed, we were hearing it doesn’t run fast enough to be executed once per game loop, and there’s still no solution to the jumping question. A month may not seem like a long time, but it’s approximately a third of our development time, and to be at that point and not have the protagonist of your game able to move in the world is a frightening thing. The cat’s ability to jump is still the most awkward part of the game, and the number one complaint by playtesters. Further, the amount of time spent dealing with pathfinding has left very little time for fine tuning the decision engine, which is what the selling point of the game was to begin with.
Perhaps we would have been better off keeping the scope of our game in mind from the beginning, designing our AI from the ground up to fit our game, rather than reaching instinctively for the most powerful tool available.
The Airplay SDK fought with us on several important issues. First of all, the differences in the emulator depending on platform (Mac OS X vs. Windows) and the differences between the emulator and the actual device environment meant that bug tracking became a much more onerous task. In spite of claims made on its website, its memory management system does not handle C++ standard library functions and classes, leading to obtuse crashes that plagued us for some time. Finally, its sound support is very bare bones, and the functionality it does have is questionable at best.
In situations like these, all you can do is do your research and roll with the punches. No middleware is ever going to do everything you need it to do perfectly, each has its own quirks, its own advantages and disadvantages. Ultimately, I think we were right in sticking to our decision once it was made, really learning and adapting to our SDK’s specific intricacies, rather than jumping ship and switching engines when problems arose, as teams in the past have done.
Making Schrödinger’s Cat has certainly been a learning experience. Through all the disappointments we’ve come out with a product that, at the time of this writing, I’m hopeful I’ll be able to say I’m proud of.