Wednesday, November 30, 2011

Growing your revenues in new markets


As we indie developers struggle to get our apps noticed, downloaded, used and pay our bills, we should maximize whatever means we have to get the app available to as many users.
One often neglected direction is localizing your app to serve users in non-English speaking countries.
Publishing your app in a local language can open for you new markets and maximize your revenues, and the effort needed is really not that great.

There are three parts for making your app available in multiple languages:

Design Time

While at the design and conception stage of your app, give some thoughts to issues such as:

  • Using text vs. using images for buttons, menus or other app elements. Using images gives you more flexibility as to the appearance, fonts, effects of your app text. Using strings makes it easier to change your texts or localize them.
  • Using special fonts which may or may not have the characters you need in foreign languages. If you did decide to use strings, and opt for using custom fonts, make sure the font has the characters for all the languages you want to support. In many cases it is simpler to use unicode fonts from the set of built-in fonts, but sometimes you do need a custom font to get that special look. Keep the character set issue in your thoughts.
  • Designing for variable size strings for labels or other GUI elements. Text may change size when you switch to a different langauage - width, height and in some cases number of lines will have to be flexible. At the design stage just keep this in mind, and allow your self room for flexibility
Development

During development, you should follow Apple guidelines for localization. Refrain from using hard coded text strings, and go for the NSLocalizedString, localized resources, etc.
Also bear in mind the issue of text size and location. You can use NSString method sizeWithFont to get the dimension of text:


font = [UIFont fontWithName:name size:size];
if( font )
   CGSize dim = [string sizeWithFont:font];


Sean Berry published an excellent tutorial with examples on Ray Wanderlich's blog site: http://www.raywenderlich.com/2876/how-to-localize-an-iphone-app-tutorial

Translation

In many cases I found Google Translate sufficient (especially for languages I have some experience with), but a more professional approach which is not so expensive is available. I am recommending a service called One Hour Translation This service is very reasonably priced (around 5-10 cents per word) and the turn around time is phenomenal - I got all my translations within 30 minutes (!!!)
I have no way to judge the translation quality, but they do give you an option (for slightly more money) to use an expert translator for your particular domain, and an option to get the translation proof read by another person.

One Hour Translation

Wednesday, November 2, 2011

My Art and other interests

I decided to separate my art related posts and place them in a separate blog. You can check them here: http://sroolart.blogspot.com/
I also created a new blog for posts on social / technology / employment issues I am interested in here: http://societyredesigned.com/


The Knife (this blog) will be just about programming...

Tuesday, August 30, 2011

OpenGL ES alternate texture renderring

A friend asked me for help with getting the sample here: http://www.mat.ucsb.edu/a.forbes/blog/?p=245 to work on the iPhone.

Since I had no experience with OpenGL ES 2 shaders, I thought it would be a good chance to get my hands dirty and learn something about it. I am still not an expert (far from it), so take it all with healthy skepticism.

This is an interim report, just to let you know the basics are working and provide with the sample code.

So the code is available here: http://iroth.net/prog/PingPong.zip

In addition to the article that was the inspiration of this, I could have not made this work without the help of the great tutorials of Ray Wenderlich and in particular this series of two:
http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial
http://www.raywenderlich.com/4404/opengl-es-2-0-for-iphone-tutorial-part-2-textures

One more thing - there seems to be some black triangle artifact in the upper left corner I still was unable to understand. If any of you find out - please comment below...

And while at it, here are some books that really help me get up to speed on iPhone game programming:






Monday, June 13, 2011

Improved CCSlider included with Cocos2d iPhone Extensions

I was happy to get an email from Stepan Generalov asking for permission to publish an improved version he made of CCSlider under an MIT license, which I approved immediately. Good work Stepan!
You can find the improved CCSlider and other cool stuff here:
http://www.cocos2d-iphone.org/archives/1506

Thursday, March 24, 2011

Pah! is on the app store - the joy of iOS programming...

It is so much fun to create apps for iOS devices. The first time you get your code to run, the first reaction from other people, but the most fun is publishing your product on the app store and watching how the world reacts...

We just published today the first truely voice-activated game for the iPhone - it is called Pah! and it is guaranteed to make you look silly, and laugh hard (or at least make the people around you laugh), and is there a more nobel cause than to make people laugh??

The game idea and design are by Eyal Shahar, and programming was done by Yosi Taguri and myself.
Eyal implemented the game few years ago using Flash, and left it alone for a while, but when he showed us the game we laughed so hard, we knew we must make it into an iPhone game. The first working version was done in few hours, and then it took another two months or so of late night work to make it happen...

The game went up 18 hours ago, and the responses are overwhelming. Here are some:

http://www.mobilecrunch.com/2011/03/24/pah-iphone-game-mouth-sounds/

http://www.theiphoneguru.net/2011/03/24/app-of-the-day-pah-for-iphone-is-voice-activated-and-hilarity-inducing/

http://www.igoiphone.com/?p=1593

http://dailyapp.mobi/index.php/2011/03/pah-for-iphone/

Check our site too: http://ahhhpah.com/

I want to give credit here to the amazing Cocos2d framework that really is fun to work with...

Wednesday, January 5, 2011

Creating a Slider Control in cocos2d

I wanted to add a little slider control to allow the user to set the background music level in a game I am working on. So I created this little CCSliderControl class that I think is cute and useful.

The CCSliderControl is sub-classed from CCLayer. Here is the .h file for it:

 @protocol CCSliderControlDelegate  
 - (void) valueChanged: (float) value tag: (int) tag;  
 @end  
 @interface CCSliderControl : CCLayer {  
      float value;  
      id<CCSliderControlDelegate> delegate;  
      float minX;  
      float maxX;  
 }  
 @property (nonatomic, assign) float value;  
 @property (nonatomic, retain) id<CCSliderControlDelegate> delegate;  
 @end  

In the init of this class instance, I add two sprites - one for the background, and one for the slider thumb:

 -(id) init  
 {  
      if ((self = [super init]))  
      {  
           CCLOG(@"init %@", self);  
           self.isTouchEnabled = YES;  
           value = 0;  
           // add the slider background  
           CCSprite *bg = [CCSprite spriteWithFile:@"slider_background.png"]; //- TODO: add this to some texture atlas  
           [self setContentSize:[bg contentSize]];  
           bg.position = CGPointMake([bg contentSize].width / 2, [bg contentSize].height / 2);  
           [self addChild:bg];  
           // add the slider thumb  
           CGSize thumb_size;  
           CCSprite *thumb = [CCSprite spriteWithFile:@"slider_thumb.png"]; //- TODO: add this to some texture atlas  
           thumb_size = [thumb contentSize];  
           minX = thumb_size.width / 2;  
           maxX = [self contentSize].width - thumb_size.width / 2;  
           thumb.position = CGPointMake(minX, [self contentSize].height / 2);  
           [self addChild:thumb];  
      }  
      return self;  
 }  

The setValue method that sets the value property of the instance also updates the thumb sprite position:

- (void) setValue:(float) newValue
{
    if (newValue < 0) newValue = 0;
    if (newValue > 1.0) newValue = 1.0;
    value = newValue;
    CCSprite *thumb = (CCSprite *)[[self children] objectAtIndex:1];
    CGPoint pos = thumb.position;
    pos.x = minX + newValue * (maxX - minX);
    thumb.position = pos;
    
}

Next step is to register for touch events:

-(void) registerWithTouchDispatcher
{
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
}


and then handle the touch events:

-(CGPoint) locationFromTouch:(UITouch *)touch
{
    CGPoint touchLocation = [touch locationInView: [touch view]];
    touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
    CGRect bbox = [self boundingBox];
    touchLocation.x -= bbox.origin.x;
    touchLocation.y -= bbox.origin.y;
    return touchLocation;
}

-(bool) isTouchForMe:(CGPoint)touchLocation
{
    CCSprite *bg = (CCSprite *)[[self children] objectAtIndex:0];
    return CGRectContainsPoint([bg boundingBox], touchLocation);
}

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint location = [self locationFromTouch:touch];
    bool isTouchHandled = [self isTouchForMe:location];
    if (isTouchHandled) {
        CCSprite *thumb = (CCSprite *)[[self children] objectAtIndex:1];
        thumb.color = ccYELLOW;
        CGPoint pos = thumb.position;
        pos.x = location.x;
        thumb.position = pos;
    }
    return isTouchHandled; // YES for events I handle
}

-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint location = [self locationFromTouch:touch];
    if ((location.x < minX) || (location.x > maxX))
        return;

    CCSprite *thumb = (CCSprite *)[[self children] objectAtIndex:1];
    CGPoint pos = thumb.position;
    pos.x = location.x;
    thumb.position = pos;
}

-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
    CCSprite *thumb = (CCSprite *)[[self children] objectAtIndex:1];
    thumb.color = ccWHITE;
    value = (thumb.position.x - minX) / (maxX - minX);
    [delegate valueChanged:value tag:self.tag];
}


And the result looks like this:



You can get the source code from bitbucket by using mercurial:


$ hg clone https://iroth_net@bitbucket.org/iroth_net/ccslider