A Short Path Short Update

Above is a quick and dirty screen cast of the current state of Short Path.  Mike Berg has been sprinkling his awesome dust around on the graphics and really making everything look great.  A few tweaks to the highlight animations and everything is looking far better than I’d imagined.

There is still a bit of polish to do, but its getting close(r) to submit time!!

If you aren’t familiar with Mike’s work, take a look here and be sure to check this out too.

The Shortest Path

ShortPath is getting close to being done.  (That said, an argument can be made that it *is* done and should be released. )

So while I’m fixing, ahem, refactoring code to address a couple of unintended features, here is a screenshot of a completed level

For those that I haven’t shared the game with at some point over the summer (is there anyone left?), the game challenge is connecting all of the locations with the shortest round trip.  A level is complete when you have found a path that visits all of the locations that is as short as (or shorter than) the path that your iPad has found.

After you have completed a level, a new level is generated with additional locations added into the mix.   There are also hints available that will give you a clue into missing or un-needed paths.

There will be multiple themes available for purchase so that you can dress up the app with different backgrounds and locations for a more personalized game play experience.

The idea for this has been rattling around in my head for several years dating back to grad school work I did on the Traveling Salesman Problem.  I was really pleased to find that some of my TSP solver code using a genetic algorithm still compiled — unfortunately, the code was too bulky and slow (and too often wrong for small sets of verticies) that I had to chuck it and write a new solver using other methods.  Nonetheless, it was fun revisiting this old problem and (hopefully) turning it into something that everyone can enjoy.

I should also mention that I’m super excited that Mike Berg (@WeHeartGames) has agreed to help me out with some of the graphics too!  Mike is a talented graphics designer out of Winnipeg.  If you aren’t familiar with his work, you should check him out.  Great stuff!

p.s. If you’d like to beta test prior to the first release to the AppStore, drop me a note (tom@<this domain> or @tomhoag)

Button Image Creation via Core Graphics & Image Masks

For the next app coming from the Cluebucket, I’ll be implementing a theme manager that will manage how the game appears using themes that the user will download from the AppStore.

Among other things, a theme will define which fonts are used in the UI, images and colors.  Initially, I had even gone so far as to use the theme to define images that would appear on UIButtons.  After putting together a few test themes everything seemed to be working fine, but it felt that defining button images was going a bit too far.

The original thought behind having a theme define button images was giving the graphics designer the capability to define adequate contrast between the background image (defined by the theme) and a few of the standard buttons (help button, next level, previous level) that would appear on the background.   This also allowed the GD to define a different look and feel for the buttons to integrate them more nicely with the theme. (Triangles on a geometric theme, hearts on a Valentines theme)

After some testing, it turned out that some buttons should just look the same from theme to theme. It keeps the user experience more consistent (the help button should look like the same help button no mater which theme the user is using).  I decided that the buttons would look the same from theme to theme — the only difference between themes would be the color of the image on the button.  No problem: I’ll just make a black version and a white version.  After all that worked fine for the info button on the iPhone.  Right??

Maybe so, but it felt like there could be some middle ground.  The GD should have some freedom to color the button to match the theme.  That cool Halloween theme on the drawing board might look just fine with a black help button and the Valentines theme might look just fine with a white help button, but the Pirate theme?  White doesn’t look good.  Neither does black.  What we need here is a nice chartreuse.

Core Graphics to the rescue!

So here’s what I did.  I defined the standard help button and created a black and white png — this will act as the mask to which I will apply a custom color (help button image mask to the left).  After applying the custom color (as defined by the GD in the theme definition), I can return a UIImage that can be scaled appropriately and put onto the help button.

The code to get it done:

First create a rectangular image that is the same size as your image mask:

- (UIImage *) createBackgroundImageWithColor:(UIColor *)color andSize:(CGSize)size {

  UIGraphicsBeginImageContext(size); // create a new context to draw in

  CGContextRef c = UIGraphicsGetCurrentContext(); // get a reference to the context

  CGContextSetFillColorWithColor(c, [color CGColor]); // set the fill color of the context

  CGContextFillRect(c, CGRectMake(0.0, 0.0, size.width, size.height)); // draw a rect to fill the context

  UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // and create an image from the context

  CGContextRelease(c); // don't forget to release the context reference!

  return image; // return an autoreleased UIImage
}

Now create a new image using the image created above and your mask image:

- (UIImage *) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {

  CGImageRef maskRef = maskImage.CGImage; // get an imageRef for the maskImage

  CGImageRef theMask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false); // create a mask out of the maskRef

  // create the maskedImage using another fance CG function
  CGImageRef maskedImage = CGImageCreateWithMask([image CGImage], theMask);

  // create the image that will be returned
  UIImage *returnImage = [UIImage imageWithCGImage:maskedImage];

  // release any references that were created
  CGImageRelease(theMask);

  return returnImage; // return the autoreleased masked image
}

Finally, the theme manager uses the above methods to return the appropriate images for various images in the theme. (OK, maybe not various, but certainly for the help button, next level and previous level buttons).

- (UIImage *) buttonImageUsingImageMaskNamed:(NSString *)imageName {
  UIImage *mask = [UIImage imageNamed:imageName];
  return [self maskImage:[self createBackgroundImageWithColor:[self buttonColor] andSize:mask.size] withMask:mask];
}

- (UIImage *) helpButtonImage {
  return [self buttonImageUsingImageMaskNamed:@"helpbuttonmask.png"];
}

- (UIImage *) nextLevelButtonImage {
  return [self buttonImageUsingImageMaskNamed:@"nextLevelButtonMask.png"];
}

- (UIImage *) previousLevelButtonImage {
  return [self buttonImageUsingImageMaskNamed:@"previousLevelButtonMask.png"];
}

Final Thoughts

So what have I gained here? I think that I’ve struck a balance in theme definition that allows me to keep some control over what a theme looks like and some of the user interface and experience.  I’ve allowed the theme designer some latitude in choosing the right color for the buttons.

And it provided a nice opportunity to use a bit of CG in this project :-)

P.S.

The masking image doesn’t have to be only black and white — you can use shades of gray as well.  Black will not mask at all, white masks 100% and shades of gray mask according to their intensity. It is important that your masking image have no alpha channel.

Cisco VPN uninstall on OS X

I don’t know for certain that the Cisco VPN Client has been responsible for all of my networking weirdness of late, but I do know that it was constantly writing messages to the console — even when I’m not using it.

I no longer need it and don’t want it — so here’s how to get rid of it:

sudo /usr/local/bin/vpn_uninstall

Simple, huh?

FiveStars

FiveStars

I had some spare time earlier this week and took the opportunity to get to know Core Graphics.  Its been a real treat as CG offers a lot of power but it takes some getting used to.

I’d been thinking for some time that a star rating widget for iPhone apps might be useful — so that became the target implementation of my CG journey.  At right is the FiveStar widget in action.  What you can’t tell from the image is that using the slider will change the value and display of the widget.  Using the slider allows the user to select fractional stars.

The user can also use a finger swipe to change the displayed value — in this mode, only whole stars can be ’selected’.

I set out to create this widget without the use of any image files — for a couple reasons:

  • I wanted to be able to add other ’shapes’ without having to create new graphics in PS everytime I wanted a new “shape” to use for my stars (i.e. circles, squares, palm trees)
  • I wanted to see if CG was fast enough to do the job (I’m not sure what that exactly means other than “doesn’t interfere with a pleasant user experience”)
  • I wanted to have the ability to display ‘fractional’ stars — using an image based solution might have required that I create several fractional images.

Initially, I had set out to only display stars either filled with one of two solid colors — one to represent a ‘used’ star and the other to represent an ‘unused’ star.  That is, if the widget were to be displaying a rating of three stars, I wanted to see the first three (from left to right) filled with one color and the remaining two filled with another color.

This turns out not to be terribly difficult in CG — simply draw a path in a graphics context and then stroke and fill the path.  Once you have a stroked and filled path, you create a CGImageRef from your context and from the CGImageRef you can create the familiar UIImage. (I should note that while drawing paths is simple in CG, generating the path my not be as easy — I had to reach way back into high school geometry to come up with a nifty algorithm to create my star path.

Creating fractional stars turns out to not be too difficult either — I simply created a filled star, clipped it with a rectangle of the appropriate size to capture the desired “fraction” of the star and then overlayed that clipped image onto the image of an unfilled star.

Once I (kind of) had the hang of that, I ventured into creating reflections.  I got a huge head start on this part by examining the code in Apple’s TheElements sample project.  The net of creating the effect is to invert the image to be reflected, clip the part of the image to show in the reflection and then apply a gradient (gray scale only!).

Finally, I ventured into creating a colored gradient for the stars — turns out to be pretty straight forward as well.  Using the original path for the star to clip the CGContext and then apply a gradient to the context.  The gradient will only appear in the clipped portion of the context.  Next, add the path back in and stroke it (don’t fill it — you’ll lose the gradient!)

I packaged the whole FiveStars widget up into a static library so that I can drop it into various projects.  The project I’ve linked to below was used to create the screenshot above. Note that there are two different instantiations of the widget — the large one uses a gradient fill and has a reflection.  The instantiation used in the table is a simple fill with no gradient and no reflection — and there is no user interaction in the table — they are ‘read only’.

Here’s a quick video of a FiveStars demo to give you a better idea of what’s going on, and what the widget can do.

I’d love to hear your thoughts, please leave a comment!

Windbuoy 2.0 Available Now in the AppStore

It’s been a long time coming, but the Windbuoy app has been updated.  Many user suggestions and features now possible with the latest SDK have been incorprated into the app.  Some of the new features include

  • Maps!  View and search for buoys on a map.  Search by ZIP, Buoy ID or location and see the results in a list or on a map
  • When searching by location, you can drag the location pin around on the map and search again.  No ZIP code 50 miles off Key West?  Don’t remember the ID of that station?  No problem.  Start a location search and recenter the location and touch the ‘Search’ button on the location annotation.
  • Historical Data — When viewing a station in portrait mode, turn your iPhone sideways to see the most recent readings and the trends.

Windbuoy 2.0 is available in the iTunes AppStore

Pazzi Launched! (also, promo codes)

Pazzi has been approved and is now available in the App Store. Pazzi is a great little tile game that challenges you to tip (or push) the tiles into groups of two or more and move them off the edge of the board. Addictively simple.

Here are a few promo codes free to first ones here.  (Please, one per reader).  If you miss out and really, really need to have a promo code, leave a comment or drop me a line and plead your case ;-)

XRNRY66L4FPT
W9XJTTTAKTR3
KK4X49EXX66P
FF36M9TK3MTL
X6PT4KNRHWX9

Look Ma! No Scrollbars!

I’ve been refreshing the Windbuoy app to make the UI just a bit more of a familiar user expeirence with respect to iPhone app standards. If you aren’t familiar with the Windbuoy app, it retrieves wind and weather info for NOAA buoys. Each buoy’s info is presented one at a time on a single UIView. The user “moves” from buoy to buoy by swiping across the UIView. The UIView does not slide off screen with a new one sliding in. Instead the info on the UIView is just updated; albeit with some animated alpha values. It works. But its not very pretty.

So I recently started down the path to make each buoy appear on a new (or recycled) UIView and as the user swipes across the UI, a new buoy UIView slides in as the old one slides out. Nifty. Sort of. I implemented this behavior using the advice found on the interwebs: “implement using a scroll view”. So I did.  In the end, it worked and looks pretty good, but I felt like it could be better.

Read the rest of this entry »

App Localization & Internatinalization

Wil Shipley has written a post on app localization and internationalization — and the pitfalls assoicated with each. A very good read. Also, free code to get it done.

Upgrading iPhone Apps

The Tweetie 2 upgrade discussion has me thinking about how I’m going to handle the next rev of the Windbuoy application.  (btw — a decent interview of  Loren Brichter — Tweeite dev –  by PatrickJ seems to have brought this mostly to conclusion — we still have to see how the App Store market reacts) .  While I’m not a full time app developer, I’m tending to lean that way and this issue has been one that has given me great pause.

For app development to be a sustainable endeavor, developing apps has got to provide an income stream.  I don’t believe its fair to app users to release an app and never make any upgrades.  On the other hand, the App Store doesn’t currently offer any great incentive to keep apps upgraded — upgrades are free.

Which brings me to Windbuoy. Windbuoy has been humming along and although there have been negative reviews from primarily from folks that don’t understand where the data comes from, it’s been largely successful in a small niche kinda way.  It does have a few shortcomings that I’d like to make changes to, but there’s just not much incentive to do so.

Now that Pazzi has been submitted for review, I’ve started thinking about some of the things that I’d like to change for Windbuoy — I’ve received a few ideas from users and with the release of the 3.0 SDK, there are other interesting features that can be integrated as well (e.g. Maps).  Looking at the code behind it, I find that there is a *lot* that I’d like to change about Windbuoy. :-)   So it looks like its going to be a big rewrite for Windbuoy.

Read the rest of this entry »