iphone development blog

Sunday, February 24, 2008 @ 6:30 PM

Part 9: Gratuitous Eye-Candy

iPhone Minds Developer's Journal - Crossword Puzzle
Games just aren't interesting without snazzy graphics. But graphics need to be downloaded, and you want to limit as many unnecessary downloads as possible when developing applications for the iPhone.

Until now, our game required only two images. The background image, and the image border used for grid highlights. Together these assets weigh in at about 24.5K. We also embedded a number of images in Javascript, which beefed up that file. All together the images, HTML file (which includes CSS) and Javascript file amount to 50K. That's really good for a complete game and means that the game will load quickly if you need to access it using EDGE.

But of all the things that irk me in life, only one is intolerable. A shitty ending to a video game. I mean you spend 40+ hours of your life (many of which are extremely aggravating) glued to the game. Is it too much to ask for a slick 5+ minute movie ending? Something brilliant that wraps up everything at the end. It only seems appropriate. So, I think it's important to give the winner of our puzzle something nice to look at when they're done.

End Screen:
Okay, it's not much, but hey, this game is being developed for demonstration purposes. Still, I think it satisfies the "snazzy graphics" requirement. Keep in mind that by the time you see the curl, the grid will be filled with letters. I didn't want to give away all of the words so I left the grid empty.

In my "Preloading Commonly Used Game Assets" post I mentioned that it would not make sense to embed all images in Javascript using URI Kitchen. The curl PNG weighs 69K. That's more than the entire game weighed up until this point. So, is it worth forcing the user to wait for this image to download when they won't even see it until the end of the game? Sure it is. Because we're not going to "force them to wait."

Since this image isn't required until the very end of the game (and it would probably take anyone at least 15 mins to solve the puzzle), we're going to load the image behind the scenes while the user is playing the game. Here's how we'll do it:

First, we set the game up. This includes waiting for all of the assets (except the curl) to download. Once the HTML has been parsed, Javascript hides the iPhone address bar, reads the game's XML file and builds the game's grid. The game is now ready to be played.

At this point we execute the following Javascript:
setTimeout(function() {
var curl = new Image();
curl.src = 'curl.png';
curl.onload = function() {
var img = document.createElement('img');
img.id = 'curl';
img.src = curl.src;
document.getElementById('body').appendChild(img);
img.onclick = function() { resetBoard(across, down); };
};
}, 30000);

Again, the above script will not execute until the game has completely downloaded and is playable by the user. This script then waits 30 seconds before it downloads and sets up the curl image, giving the game more than enough time to prepare the asset before it's required.

For dramatic effect, we're going to fade the curl in when the user has completed the puzzle. There are a number of Javascript resources you can utilize to create fades. MooTools is a great option. But since we're not relying on MooTools to manage the styles or effects of any of the other elements that make up the game, it doesn't make sense to include the MooTools Javascript library (an extra download) only to access it for one effect. There's a simpler way.

The Mac software company Panic has, for a long time, been a leader in creating compelling, and shockingly easy to use, Web applications (they of course make brilliant Mac applications as well). On their site I found a small snippet of math which we can use to fade the curl.

Javascript:
function cubicOut(t, b, c, d) { return c*((t = t/d-1)*t*t+1)+b; }
If you use this code within your projects, please give credit to Panic.

Using the cubicOut function, we can do the following:
var curlanim = { time:0, begin:0, change:0.0, duration:0.0, timer:null };

function curlFade(start, end, duration) {
if (end == 1) document.getElementById('curl').style.visibility = 'visible';
if (curlanim.timer != null) { clearInterval(curlanim.timer); curlanim.timer = null; }
curlanim.time = 0;
curlanim.begin = start;
curlanim.change = end-start;
curlanim.duration = duration;
curlanim.timer = setInterval(function() { fadeAnimDo(end) }, 15);
}

function fadeAnimDo(e) {
if (curlanim.time > curlanim.duration) {
clearInterval(curlanim.timer);
curlanim.timer = null;
if (e == 0) document.getElementById('curl').style.visibility = 'hidden';
} else {
var alpha = cubicOut(curlanim.time, curlanim.begin, curlanim.change, curlanim.duration);
document.getElementById('curl').style.opacity = alpha;
curlanim.time++;
}
}

In the last post I mentioned that the matrix array keeps track of whether or not correct letters have been added to the 225 different spaces that make up the puzzle. If it is determined that the puzzle is filled with correct letters (using the matrix array), then the game has been won and we initiate the curl fade with the following code: curlFade(0, 1, 50).

And that's it! The tutorial portion of this feature is complete. Although we didn't post every bit of the game's Javascript, I hope we've explained enough to provide a good sense as to how everything was developed. Come back tomorrow for a link to the working game!

// Ryan Jennings

Labels: , , , ,


MindComet at 6:30 PM - View Post