SwipeHead
Most of us, at some point, will apply a label of sorts to ourselves. Are we teachers, rocket surgeons, hippies, nihilists, or maybe middle-aged? A single label rarely suffices, and I’ve gone through a few myself. I’ve alleged myself to be a musician, a coder, a technician, a writer (hah), and had a few other stints. There’s a common thread here: I like making things. With that out of the way, in the middle of December I helped to make this:
This is SwipeHead, a sort of hybrid puzzle game for the iPhone and iPod touch. I’d explain how it works, but figuring that out is one of the more satisfying puzzles. It reminds me a bit of old LucasArts adventure games in which a challenge would be posed and various tools offered, but after that it was up to the player and their wits. SwipeHead, likewise, is meant to have an intuitive learning curve and once it gets going, is very enjoyable.
Though I might seem to be trumpeting my own horn, the real kudos go to the game designer, Leanne, over at Wizkeit Games, who designed and produced the whole thing. For my own part, it’s humbling to see my code executing on other devices and available on the iTunes Store. I know there iTunes Store is a pretty saturated market these days, but it doesn’t detract one bit from the glee. More horn trumpeting yet: it was accepted on the first submission, which Leanne and I were told doesn’t happen often.
If you’re looking for a unique experience among the many app clones on the iTunes Store, give SwipeHead a try. When I first saw the design documents, it wasn’t one bit like any other puzzle game I saw out there, and remains so even post-release. Though only a mere $0.99, there’s a free version as well to whet your appetite.
[UIImage imageNamed:]
UIImage *myImage = [UIImage imageNamed:@"pony.png"];
This is probably one of the most convenient methods I’ve ever come across. Feed it a name and it will return an image. Better yet, it handles caching for you automatically so that you don’t have to. Notice something about it though? There’s no alloc, meaning you shouldn’t call release. If you can’t call release, how do you get your memory back? This isn’t a big deal when using Mac OS X’s older brother, NSImage, since your average computer these days ships with several gigabytes of memory as opposed to the paltry 25MB or so that most iPhone apps are limited to. If you’re dealing with a lot of images on the iPhone though, this hands-off caching approach is going to cause problems.
The first obvious solution is to just avoid the convenience method and manually alloc and load each image with its full path:
UIImage *myImg = [[UIImage alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/pony.png", [[NSBundle mainBundle] bundlePath]]];
That’s not awful for loading an image or two, but if you’re going to load many images, why not encapsulate this in something more elegant? Since such a method would be useful application-wide, it furthermore makes sense for the method to exist in its own application-wide class, rather than just stuffing the method willy-nilly into whatever class you’re working in. Actually, if you’re going to go to the trouble of creating a new class just for a convenience method, why not make it do other neat things? Let’s do that.
Litmus Test
The other night Danny and I were talking about tag clouds and a possible experiment that could be done using something called Wordle (see this post for more info about Wordle). The experiments requires that the news cycle be on “autopilot,” i.e., a general representation of what’s going on in the world over a long stretch of time. The recent swath of high-profile celebrity deaths has thrown a kink into the works (to put it lightly), so hopefully I’ll be able to put up some results in a week or two.
In completely other news, I’ve located another excellent source of OpenGL ES tutorials, this time from Simon Maurice. Jeff Lamarche, whose tutorials I posted a few weeks ago, has also added some new content and updated his project template to work with the new iPhone OS. Good stuff.
Phantom Functions
Not that they’re very spooky, but function calls that don’t do anything can be a real time-sink. The call in question: glPolygonOffset(), a terribly useful function which I was using to prevent Z-fighting. Everything worked as expected in the iPhone simulator, but nothing happened when run from the real hardware! After an hour of searching through the code and documentation, it turns out the answer is pretty straightforward: polygon offset is not supported by the hardware.
The fact that the compiler didn’t kick out a warning or error would seem to suggest that the feature is available in later models. My test platform uses PowerVR’s MBX Lite 3D GPU, as do all models up until Monday’s announcement. Still, Apple is able to tailor the SDK’s header files exactly to their devices capabilities, so it’s a touch frustrating. On the bright side, there’s a workaround for coders who needed glPolygonOffset to draw edge geometry:
#define EDGE_OFFSET 0.00001
glDepthRange(EDGE_OFFSET, 1.0);
/* draw all non-edge geometry */
glDepthRange(0.0, 1.0 - EDGE_OFFSET);
/* draw all edges */
There’s a couple more good ideas actually, but the above code works fine for a low-power device.
I am an Idiot
Learned two things today:
1). An array of pointers is possible without stuffing it inside a struct. GLuint **texturePtr; creates a pointer to a pointer, and since a pointer can easily point to an array allocated with new, it follows that such a pointer could point to an array of pointers pointing to more stuff. Lesson learned.
2). The statement int allocSize = n * 16 – 8; GLfloat *vertices = new GLfloat[allocSize]; is only useful when n > 0. Whoops.
Update: It’s done! This most productive weekend has turned out a mostly-functional lightweight OpenGL-based sprite library.
Pointing Fingers
An array is useful, and a pointer is useful, and if a pointer pointing at a dynamic array is more useful yet, then surely a dynamic array of pointers must be made of awesome sauce. Cocoa has spoiled me a bit, what with NSMutableArray acting as just the ticket, but at a probable expense. Complexity and abstraction layers are the enemy of framerate, so I’ve turned to C arrays to solve a time-sensitive problem. After a couple hours of poking around, I’ve found a solution, though I can’t tell if this is elegant, hackish, or just downright silly:
typedef struct {
GLuint *texturePtr;
} TextureStruct;
TextureStruct * allTextures;
So what’s going on here? Originally, the plan was to have an array of GLuints to keep track of loaded textures (there’s no sense of loading the same data twice on a handset with little memory after all). The array doesn’t know how big it will be at compile time, and more importantly, it might grow or shrink during runtime, so a declaration of GLuint * texture; seemed like the logical thing. Problem is, arrays hold data, but this array must hold pointers. Wrapping the pointer inside a struct and then declaring a pointer/array of the new structure does the trick, but it feels crude.
It’s a strange feeling though, that the actual data doesn’t have any central location. A texture is loaded when an object needs it, but the texture doesn’t belong to the object, nor does it belong to the above structure/pointer/array monstrosity. It just hangs out.
OpenGL ES from the Ground Up
Back in developer land, I’ve found something terribly interesting. A fellow by the name of Jeff Lamarche has written up an OpenGL ES tutorial geared towards iPhone Devs. OpenGL has always terrified me, so this will be a great resource. Better yet, OpenGL, as hinted by the word “open,” is intended to be a very portable cross-platform tool, so the lessons learned should be equally portable.
Object Chains
This almost certainly isn’t a first, but I discovered a neato trick. Let’s make a chainable class, called Chain. It would contain two instance variables (at least) called next and previous, also of the Chain class. Its init method would go something like this:
- (id)initChainOf:(int)n
{
if(self = [super init])
{
// Setup instance variables, etc. Then:
n--;
if(n > 0)
{
next = [[Chain alloc] initChainOf:n];
next.previous = self;
}
else
{
next = NULL;
}
previous = NULL;
}
return self;
}
Call Chain *myNewChain = [[Chain alloc] initChainOf:5]; and you’ve got five new objects linked together. After the first object is initialized, it decrement the link number and initialize another link if the link number is above zero. The next link repeats the process until the link number reaches zero. The instance variable previous (more explicitly called self.previous) is initially set to NULL, but if the link has been created by a parent link, it will manually set next.previous to self, which alone is a slightly confusing statement. Clean up works similarly:
- (void)releaseLink
{
if(next)
{
[next releaseLink];
[next release];
}
}
One link will call the next to release its link, which will then call to release its next link, etc. No object actually releases the self.next object until it has told its own link to do the same, so all the releases actually cascade down. The whole thing can be unravelled with two lines:
[myNewChain releaseLink]; [myNewChain release];
Recursive programming is one of those things that’s crude is misused but elegant when done right. I’m not sure which the category the above falls under, but maybe it’s too bare bones to qualify yet. With the above setup, you lose some of the control that NSArray and its mutable counterpart provide. On the other hand, it’s probably leaner and faster at what it does if you don’t need all that control. Sorting is non-existent, inserting objects between links (or inserting any object at all that isn’t a Chain) becomes problematic, but its behaviour is just what I need right now.
Instruments: Building a Watertight App
Probably one of the main criticisms I’ve hear about iPhone applications is that they have a tendency to crash. This is not isolated just to bad applications, not that it helps. If I had to make a wild guess, I’d say the main cause of such crashes is memory leakage combined with the iPhone’s apparent 128MB of memory. Sure, on a desktop with several gigabytes kicking around, you could almost afford a few sloppy leaks (not that you should), but the iPhone offers no such padding. You don’t need a big leak either as long as it keeps growing; add to this that many non-Mac developers have no previous exposure to Cocoa’s alloc-retain-release methods and you’ve got an application ready to tank.
Instruments, part of the developer tools, has a crazily useful module called Leaks that does exactly what it advertises. It keeps track of all memory allocations and deallocations and lets you know where the outstanding balance is and which method it lives in. Although early optimization is considered be on par with supervillainy, leak detection is not optimization per se and I would recommend profiling for it early and regularly. Method calls will only get deeper and more tangled as time goes on. I was surprised to learn that my own code had nine leaks, nine. That’s nine more than I was hoping for. I’ve cut it down to a single 3.5KB leak thanks to Instruments, and while that may not seem like much, I’m going to find and nuke that 3.5KB before the night is over.
Mirror, flip, inverse, invert, stop drop and roll
Not having much to compare it to, I can’t honestly say how well the developer documentation stacks up against those available on other platforms. It certainly serves me well enough, and is worlds apart from what came with MPW. The day that MPW finally started working was a small miracle; this was before Google had an answer to just about everything (great instructional video too), and most libraries assumed you were using CodeWarrior anyway. At any rate, the reason for today’s post: for everything not spelled out by the developer docs, there’s Google.
After spending a good hour trying to trackdown a [UIImage reverse] method (there is none), I’ve boiled it down to a working block of code. Best of all, it’s short! So here’s to you, Googlers, I’m putting it on the internet in hopes that another dev finds it useful. The following snippet will horizontally reverse/flip/mirror a UIImageView:
UIImageView *myView = [[UIImageView alloc] initWithImage:myImage]; myView.transform = CGAffineTransformIdentity; myView.transform = CGAffineTransformMakeScale(-1.0, 1.0);
That’s it. To flip it back:
myView.transform = CGAffineTransformIdentity;
Not so scary anymore! So what’s going on here? Get your answers from a more authoritative source. It’s a good read about a powerful property, and highly recommended for anyone who doesn’t want to create two or ten different versions of the same image at different rotations.
