Feeds:
Posts
Comments

Archive for the ‘Code’ Category

Warp Speed

In our game, there’s a lot of on-screen action that we had to be prepared for — we couldn’t have cumbersome, but necessary, calculations and memory allocation processes drop our frame rate to an unplayable level. We’re shooting for a frame rate of 45 FPS; we’ll be happy with anything between 45 FPS and 60 FPS. To help us stick to the 45 FPS end of that spectrum, here are a few things we did to keep the game running smoothly:

1.) The default setting for Xcode is set to “Compile for Thumb”. You get smaller compiled code, but it’s slower in-game. Instead, we turned that off, which makes instruction sets larger, but they get processed faster in-game.

2.) Allocating memory is a slow process and doesn’t need to be done in the game loop; we stashed it away in the loading screen. That’s a big burden off the processor’s back during game play.

3.) All calculations that we needed for our particle system in game, we precalculated. When a meteor gets zapped, or collides with another meteor, the splash for the resulting 200-odd particles is already stored in memory; no slow, ponderous calculations that can effect frame rate need to be done within the game loop.

4.) We had the option of tracking and accounting for off-screen collision detection but chose not to do it. Concentrating only on the objects on-screen requires fewer operations and we decided the benefit to the speed of the game was more valuable than accounting for whether X and Y meteor collided on the opposite side of the planet. In a related maneuver, we also did not draw X and Y meteor on the opposite side of the planet; only the meteors near the spaceship (on-screen) are drawn, thus saving the processor from accounting for meteors not directly affecting gameplay at that moment.

5.) Originally, we stuck with Apple’s convention and wrote the game in Objective-C. We suppose this language makes sense if you need the compatibility Objective-C offers for other iPhone programs (like, say, a photo album) but there really wasn’t anything on the iPhone that the game would benefit from if it were written in Objective-C, so we rewrote the game in C++. This, too, gives us greater flexibility and helps keep our frame rate at the target 45 FPS.

A great resource on optimizing your application’s performance is this page from the Apple iPhone Reference Library: http://developer.apple.com/iphone/library/technotes/tn2008/tn2230.html We used it extensively while figuring out how to keep our game humming along, here’s hoping it will help you too.

Read Full Post »

Compression

What’d you do to my phone bill?!

If your game is going to send data over the network, remember that it’s going to cost your users money to do that. If it costs too much – i.e. if they raise an eyebrow even a bit at the cost – you’re in trouble. To avoid this, you’ve got to compress any data sent over the network. The second place where uncompressed data can screw up your app is in the game. Uncompressed text data stored in the game can slow load times and compromise the user’s experience. Large amounts of text data in-game need to be compressed and doing so can speed up your load times, which is always a plus. Copy and add these two files to your project to get around these two landmines:

1. Xcode -> Project -> Edit Project Settings -> Linking -> Other Linker Flags -> -lz (be sure to do it for all configurations)
2. follow the usage in the main.m file below
//
//  Compress.h
//
@interface Compress : NSObject {
}
// Returns a data object containing a Zlib compressed copy of the receivers
// contents.
+ (NSData *)compress:(NSData *)data;
// Returns a data object containing a Zlib decompressed copy of the receivers
// contents.
+ (NSData *)decompress:(NSData *)data;
@end
//
//  Compress.m
//
#import “Compress.h”
#import “zlib.h”
@implementation Compress
// 16K chunks for expansion
const int CHUNK_LENGTH = 16384;
+ (NSData *)compress:(NSData *)data {
if ([data length] == 0) {
return data;
}
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in = (Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
//   Z_NO_COMPRESSION
//   Z_BEST_SPEED
//   Z_BEST_COMPRESSION
//   Z_DEFAULT_COMPRESSION
if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK) {
return nil;
}
NSMutableData *compressed = [NSMutableData dataWithLength:CHUNK_LENGTH];
do {
if (strm.total_out >= [compressed length]) {
[compressed increaseLengthBy:CHUNK_LENGTH];
}
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] – strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength:strm.total_out];
return [NSData dataWithData:compressed];
}
+ (NSData *)decompress:(NSData *)data {
if ([data length] == 0) {
return data;
}
unsigned full_length = [data length];
unsigned half_length = [data length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength:full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[data bytes];
strm.avail_in = [data length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (inflateInit(&strm) != Z_OK) {
return nil;
}
while (!done) {
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length]) {
[decompressed increaseLengthBy:half_length];
}
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = [decompressed length] – strm.total_out;
// Inflate another chunk.
status = inflate(&strm, Z_SYNC_FLUSH);
if (status == Z_STREAM_END) {
done = YES;
} else if (status != Z_OK) {
break;
}
}
if (inflateEnd(&strm) != Z_OK) {
return nil;
}
// Set real length.
if (done) {
[decompressed setLength:strm.total_out];
return [NSData dataWithData:decompressed];
} else {
return nil;
}
}
@end
//
//  main.m
//
#import <Foundation/Foundation.h>
#import “Compress.h”
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string = @”This is a test of the compression library. Usually text compresses better than binary data. Don’t forget to add ‘-lz’ to ‘Other Linker Flags’ in your project settings!”;
NSData *data = [string dataUsingEncoding:[NSString defaultCStringEncoding]];
NSData *compressedData = [Compress compress:data];
printf(“compressed bytes: %d\n”, [compressedData length]);
NSData *decompressedData = [Compress decompress:compressedData];
printf(“decompressed bytes: %d\n”, [decompressedData length]);
NSString *decompressedString = [[NSString alloc] initWithData:decompressedData encoding:[NSString defaultCStringEncoding]];
NSLog(decompressedString);
[decompressedString release];
[pool release];
return 0;
}

Read Full Post »

Encryption

No Peeking

Unless you want your high scores boards filled up with bored hackers’ fake data – 20,000 users with high scores of 999,999! – then you’ve got to encrypt any data you send over the network and any date you save on the phone. It’s too easy for hackers to snag this data and wreak havoc on your high scores or, much much worse, with the passwords, phone numbers, and/or credit card information of your users. You’re a custodian of this data and if your users don’t trust you, you’re sunk. Simple as that. Here is some code that will help keep sensitive information private and hackers out of your high score boards:

Read Full Post »

Get Off My Boat, err, App!

The waters off Somalia isn’t the only place pirates disrupt the work of good, honest folks just trying to get their haul of tuna back to port. The iPhone app store is picked apart daily by the world’s internet pirates and a burgeoning library of apps – some 6,000 of the 25,000 for sale in the app store – are now available online for free. Big Brother (Apple) sits back in his chair – hands up, palms out, to show how clean they are – and spouts some kind of “the enemy of my friend is my friend”-type of head scratcher. So we’re on our own out here in a leaky fishing trawler trying to protect our catch from zooted up pirates and, let me tell you, Obama’s Navy Seal sniper team ain’t nowhere in sight, brother. So all you got is your wiles; here’s how to use ‘em.

First, you’re going to want to know if your app has been hacked. That genetic code of your app – Info.plist – will give you all the evidence you need.

1. If the file, once uploaded, is in text format, you’ve been hacked. When you upload your app, the file is converted into binary code, so if Info.plist is in text, it’s because someone wanted to change the parameters to allow your app to work on any phone and they’ve converted it back to text in order to do that.

2. Search for “SignerIdentity” in your uploaded Info.plist file. This is the fingerprint of a hacker. It’s the Shibboleth for your app to work on any phone. If it’s there, it shouldn’t be there.

3. When you’re finished with your Info.plist file, you know its size. So if that changes once it’s been uploaded, somebody’s gotten into it and screwed around.

Ok, so the pirates have their grappling hooks thrown over the side of your boat and a dude with no teeth and one ear has you looking cross-eyed at the business end of an RPG. It’s time to get diplomatic, so get out your sticks and carrots.

You’ve got a couple options. You can either shut out users who have a pirated app and just make the thing not work. But this is overkill, there’s no need to scuttle the ship right away. Instead, set a time limit, or max number of times a user can open the app, and when one of those parameters is met, display a message and explain that it appears the app on their iPhone is pirated and, please, we’re just family people trying to eke out a living in this cruel, electronic world, so why not click this link and dole out the measly $2.99 for our app? This tactic has been tried, and the results were surprising — conversion rates – from pirate-copy user to legit-copy user – of around 10% were seen when a calm explanation of the situation and an invitation to purchase the app were offered. The added bonus to this approach is that when someone cracks your code, it won’t be immediately obvious to the hacker that there is a built in fail-safe; he/she may play for a few minutes and move on to the next app thinking that this one is cracked. But when the hacked app is downloaded, after a few minutes, or a few uses (whichever you decide) users will get the notification that their copy is pirated and a request to buy the legit version.

There you have it. If only diplomacy worked this well in Somalia.

Read Full Post »

iPhone Audio Basics

Sounds Nice

It’s all in the details. You’re so focused on getting your app just right – making the splatter effect when missile meets buffalo in your “BuffaloZapper 2: The ReZappening” app, perfect – that you forget the system on which your app will be played was not designed with only your app in mind; your user has his or her own things going on with their phone, too, and they don’t want your app to blot those things out.

The big spot where this comes into play is with sound and music. Your exploding buffalo noise might be great, but your users might not care if they can’t have their favorite Anthrax track playing in the background when it happens.

So you’ve got to have your sounds right. To do this, you need to consider the different situations that could arise for a user and what expectations they would have for your app, their iPhone, and their music. Below is a chart that diagrams all the sonic situations your app should be prepared to accommodate for its users.

Headphones Plugged In iPod Music Playing Silent Switch On 

(iPhone only)

Music Sound Effects

Read Full Post »

Follow

Get every new post delivered to your Inbox.