Wednesday, February 6, 2013

GGJ: what I knew to make Heartchers

The other weekend I was part of the Global Game Jam. The theme was a heartbeat, and my team made Heartchers, a head to head HTML5 game for iPad (or other large-ish multitouch systems) Here it is in action:

You can play it online at  heartchers.alienbill.com (the ratio might be off in a desktip web browser, and the controls won't be as pleasant, but you can still get the idea.)

The core of the game is Processing.js -- I've had great luck with Java-based Processing at past jams, and was able to transfer my experience to its crazy fun "write java, we'll turn it to javascript" outlook. It was also a good test of my own lowLag.js sound wrapper.

My team was me as the programmer, Bart Cusick as the "art guy", and Ken Snyder for sound. So this entry here can either be seen as a postmortem of our weekend, or me tooting my own horn about how darn clever I was.

The Shape of the Game
I pitched the game during the brainstorming session (the name was suggested by Ryan Kahn)... I had the vision of a game with joust-like controls, maybe with one person doing left and right flap, and a second player aiming and firing the arrows with the mouse. I had used the left/right flap control scheme in an earlier 2hour gamejame game and I knew it had some untapped potential.

For a while we toyed with having a server-based game, which would let us hit the "play over 2 devices" diversifier (optional challenges a team can take on), but given my inexperience with that kind of game making we decided to keep it simple and local. The 2 player aspect came out as we developed playable prototypes... it's a classic, solid game paradigm harkening back to Spacewar!-- appropriate, because we were just down the street from where that pioneering game was made.
 
The end result was pretty close to what I had in mind when I pitched it, I'd say. I think members of my team were pretty decent at listening to one another during the inevitable small disagreements that emerged.

The Build Process
Since we were targeting iPad (using multitouch as a way to get past the multiplayer interface limitations of a typical PC+mouse setup), we had to figure out how to get builds onto devices. I figured it would be easier to throw builds up onto my webserver. (I thought I was pretty clever for making a dedicated subdomain for this, heartchers.alienbill.com, but I was surprised how many teams either did that as well or grabbed a new domain entirely!)

A typical large(ish) Processing program will be broken into multiple files, and then those files are concatenated into a single ".pjs" or ".pde". I recreated this process with a Perl script... my index.cgi actually glued the pieces-parts into a big file every time it was reloaded. (Actually shelling out -- something like

`cat src/file1.pjs src/file2.pjs src/file3.pjs > heartchers.pjs`;

-- to do the work.)

Of course, one of the charms of writing HTML5 stuff is when you eliminate the build process entirely, just save, switch over to the browser, and run. I recreated that ease of with the program WinSCP... I set it up to monitor my src directory. Every time I saved a file, it noticed the update and pushed the changed files to the server. No source control to speak of, but we had continuous deployment up the wazoo, baby! (I should  have written a few more lines of script in index.cgi to take snapshots, come to think of it.) Dropbox worked well for sharing art and sound, and with one programmer we dodged much of the usual file conflict issue.

Multitouch
So Processing.js supports multitouch, but I couldn't find solid documentation for it, in particular the content of the "touchEvent" object... I had hoped/assumed that if there was a touch event there was a way of identifying the "new" touch, but I didn't know what that was (the "changedTouches" array, it turns out)
I tried to use JSON.stringify on it, but its structure was circular, and stringify() wouldn't work. I ended up making my own inspector of the keys for the object, and figured it out from there.

Another important step was making it so I could still do most playtesting on my laptop -- I wrote an abstraction layer so both mouseEvents and touchEvents would be treated the same:

void mousePressed() {
  controlPress(mouseX, mouseY);
}
void mouseDragged() {
  controlMove(mouseX, mouseY);
}
void mouseReleased() {
  controlRelease(mouseX, mouseY);
}

void touchStart(TouchEvent t) {
  for (int i = 0; i < t.changedTouches.length;i++) {
    controlPress(t.changedTouches[i].offsetX, t.changedTouches[i].offsetY);
  }
}
void touchMove(TouchEvent t) {
  for (int i = 0; i < t.changedTouches.length;i++) {
    controlMove(t.changedTouches[i].offsetX, t.changedTouches[i].offsetY);
  }
}
void touchEnd(TouchEvent t) {
  for (int i = 0; i < t.changedTouches.length;i++) {
    controlRelease(t.changedTouches[i].offsetX, t.changedTouches[i].offsetY);
  }
}

I was surprised to find out I didn't have to weedout mouse events on the iPad; I get the feeling once the system knows you're reading multitouch it stops doing its usual "treat touch events like the mouse" thing.

Misc Points
I've always been a big believer in log-based debugging; especially in a system with as a big a gulf between source code and running code as Processing.js, the process of "figure out your assumptions, then what you can print to tell you which is incorrect" is even more crucial than usual. Processing.js offers a fakey console with "println()" support but it interferes with the game display; I ended up writing my own "Msg()" function to do an onscreen log display.

There were some problems with stopping iOS "select text" feature, and an annoying little attempt at scrolling it would do. This link on select helped a bit as did this one on the bounce effect.

There's actually a bug on iOS and the "first touch event", see this thread which has a link to the custom bugfix processing.js file we actually used.

I think I played a little fast and loose with the Processing/Javascript divide; for instance I called my lowLag library directly, and I think after a while started getting sloppy to the point where I couldn't use the default Processing IDE- I switched over to Komodo Edit in java mode then.

The game does some funky scaling to always fit the available real estate, but it also has some hard coded size constants so it's not really playable on iPhone. Also, there have been times I left it running where it kind of locked up the iPad; the game was still running and responsive but I couldn't get back to the home screen or even turn it off without doing the "hard shutdown" off the device. (!) I don't think a web based game should be able to do that on iOS...

The old adage about building playable prototypes ASAP certainly came into play; of course, that's my dark secret as a gamemaker: I'm actually a toymaker who then builds games on top of the toy. For me, that's where the heart of the joy of video games lies; not in story, or character, or rules or system, but in virtual toys that might not even be possible in real life.

The controls were kind of fun... a virtual dial to aim, release to fire, and then virtual left and right flap buttons for each player (it was surprisingly easy to make the "upside down" version for player 2, my art guy had been skeptical) Of course the challenge with multitouch is you don't necessarily know what player is doing which touch, so we took the simple approach of splitting the screen, and having static controls separate from the action.

So overall I am happy with the way it turned out! It's one of the most fun games I've ever made. I might try to do a native iOS version at some point, or experiment with other variations, like a one player mode. I'm also delighted to know how to do a multitouch game now-- I'm eyeing a version of Atari 2600 Warlords next...

No comments:

Post a Comment