Saturday, December 25, 2010

Cocos2D support new and old devices textures

Got a new iPhone game project going - an opportunity to learn some new things which is always fun.
I am using the cocos2d framework, which really saves me a lot of work.
I still would like to get deeper into OpenGL ES some time later, but for this project it will be enough to have cocos2d handle the low level details.

One issue I struggled with is that I need to create fairly detailed animation of the scene background.

Due to the limit on OpenGL ES texture size (especially on older devices where the texture is limited to 1024x1024 pixels), I am faced with two options:

  • Limit the number of frames (In a 1024x1024 texture I can get 9 frames of size 320x340 which is the size of my background area in the game).
  • Construct the background area from multiple animations and compose them programmatically. While possible, this makes the design work more cumbersome as the designer needs to supply the needed graphics and their location.
Using a larger texture size of 2048x2048 gives me enough room for 36 frames, which is sufficient for quite a nice background animation loop, but should I give up all older devices (prior to iPhone 3Gs)?

There are millions of those!

So this leads me to the current solution I am going to use, which is:

Use a 2048x2048 texture for newer devices, and substitute that for a smaller 1024x1024 texture on older devices in run time.

But how should I decide which texture to use?

Well, I will save you all my google searches, as the answer was found right under my nose:

Cocos2d CCConfiguration class!

Here's the code:

    NSString *plistFile;
    int numFrames;
    if ([[CCConfiguration sharedConfiguration] maxTextureSize] < 2048)
    {
        plistFile = @"highQualityAnimation.plist"];
        numFrames = 36;
    }
    else
    {
        plistFile = @"highQualityAnimation.plist"];
        numFrames = 9;
    }
   
    // cache the frames to the sharedSpriteFrameCache
   
    CCSpriteFrameCache * cache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [cache addSpriteFramesWithFile:plistFile];

    // create the animation
    CCAnimation * animation = [[CCAnimation alloc] initWithName:@"animation" delay:0.1];    // set the frame rate as needed
    for ( int i=1; i <= numFrames; ++i )
    {
        NSString * fname = [NSString stringWithFormat:@"animation_frame_%i.png", i];
        [animation addFrame:[cache spriteFrameByName: fname]];
    }

    CCSprite *backgroundSprite = [CCSprite spriteWithSpriteFrameName:[NSString stringWithFormat:@"animation_frame_1.png"]];
    id action = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
    [backgroundSprite runAction:action];

    // add the sprite to the scene layer

    [self addChild:backgroundSprite];

That's easy enough, gives good animation on newer devices, and still reasonably support for older devices.

Saturday, December 18, 2010

Easily making the different size icons for iPhone and iPad

This is a small tip for scaling your icon to the different sizes requested by iPhone and iPad applications. I used to do that with Photoshop actions in the past, but if that is not available, you can use this tip with no extra software using Mac OS X Automator:
1. I Start with a high quality 512x512 png file (which you will later rename to iTunesArtwork without the png extension) as this is needed for the App Store.
2. In Automator, create a new Service and add the following steps:
Save this service as iPhoneIcon (or icon57, or whatever).
3. Similarly, make services for the different sizes as listed here:
Icon-72.png (72x72)
Icon@2x.png (114x114)
Icon-Small.png (29x29)
Icon-Small-50.png (50x50)
Icon-Small@2x.png (58x58)
4. Now place your 512 icon in a folder, in the finder, right-click the icon file and select from the services sub-menu the different services, and voila! you got the scaled icon with the right name.
5. Add to your project resources and you are ready to go...

Saturday, December 4, 2010

File Names are Case Sensitive!

Urrrrrrgggggghhhh. Spent two days debugging an issue where my program works well on the simulator, but not on a device. I was debugging directory creations, file createions, file permissions in an attempt to find why a dwnloaded file could not be read. I am downloading a zip file from a server, and unzip it into a sub-directory of the Documents directory of my app.
I used PhoneDisk to look at the file system - all hierarchy is created and it seems the file I am trying to read is there too.
After two days of debugging and trying all kind of things, getting file not find errors, I finally realized that the file is named "File.ini" while I was trying to read "file.ini".
This works fine on the simulator, but not on the device where all file names are case sensitive.
I feel stupid, but at least fixed the bug....

Saturday, November 20, 2010

TTURLRequest tracking download progress

OK, I needed to present a progress bar while downloading a fairly large file to my app.
This presented three challanges:
1. Presenting a progress bar. Well, with three20 this is real easy - I created a view controller that is presented modally and used the Three20 ActivityLabel:
- (void) loadView
{
    [super loadView];
    _downloadProgressLabel = [[TTActivityLabel alloc] initWithStyle:TTActivityLabelStyleBlackBezel];
    _downloadProgressLabel.progress = _progress;
    _downloadProgressLabel.text = @"Downloading My File...";
    [_downloadProgressLabel sizeToFit];
    _downloadProgressLabel.center = self.view.center;
    [self.view addSubview:_downloadProgressLabel];
}

- (void) setProgress:(float)inProgress
{
    _progress = inProgress;
    _downloadProgressLabel.progress = _progress;
}

2. Getting the progress from an asynchronous TTURLRequest. Well, the TTURLRequestDelegate protocol has a method called requestDidUploadData, but this is only used by uploads (POST with some body). Well, thought I will implement something, but a quick google search found me that: https://github.com/facebook/three20/pull/288
So, I was not the first to tackle this... thanks Cemal Eker!

3. After implementing this, I still had an issue. I found out that I made a stupid mistake. I was waiting in a loop for the request to finish doing [NSThread sleepForTimeInterval:0.5]. This caused both the URLRequest to not function as well as my view controller to not show up..
So, don't do that, you are going to get a requestDidFinish in your delegate, so no need to sit in a loop...

Thursday, October 21, 2010

Sizing a launcher item image in Three20

Recently I got deeper into iPhone (or iOS) programming, doing some projects for fun and for fee.
My friend Reuven wanted me to use a framework called Three20 in the context of a project I am doing for XMPie, but the person who really pushed me into it is Yosi Taguri of fiddme.com who gave me a crash course on Three20.
So, I am working now on converting the XMPie project to Three20, and I spent the last couple of hours on trying to get the launcher view work with some images that are of unknown sizes. I initially thought I will have to sub-class the launcher view and all its related classes (TTLauncherItem, TTLauncherButton), but this is of course the wrong way of doing things in Three20...
There is a better way which is to use the stylesheet mechansim of Three20. I read the tutorial by Matt Vague (Three20 stylesheets tutorial), but it was not enough to get what I wanted.
What really helped me figure this one out is a tool named TTStyleBuilder by a guy named Keith Lazuka.
finally I was able to create the following style in my stylesheet to get the images to behave:

- (TTStyle*)launcherButtonXM:(UIControlState)state {
    return
    [TTPartStyle styleWithName:@"image" style: TTSTYLESTATE(launcherButtonImageXM:, state) next:
     
     [TTTextStyle styleWithFont:[UIFont boldSystemFontOfSize:11] color:RGBCOLOR(180, 180,180)
                minimumFontSize:11 shadowColor:nil shadowOffset:CGSizeZero
                  textAlignment:UITextAlignmentCenter verticalAlignment:UIControlContentVerticalAlignmentBottom
                  lineBreakMode:UILineBreakModeClip numberOfLines:1 next:nil]];
}

// Our launcher button image style
- (TTStyle*)launcherButtonImageXM:(UIControlState)state {

    TTStyle* style =
     [TTShapeStyle styleWithShape:[TTRoundedRectangleShape
                                   shapeWithRadius:8] next:
      [TTBoxStyle styleWithMargin:UIEdgeInsetsMake(0, 0, 0, 0)
                          padding:UIEdgeInsetsMake(22, 22, 22, 22)
                          minSize:CGSizeMake(0, 0)
                         position:TTPositionStatic next:
          [TTImageStyle styleWithImageURL:nil defaultImage:nil contentMode:UIViewContentModeScaleAspectFit
                                     size:CGSizeMake(57, 57) next:nil
      ]]];

    if (state == UIControlStateHighlighted || state == UIControlStateSelected) {
        [style addStyle:
         [TTBlendStyle styleWithBlend:kCGBlendModeSourceAtop next:
          [TTSolidFillStyle styleWithColor:RGBACOLOR(0,0,0,0.5) next:nil]]];
    }
   
    return style;
}


You use this style in the launcher by setting the style property of the launcher item:

        launcherItem.style = @"launcherButtonXM:";
        [_launcherView addItem:launcherItem animated:YES];

Three20 is cool!

[Edit] Based on some questions I got, I want to clarify that the style methods above are placed in my XMDefaultStyleSheet which is defined as an inherited class of TTDefaultStyleSheet. I create an instance of this class and set it as the default style sheet in the App Delegate applicationDidFinishLaunching method like that:

    // register our stylesheet
    [TTStyleSheet setGlobalStyleSheet:[[[XMPDefaultStylesheet alloc] init] autorelease]];

Tuesday, July 20, 2010

Startup weekend Tel Aviv Jaffa

Just got back from three days of fun at the startup weekend event in the Peres Center for Peace in Jaffa. It was nice to see a nice Palestinian group joining together their fellow Israeli entrepreneurs and working together to create cool and useful start ups. Compared to the previous event, I felt this time there were more "real" ideas and very high level execution and presentation. I joined a team where we developed an iPhone game for blind people. The game "son of zato" allows blind people to aim and shoot at virtual monsters using audio directional signals. It was great fun!




- Posted using BlogPress from my iPad

Friday, July 9, 2010

Birthday Present

My beloved wife is celebrating birthday tomorrow and I just found the right present:
Three Men In A Boat - in audio book format. It is also available for download from Audible.

She used to have that on cassette tape, and this is no longer playable...

Hope she will be happy...


Happy Birthday Love!

Thursday, July 1, 2010

Art Experiment of the week

This week I had some great tasting cherries. I went through a dozen watching TV, and placed the stones on a piece of paper. The stones with some left over from the cherries, created some blood colored stains on the paper. A light bulb turned on over my head... "Aha", I thought, lets try painting with cherries...
 So here is the first attempt of cheery-paint (not sure you can see the details in this scan, and I am not too happy about it yet. I plan to try some more - so stay tuned...):

Friday, June 18, 2010

Trying Windows Live Writer

I am “forced” to work on my windows laptop as I am working on a huge tender response that includes many technological systems, suppliers, integration and so on. I started working on the project using my MacBook with Open Office, but that created quite a mess as the rest of the companies and my client are using Windows and Microsoft Office. So, I had to go and get a laptop with Windows 7 on it. I went to the local computer store, and asked “here’s what I need, what do you have in stock?” – so I got a Dell Inspiron which I am absolutely OK with.
Now, this tender is a bit special in that the technological part of it is being reviewed by the government using a “flexible procedure” – meaning that this part is not given score, but the government can get back to us with more questions, requests for clarifications, etc. This means I am already working on the fourth iteration. Now, this time the committee inspecting our proposals warned us that “this is the last round” and that they will not issue any more – so we should really try to provide the best answers. The deadline is next Thursday… And, I am flying for a week to Italy….
So, I am working feverishly to try and prepare all the materials for my client, so they can take over preparing the response while I am away. But they still insist I take my laptop with me to Italy in case they will have some questions for me. I originally planned to be completely disconnected from the world while on vacation, but life sometimes makes other decisions for us…
Anyway, trying to make the situation have some positive side, I thought I will also use the laptop to write some blog posts from Tuscany…
As I don’t expect to have regular internet connection in the rural areas of Tuscany, I searched for some offline blogging tools, and I found out that I already have one installed – which is Windows Live Writer. So here I am giving it a try before I pack to see if this works for me…
Here's the area we will be in:

View Perugia in a larger map


Tuesday, June 15, 2010

Test post from iPad

OK, trying to write my first post using BlogPress on the iPad. First impression is that the iPad on-screen keyboard is quite usable. Well until you want an hyphen or other mark not on the main keyboard. But who cares of those little marks.... Being a (very) new blogger, I do not have much experience but clearly for blogging on the run this Is more than enough. You can always go back and make it prettier when you get back home or to an internet cafe. There is no fancy editor. Pretty much simple text, but there is an option to add pictures. So here is one...



I am even able to add some text below it as you can see..

- Posted using BlogPress from my iPad

Saturday, June 12, 2010

The pleasure of simple things

Sometimes preparing food, washing dishes, doing the laundry, folding, ironing and watering the garden can be real joy. Here's how I do it: I get a portable music device (I am using a mobile phone with mp3 player, but you can use iPod, mp3 player, etc. - no shortage of music sources), load it with some good music and let it shuffle play...
I call it chores-yoga and I really love it.
If your device has enough music on it, from all periods and genres, it can be a real pleasure to let it shuffle and get surprised with a song you forgot you even had in your collection.
I find myself completely isolated from the world, from the news, from any worries, concentrating on the task at hand, enjoying the music and getting work done...
Some people can listen to music while they work. As my work often needs my full attention, I find it too distracting often, but with the daily chores - it is just perfect!
As I write this post, my player just surprsied me now with the "I hear a Rhapsody" played by Bill Evans and Jim Hall from their Undercurrent CD - what a great piece! Can bring me to tears...

Here's a self portrait I made:
















"Self Portrait as a cat" - 2010


You can get the Bill Evans and Jim Hall "Undercurrent CD" from Amazon: