Comfy sofa, STAT!

Celebreight is celebrating!

Celebreightions from the party eight!

You’d better sit down for this. Ok, here it is. I’m going to tell it to you straight, I owe you that. I won’t pussy-foot around, beat around the bush, procrastinate or generally dance around the issue. I am going to go in deep, now, and get to the point without any dilly dallying. Ok, here we go. Ready? Comfy? Could I get you a tea first? No? Right. Honestly, you’re not going to believe this. Set your face to stunned:

I have made some progress on my iPhone game.

Wooooaaah, there, careful, I did tell you to sit down. Not much progress, granted, but thanks to Baby Cobra sleep, a late train, being deserted by my train friends a couple of times (fine, they all had excuses, but I choose to feel deserted for dramatic effect) and an evening or two’s button pressing I have managed to fit in a staggering eight hours of progress. Yupperillo, that’s a day’s worth of achievement. The classic cobra-artist’s rendition of the Celebreight, to the right, is there to bang in just how magnificent this occasion is. It is, in fact, to a reasonable approximation, infinity times more progress than was made between May 2011 and the start of June 2012 so you can understand my excitement. Let’s run the numbers through the Progressatronic-6000 Deluxe Schedulometer and see what pops out:

Estimated total project duration: 4 months with a month’s contingency
Start date: March 2010
Total progress so far: Three weeks, 1 day
Total progress since last update: Eight hours!
Estimated completion date: Possibly inside my life-time!

I is lerrning fings

The progress has mainly been with the map editor. This is now pretty much finished. I had to make a lot of adjustments and I rewrote large chunks of it. It’s now slim, fast, reliable and is almost certainly in better health than I am. I learnt a lot, including:

  • OpenGL for the map editor was a poor choice. I used it because it got things going quickly: I had an OpenGL rendering engine for the game itself and it compiled and worked under OSX pretty much first time. I simply changed a few “UIxxx” classes to “NSxxx” and Bob’s my uncle. However, given I’m rendering some lines, circles, text and blocks in a non-performance sensitive 2D environment, OpenGL is massively over-complicated. It’s like ordering a fleet of taxis so that each of the items in my bag can be carried to the station separately. More on this in a bit.
  • C++ 11 is g-g-g-grrrrreat, but needs iOS 5 as a target. It’s amazing how quickly you get used to the little time-savers that C++ 11 offers you. I love the range based for-loops. I adore the little touches like auto (type inference) and scoped enums. std::initialiser_list makes me warm inside. The ability to delete the automatically generated things like copy constructors and what-nots from your classes to better help the compiler to help you not fuck things up by accident is sex on wheels. These features have seeped into my standard day-to-day programming and I feel naked (but not greased up) without them. Learning that I need to target my iPhone game at iOS 5 to use these features was a minor disappointment but won’t really have any impact given we’ll be on iOS 42.6 by the time I’m done.
  • If you need 0,0 at the top left, it’s easy. You need to do two things. One is add the one line of code I added in last month’s update and the other is to flip your NSImages that contain the stuff you’re rendering onto the NSView otherwise they render upside down. You do that like this:
    NSImage* blocksImage = [[NSImage alloc] initWithContentsOfFile:@"My_Awesome_Image"];	
    [blocksImage setFlipped:YES];

    This works in concert with NSView’s isFlipped { return YES; } jazzamatazz.

  • Sprite-sheets using NSImage are easy-peasy! Despite an uncharacteristically unhelpful answer on Stack Overflow1, it is easy to render sprites from an NSImage sprite sheet. Quite why anyone would even suggest cutting out the individual images perplexes me, but perhaps that individual enjoys making huge amounts of unnecessary work for themselves. Here’s some code that does it:
    // Target rect is the NSView screen position. Shrink 'targetBlockSize' to
    // do neat scaling:
    NSRect targetRect;
    targetRect.origin.x = x;
    targetRect.origin.y = y;
    targetRect.size.width = targetBlockSize;
    targetRect.size.height = targetBlockSize;
    //
    // Source rect is on the sprite sheet. This assumes that the sheet is 8 x 8 of
    // 64 x 64 sprites. "blockIndex" is a 0 -> X index of which sprite we want.
    NSRect sourceRect;
    sourceRect.origin.x = (float)((blockIndex % 8) * 64);
    sourceRect.origin.y = (float)((blockIndex / 8) * 64);
    sourceRect.size.width = 64.0f;
    sourceRect.size.height = 64.0f;
    //
    // Draw block and selection rectangle if required. *This* is the magic line:
    [blocksImage drawInRect:targetRect 
                   fromRect:sourceRect 
                  operation:NSCompositeCopy 
                   fraction:1.0];
    if (blockIndex == (unsigned int)selectedBlockIndex)
    {
    	// This just shows a yellow un-filled rectangle around the block that's the
    	// selected one:
    	[[NSColor yellowColor] setStroke];
    	targetRect.origin.x += 1.0f;
    	targetRect.origin.y += 1.0f;
    	targetRect.size.width -= 2.0f;
    	targetRect.size.height -= 2.0f;
    	[NSBezierPath strokeRect:targetRect];
    }	// if (this was the selected block)
    

    The magic there was done with NSImage’s drawInRect. You can also use this to scale the target – I use it in the editor to allow zoom and “small mode” for the map block choice. In a nutshell, it lets you take a rectangle of your choice out of your source NSImage and blit it to a target rectangle of your choice in your NSView. Nice, eh? Well, I thought it was.

  • Fat fingers are fat. Yeah, and that means yours too. When you press on the simulator, you do so with a mouse pointer. If you detect presses as being a touch down followed by a touch up with no dragging between the two, that code will work wonderfully in the simulator. On the device, however, your fingers are not as accurate. You need to have a threshold of movement that doesn’t count as a drag by still counts as a press. I realised this after friends trying my prototype on my iPhone had all sorts of difficulties. My “well, it works on the simulator” is not a helpful response and just leads to a conversation that ends with “are you saying my fingers are fat?”
  • Tags are great! If you have a whole stack of checkboxes, how do you tell them apart? Up until now I was either 1) linking an outlet to each control and doing the comparison to sender in a single IBAction or 2) have an IBAction for each button. On Win32, I’d have hidden an ID in GWL_USERDATA and avoided both of these pox riddled solutions. Turns out, of course, Cocoa has an equivalent but it’s called something different: the ‘tag’. You can set this in IB and read it in a single IBAction dispatcher with code like if (1 == [sender tag]) { yodel_continuously(); } I’m kicking myself for not knowing this before given how long I’ve been Cocoaing but better late than never.
  • Tool windows need to accept first mouse. The utility windows in the editor needed one click to activate and another to do something. This is an awful user experience in an editor, particularly with the block selection view. What I was missing was this little piece of code in the relevant views:
    -(BOOL)acceptsFirstMouse:(NSEvent *)theEvent
    {
    	return (YES);
    }

    With this, everything worked as I expected.


The net result of all this is something that looks pretty good. Here’s a poorly taken screenshot of a poorly designed level I was testing with recently:

Map Editor June 2012

I’m not quite ready to say what the game is all about or what it is called, but soon. Of course, with my two readers, it’s not as if I’m leaking anything substantial, it’s just a… thing.

Note the class-A program icon bottom left. I drew that. I’m so proud. EGADASI2 (pronounced ‘eggadassie’) as only I say after close to the LD50 of wine.

A cake was involved

The icing on the cake (oh, and I baked a cake. Not as good as this one but any cake is a win) with this update is that the levels in this editor can be now loaded and played in the game itself. The game code was a bit messy, which is not enormously surprising given how long ago the core of it was written and what I knew about Cocoa at the time, and I’ve had to spend some time chopping down the weeds before I can plant anything nice but they are playable. I’ve fixed some issues, tidied some bits and pieces and generally brushed away some code cobwebs in preparation for the remaining features.

What are the things left before I have an actual product I could possibly stick on the App Store? Quite a lot, unfortunately:

  • A whole stack of graphics. Mostly glue graphics: splash screens, menu panels, etc., but also some additional blocks and entities.
  • Some sound. I need some sound effects and perhaps the odd little jingle for start of level, end of level and the title screen.
  • Levels, lots of levels! I really need a good twenty levels to feel comfortable about having a first release. I have two so far. Yes, two. But at least I have a half decent editor now.
  • Some code. The engine needs bad guys code, parallax rejigging, game centre integration and a whole pile of little things. About three week’s worth of little things, in fact.

I don’t quite know how I’m going to get all this done given I can only really pay in roast dinners and wine these days. As delicious as they both are, they don’t pay people’s bills. I’m sure I’ll come up with something, though, and it does at least feel good to have made progress and to make an update that doesn’t involve a comprehensive package of excuses.

Yey!

1 I must get around to creating an account there. Given how much time I spend on Stack Overflow and how important it has become it seems offish for me not to contribute on the rare occasion that I feel that I can.
2 Every Good Application Deserves A Splendid Icon

This entry was posted in My iPhone game and tagged , , , , , , , . Bookmark the permalink.

Comments are closed.