iDevBlogADay

Deadlines, and Indie Experience

Block you menu screenDeadlines. Love them or Hate them. Evil things that demand overtime from underpaid artists and engineers, or the only thing producers can use to nail down those creative types to actually deliver assets.

I don't want to get into the pros or cons of deadlines, I just want to share my perspective as an indie, and how some deadlines helped us ship our latest free to play, iOS title, Block You.

As an indie developer, the 'It ships when it is ready' mentality is very prevalent. Not constrained by typical oversight, with costs less than visible than normal (didn't get paid this week, won't get paid next week, so who cares if it slips a week), it is easy for an indie to keep plugging away at code and art assets, watching the days and week fly by.

That is exactly what happened to me on my first two games. Both missed their original timelines for over 50%. Sure chalk it up to learning curves and features creeps, but really, how can I plan a 6 or 12 months of releases and projects, if what I call a 3 month project really takes me 5 month to do. So here is my take at trying to set some deadlines, add some time pressure into my development cycles and see how I do.

Phases of Level Polish on Lab Bunnies

Having not taken a regular course of level design outside those offered by the experiences of life and trial and effort, I now endeavor to document the phases of level design and polishing that went into Lab Bunnies, now available in the AppStore.

Steps in Brief

  • Hand Drawn Designs
  • Constructed in Level Editor (at times by another person)
  • Game Tested and Tweaked for Playability by original designer (in case the original design was untenable or not fun)
  • Level replayed many times to gauge correct time and movement bonuses
  • Decorations were added (by original designer or another)
  • After all this, a series play testing revealed a some levels that needed further improvement or updates.

The App Store Playbook - My Interview

Earlier this year I was glad to offer an interview with Shane Lee at Beginning iOS Dev while I making Lab Bunnies. He has packaged my interview, and 8 other indie developers including @DeneCarter Creator of Incoboto, @ADAMATOMIC Creator of Canabalt, and @davekalina Creator of Spider: The Secret of Bryce Manor.

Here is an excerpt of the interview that I participated in:

Operation: Eradicate Financials Three Months In

Operation: Eradicate, has been in the AppStore a bit over three months now, and I wanted to give a report of the ups and downs regarding the financial outlook of the game. Eradicate was a great game for us to create, laying a good foundation for our studio both from production & technical standpoints for which we can launch our newly announced game: Sheepo (A Kickstarter just started to help our artists).

For a bit of background please read about Post Launch Marketing Analysis and our game dev Post Mortem.

Quick Take: Not a Flop, Not a Success

According to a survey last year of indie developers, 50% of first time games don't clear $500, and 75% of indie developers don't make $10,000 off a game in a year.

As of this writing we are a couple days away from $10,000 in NET Revenue (after Apple's cut), which only took three month in the AppStore to hit. Thus regardless of my own personal expectations, we shouldn't call Operation: Eradicate a flop. But until we cover about $20K in net revenue, I can't really call it a break-even game either, as far as time and money spent.

This graph is the fast way to represent where we have been since launch. As can be seen, being listed as a Staff Favorite for iPad games isn't a game changer. It moves the needle a bit while on the list, but doesn't fundamentally change sales like a New & Noteworthy featuring, or a What's Hot notice (two years ago I had a free app featured, 15x downloads for that week).

But we do feel that our quick update to include Retina Display ready images from the new iPad is what placed us on the Staff pick list. Thus continual maintenance of a game, may get rewarded by Apple in the long term. But, other's experience may vary.

Also, we have been playing with the price every couple weeks, moving around from $3.99 to $1.99. The further we get from the initial launch the harder it is to retain revenue at the higher price. We feel now that for our niche Strategy game, the $3.99 was briefly sustainable, but now $1.99 is the highest we can go, and will in the future do periodic 1/2 off sales to $0.99.

Where we are headed now

Besides working on our next game, we will continue to support Operation: Eradicate. We are currently translating it to German, and will do a few other translations next month.

We are weighing the cost of adding in new game modes and possibly charging for them. We are also toying with the idea of setting it free for a few days (not using any paid service, just free on our own) and see how that affects sales. Partly we will do that to establish a baseline if we later try a free app promotion type thing.

I hope some of these facts and figures encourage other indies, or at least show a transparent light on what happens around small iOS studios. Skejo Studios is committed to the long haul. We have much personal and studio financial reserves to keep us going for a while, and a great budding team to keep pressing our game designs as we strive for fun and successful games.

Marketing Post-Mortem, Operation: Eradicate

Following up on the Development Post-Mortem I wrote for our new iOS game, I wanted to give a quick look into how our marketing push was planned and how the first few weeks of sales went.

Though I am a coder first, I have many spare cycles in my brain to approach the business side of things, and I knew I didn't want to neglect the marketing and promotion side of the app. A failure to launch is many times cited as a source of frustration of independent developers and I wanted to give my new game a fair shot at success.

We finished up the game the first week of February, and it was submitted on Feb. 15th to Apple. We were hoping to launch the app before GDC since we didn't want to compete with GDC news and events. At this point, I was a bit worried that it would linger in the Apple review pipeline for too long, and I would have to postpone the launch until mid-March. Gladly, the game was approved on Feb 20 and we scheduled the launch for the next Sunday, Feb 26th.

Now that you have a basic timeline, I want to break down our efforts into two segments:
Pre-Approval, the time between App submission and approval.
Pre-Launch, the time between App approval and the release data.

Pre-Approval

During the Pre-Approval timeframe, which lasted only a week for us, we had two goals: prepare all the needed marketing material, and contact our high-target sites. During this week we created our promo trailer setup our website, started gathering emails for a LaunchRock promotion (more on that below), a few other presentation items.

Over the course of the last few months, I had gathered a large list of sites to contact, and from that list I selected 10 main sites that I wanted to write about us. I wrote a short 'new studio' type email, with links to the trailer, our website, and we offered a sneak peak through Testflight (since we couldn't give out promo codes yet).

One article was written by IndieGameMag.com and a few others expressed interest. Really I was just hoping to set the table to the release announcement, so I wasn't discourage that we had only one hit at this point.

Pre-Launch

When Apple approved our app, we entered our Pre Launch phase, which was a bunch more work. Even though our release date was 6 days into the future, Promo codes still work once the game has been approved by Apple. So I templates and sent out at least 75 emails to game and app review sites offering promo codes for an early look at the game. I focused the email on the release data, included a few screen shots and links to the app on iTunes and to our trailer. I also offered to a few of the larger sites a sneak peak to our Press Release since the feel of an exclusive might get the wheel turning.

About 30 different sites or writers got back to me with interest, and I distributed 35 promo codes to writers leading up to and right after the launch.

This effort resulted in three decent sites, AppAdvice.com, Gamezebo.com and Appmodo.com, writing Preview articles. All three would then write Release or Review articles in the days following the release of the game. In the 10 days after launch 6 more articles were written about the game, including 148Apps.com and SlideToPlay.com, and two from Board Game specific sites, which is the genre of the game (Board and Strategy categories in the App Store).

So as far as effort, 75 emails resulted in about 30 people asking for promo codes, and about 12 or more articles written about us. We issued over 35 promo codes to writers/sites, and only about 20 of them were ever used. Most of those codes were given to people who expressed direct interest in the game as opposed to the fill out this form and add a promo code type interactions. This effort alone probably totaled to over 2 full days of work on my part.

A word of warning: Don't get excited about 'interest' or even 'commitments' to write, only about actual articles. About half of 'enthusiastic' writers never wrote an article, and two higher profile sites wrote 8-10 days after launch, and one firm 'we will write about you' never happened.

Press Releases

The other main item of effort was the writing and posting of the press release. We posted the release in two different places (PRMac.com and GameRelease.net), scheduled it to go out at 3am EST the day of our release (Press Release text).

We felt the press release was part of our multi-pronged approach. They are a low cost way to spread the word to hundreds of sites and writers at one time and shouldn't be neglected.

Giveaways and Promotions

We ran two free game promotions, one for Twitter Followers and one for Facebook fans. Since this is our first game, we decided to only have studio accounts instead of game specific accounts. This way we can increase the followers and fans for the studio which hopefully will be leveraged for later games and updates.

We decided to give 5 free games to five random Twitter followers, and 5 free games to Facebook fans. For Facebook, all they had to do was Like our Skejo Studios Facebook page. We purchased a couple days worth of targeted ads on Facebook which gathered about 100 likes, and cost under $50.

Not sure exactly what the impact was from these giveaways besides increasing our Fans and Followers a bit, but for the cost of $20 worth of free games, and very little actual time, it felt worth it.

Quick Timeline:
2/15 Submitted app to Apple
2/17-2/19 Contact High Profile sites for Preview or Studio Spotlight
2/20 App Approved
2/21-2/25 Starting email campaign, announced Follower and Fan free giveaway, and posted trailers to Youtube
2/26 Issued Press Releases very early in the morning, then started checking the charts

Charts

But the true impact needs to be measured in sales and app position. We moved steadily up the iPad Board and Strategy rankings until on Monday morning we hit the #4 and #5 spots on those boards. Very satisfying. Of course we have since fallen to around 80 or 100 on those charts, but we are releasing a Retina graphics update for the new iPad and will probably do another promotional push after it is approved.
#4 iPad Strategy Game
 
#5 iPad Board Game

Here is a quick sales chart. The exact legend is removed, but for scale the tail is a shade under 50.

Quick Summaries

Here are some quick summaries of the efforts we pursued.

LaunchRock: Set up Launching Soon page in minutes. They allow you to setup an email capture form, that is nicely wrapped. Then they help those who have signed up to spread the world virally through email, twitter, Facebook and other social avenues. Works best if you can give early access or other tangible benefits to the people who are referring to your sign up.

Cost: FREE
Impact: 23 Signups, only 6 referrals, about half were people I knew and would have contacted anyway. A waste of time.
Avenues of improvement: Start the signup earlier. Find a more viral message, or a better award for the top referrers.

PRMac: Most of the multi purpose app review sites repost PRMac.com press releases. You will also get 10-20 emails from paid app review sites asking if you want to pay $50-$125 for 'featured reviews'. All of those were ignored.
Cost: $19
Impact: Was sent to 700+ contacts, and viewed 11000+ times according to PRMac. According to Google, over 30 sites have reposted the press release, including 148Apps.com and other large general purpose iOS review sites. About five reviewers approached us for promo codes because of PRMac. I don't think any actually wrote.

GameRelease.net Press Release Service
The GameRelease.net community site has a members only system that allows you to post one press release a month, along with member only forums.
Cost: Either $150 for full membership, or $15 a month for 12 months. One Press Release per month included.
Impact: Press Released uploaded to GamePress.com, which resulted in reposting by Gamasutra.com. Not sure exactly beyond that.

Development Diaries: I posted about 12 development diaries along the 17 weeks of development. All were later cross posted to Gamasutra where a few of them were Featured.
Cost: Lots of time writing
Impact: Hard to know, if any. I pointed to the dev posts in the review solicitations, but don't know if that had any impact on reviews being written. At least provided some back history to both the project and the new studio.

Forums: No outreach was done at all in any forums. I did check some major sites after launch and replied to a few threads that popped up, but I it was only reactionary on my part.
Cost: Free
Impact: Hard to measure, gives the perception of engagement.

Other Tools

Promoter
Promoter is a great service that scours over 1000 gaming websites for mentions and reviews of your game (load it with a few specific keywords to look for like your studio name or game title). An example, the public reviews for Operation: Eradicate.

Cost: Free for one app, 12 Euros a month, or 99 a year.

AppFigures.com, used for tracking apps sales. Breaks down country sales.

This wraps up a wandering guide into our marketing efforts. After a few more weeks of sales and pricing adjustments, I will write about how 'successful' the game has been for us, both in regards to the raw sales numbers, and from the studio perspective of laying a foundation for future success. So far, it looks solidly in the middle of my expectations, have already passed the cash expenditures break even point, and is forecasted to probably hit the 'time and effort' break even point. If our first game out the gate breaks even, I will be happy, and we have plenty of new stuff brewing that I hope has much more potential.

Operation: Eradicate Post Mortem

For four or the five months, I have been working on Operation: Eradicate, an iOS turn based strategy game. With my graphics designer, we at Skejo Studios have revisited the last few months, and wanted to write about the highs and lows, and lessons learned for next time.

First I wanted to start with our initial hoped for timeline:

Initial Timeline

* Sept 2011 - Start
* Oct 2011 - Code fleshed out and Art assets started, first round done
* Nov 2011 - Dev and art near finish, start beta testing
* Dec 2011 - Wrap up loose ends, ship by Christmas

What really happened

* Oct 2011 - Started full-time on the first project with part time UI graphics guy, and contract artist
* Late Oct - Basic gameplay with dev art done, still hoping for Xmas release. Yeah right!
* Late Oct - First hard-drawn art assets issued
* Early Nov - Save/resume games implemented, iOS 5 turn based games (a selling point, to Apple more than anyone).
* Late Nov - Wife got a new job, moved new city little dev done. Art still slowly making progress.
* Early Dec - Final non-colorized artwork done. We were advised the game needed a full event driven tutorial to on-ramp players to game. Ugh! - Moved goal for launch to end of Jan.
* Late Dec - All game mechanics done, first beta test sent out to 5 players.
* Mid Jan - Many UI redesigns occur, plus tons of polishing adjustments.
* Late Jan - Finalized, full color artwork delivered. Pushed launch to Feb. Another round of play testing, polishing, tweaking.
* Early Feb more weeks of polishing.
* Submitted to Apple, Tuesday Feb 14.
* Approved by Apple, Mon Feb 20 (on my birthday)!!! Massive Marketing push ensues.
* Released set for Sunday Feb 26 (to get in front of GDC)

I will also be writing a Marketing Post Mortem to trace and dissect the good, bad and lessons learned from the launch.

The first lessons we learned is to be flexible with due dates, but still have them in place. As I was the only full time person, I was pushing hard because I could, but it is difficult to push part time contractors to speed up. I now will factor in slips in the timeline for artists. But even missed deadlines serve the function of putting a mark on the calendar and pushing for it. Motivation sometimes can be lacking, and that date keep things in focus. Just don't use missed deadlines as a source of depression, just learn to estimate better. Deadlines also help you look back and realize how much you did get done before that date passed.

Deadline Tip we learned

One way to help contractors (of any stripe, not just artists) create deadlines they will really try to hit, is to incentivize the deadline. Maybe add a 5% bonus for each delivery deadline hit, or maybe a lump bonus if 75% of delivery deadlines were hit. This will help them suggest dates they can hit, and gives them reason to hit them more accurately.

What Went Wrong

As already mentioned, this was my first time working so closely with artists directly, and a few false starts, and all deadlines missed made me realize I was working with people different that me (an analytical engineering type). We are all different minds, and that is all good. For me, I felt the artist delivered more than I asked for, but took longer than I wanted. But how do you direct them to do less to hit the deadline, when they are working on hand drawn artwork. Especially when the artist insists that he won't charge. Again, this is where the incentivized deadlines can come in handy

The other deadline item is setting realistic timelines for part time contributors. Rarely did their contributions come in smooth, predictable chucks. More likely they came in spurts, sometimes unpredictable. We will keep that in mind on our next projects, and as we develop updates for this game.

The last huge mistake is that we didn't add a zoom to the playing map for iPhones and iPod Touches. During one UI redesign, we took it out, and none of our play testers complained so we thought we were good. Except all of our play testers were experienced gamers, and had used the controls so much they didn't notice (or didn't report) issues with the map on smaller devices.

But we were nailed in the reviews w/ numerous 1 star reviews, and many emails asking for a zoom to be added. Thankfully we already had the code generally working, so it only took a couple hours to get an update to our testers, and wrapped up a submission to Apple in two days (numerous other typos, small fixes and enlargement of other buttons included).

Two things we learned from this issue is to specifically ask the impressions of a change you make if you are using the same testes. Them not reporting that the disliked a change, doesn't mean they liked it, just that they didn't report it. Second, use more new testers each time you have a test release. Otherwise they might be too familiar with the and attuned to the rough spot, thus not reporting them.

What we did right

We allowed enough time for UI rework. We didn't kid ourselves into thinking that we were going to get it all right the first time. I worked on a first pass developer UI just to get the game to a playable state. This I pushed to the UI designer while I worked on other behind the scene stuff like turn based games, Game Center integrations and other items. Then I implemented his design and we through it to some testers. Their feedback, and more time to imagine gave the designer more inspiration, which eventually lead to a good interface.

You can see the map and UI progressions here: http://www.tech-wanderings.com/eradicate-week-16-game-mapui-progression

Some Quick Lessons Learned

* Send stuff to publishers. They may reject you, say mean things about your progress, but they might also give you hints on how to improve. They did for us.
* Fix bugs/broken stuff when you see it, don't add toa todo list. Fix it NOW!
* Biting off too much is very easy to do!

Don't Listen to these Fears

Fear 1: What will other people think of it? Maybe I will wait until I get more done.

No, the earlier you get feedback the better. Test users and honest feedback gets you off wrong paths and deadens, and spot glaring issues sooner. Polish added to a feature you remove later is a waste of time. Don't polish anything until you know you have nothing more to cut out.

Fear 2: We are done, but I don't want to send the game to reviewers because they might be critical.

If you think your game doesn't blow away the competition, or that the reviewers will hate it, then why did you make the game? If you aren't proud of it, send it back for more polish or rework. If you are proud of it, send it out, get as much talk about your game. Anything is better than silence. This last point is more for a marketing post-mortem, but it felt like it fit here.

Quick Facts

  • Web site: http://www.skejo.com/eradicate
  • Release date: February 26th, 2012 (iPad and iPhone/iPod touch)
  • Development time: 4 months
  • Team size: 1 full time, 1 part time, 1 contractor part time
  • Development cost: Cost of living for 4 months + about $2500 (art, marketing, resources)
  • Open source code: Cocos2d, Box2d
  • Primary tools: Xcode, git, SpriteHelper
  • Raw asset size: 391 MB
  • Total app size: 13.9 MB
  • Coffee Consumed: 500+ shots of espresso

Finally, we do have the first week's worth of sales data, and we must have done a few things right. We landed in the #4 iPad Strategy spot and the #5 iPad Board game spot at launch. We didn't write down targets for launch, but this would have exceed anything we would have written.

  

What is coming next for Skejo Studios?

Vertical Scrolling story telling platformer, to be official announced shortly.
With a side scrolling indirect platformer using same artwork/world/back story.
Very high concept resource management, mini-game, character advancement game.

Operation: Eradicate on iTunes.

Comment below, or with Twitter,

SLIDES:

The One Day Help System, in Cocos2d for iOS

Since we are developing a strategy game for the iPad/iPhone at Skejo Studios, we were in need of an in game help system to quickly tutor the player with the different controls and game options. We had been putting off this mechanism for a while, since it was figured it might take a while, but surprisingly it was rather easy in Cocos2d to accomplish.

Game Layer Code

I am assuming you know how to add the correct definitions and import class headers, so I am not showing that part. Placing the below code in your init method for the Cocos2d scene or layer setups up the layer to receive touches (though I assume almost any game is receiving touches already) and adds the help layer (blank for now).

-(id) init
{
    
	if( (self=[super init])) {

        //Setup delagate for processing touches
        [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:-1 swallowsTouches:YES];
	...

    helpSystemOn = NO;
    helpLayer = [HelpLayer  node];   
    [helpLayer setGamePlayLayer: self]; //Only needed if you need to know something from your gaming layer.
    [playingLayer addChild:helpLayer z:10];

	...
}

To accept the touches, you need at least the ccTouchBegan method (required for the CCTouchDispatch call):

#pragma mark Touch Processing

-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event
{	
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];

    if (receivingTouches == YES) {
        [self selectSpriteForTouch:touchLocation];
        
        return YES;
    } else if (helpSystemOn == YES) {
        [self selectSpriteForHelp:touchLocation];
        return YES;

    } else {
        return NO;
    }
}

- (BOOL)selectSpriteForHelp:(CGPoint)touchLocation {
    BOOL processedTouch = NO;
    processedTouch = [helpLayer processTouch: touchLocation];
    return processedTouch;

}

In our game, we don't always want to be receiving touches, so we have a receivingTouches flag that we check for. If so, then we forward the touch to the correct method. We now added the check for the Help System by checking for the helpSystemOn flag and forward to the selectSpriteForHelp method which simple passes the touch to the HelpClass instance.

NOTE: The 'processedTouch' return value is use if you have multiple TouchDispatchers going at once. They will be queried in order of priority until a dispatcher returns a TRUE value.

Before moving on to the HelpLayer class, we need to add the toggle switch for the help system. Normally such a toggle should be placed with other high level game controls like 'End Turn', 'Return to Menu' or 'Restart Turn' buttons. We added the showInfo menu button with the other buttons and assign it the showInfoPressed method when pressed.

- (void) addGameControls {
	...  //Other menu items.
    
	CCMenuItem *showInfo = [[CCMenuItemImage 
                              itemFromNormalImage:@"info.png" selectedImage:@"info_pressed.png" 
                              target:self selector:@selector(showInfoPressed:)];
    
    showInfo.position = ccp(60, 300);
    
    CCMenu *controlsMenu = [CCMenu menuWithItems:pauseGameItem, showManual, restartTurn, showInfo, endTurn, nil];
    
    //Place in upper left corner
    [controlsMenu alignItemsHorizontallyWithPadding:10.0];
    controlsMenu.position = ccp(10, 700);
    [self addChild:controlsMenu z:10];

}


-(void) showInfoPressed: (CCMenuItemFont*)itemPassedIn {
    
    if (helpSystemOn == YES) {
        //Turning Off
        helpSystemOn = NO;
        [self rebuildActions]; //Used to re-enable action menu    
	} else {
        //Turning On
        [self cancelMoves]; //Used to disable any current actions
        [self rebuildActionsWithBlanks]; //Used to disable the action menu
        helpSystemOn = YES;
    }
    
    [helpLayer toggleHelp];
}

Any appropriate measures should be taken so that the game is essentially paused when the information system is on. We did this by disabling the action menu and canceling any in-progress moves.

So that is all the code that is needed inside the game play class, now we need to move to the HelpLayer class.

HelpLayer Class

//
//  HelpLayer.h
//
//  Created by Greg Holsclaw on 12/12/11.
//  Skejo Studios, www.skejo.com
//

#import 
#import "cocos2d.h"
#import "GamePlayLayer.h"
#import "Constants.h"

@class GamePlayLayer;

@interface HelpLayer : CCLayer {
    CCLayer *infoLayer;
    GamePlayLayer *gameLayer;
}

@property (nonatomic, strong) CCLayer *infoLayer;

- (void) toggleHelp;
- (BOOL) processTouch: (CGPoint)touchLocation;
- (void) setGamePlayLayer: (GamePlayLayer*) gamePlay;

@end
//
//  HelpLayer.m
//
//  Created by Greg Holsclaw on 12/12/11.
//  Skejo Studios, www.skejo.com
//

#import "HelpLayer.h"

@implementation HelpLayer
@synthesize infoLayer;

- (id) init
{
    self = [super init];
    if (self != nil)
    {
        
        infoLayer = [CCLayer node];
        CCSprite *helpBG = [CCSprite spriteWithFile:@"overlay-70.png"]; //A 1x1 pixel semi-transparent black overlay.
        [helpBG setScaleX:1024]; //Scale transparent background to appropriate size.
        [helpBG setScaleY:768];  //Scale transparent background to appropriate size.
        [self addChild:helpBG];
        [self setVisible:NO];    //Initially made invisible, only shown when info system turned on.
        
        CGSize screenSize = [CCDirector sharedDirector].winSize;
        self.position = ccp(screenSize.width/2, screenSize.height/2);
        
        [self addChild:infoLayer];
        
	}
    return self;
    
}	

-(void) setGamePlayLayer: (GamePlayLayer*) gamePlay {
    gameLayer = gamePlay;
}

- (void) toggleHelp {
    if (self.visible == YES) {
        //Remove Help system

        [infoLayer removeAllChildrenWithCleanup:YES];
        self.visible = NO;
    } else {
        //Add Help system

        self.visible = YES;        
        CCLabelTTF *helpLabel = [CCLabelTTF labelWithString:@"Info Mode On" fontName:kBaseFont fontSize:24];

        [helpLabel runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2.2], [CCFadeOut actionWithDuration:1], nil]];
        
        [self addChild:helpLabel];
    }
}


-(void) dealloc {
    gameLayer = nil;
}

@end

When the toggleHelp method is called by the main game layer it makes visible the transparent overlay, and adds a disappearing message. Now we just need to implement the processTouch methods that was used when receiving touches.

Before diving into the code, I need to mention that a couple of design considerations went into this code. There are always at least two consideration in coding, ease of coding and maintainability. Usually the super easily coded solution isn't the best long term solution. We followed an easy to code method, which I admit *might* become a time sink later. But if the UI doesn't change much, then later will never come. We try not to let the perfect kill the good here.

If your game consists of items that are moving, and those items need to present information when pressed, then the code gets a bit more complicated, and the proposed solution won't work at all. See the 'Where to Go From Here section'.

For now, we simply wanted to add information for the control buttons, which are statically placed. Thus all we have to layout a set of coordinate boxes, and trigger the correct message if the touch is inside the boxes.

- (BOOL) processTouch: (CGPoint)touchLocation {
    BOOL processed = NO;
    BOOL found = NO;
    NSString *imageStr;
    NSString *text;
    CGRect boundBox;
    
         
    boundBox = CGRectMake(10, 230, 50, 50);  //Location of Move Button
    if (CGRectContainsPoint(boundBox, touchLocation)) {   
        found = YES;
        imageStr = @"help-move.png";
        text = @"HELPMOVE";
    }

    boundBox = CGRectMake(10, 280, 150, 50);  //Location of Fight Button
    if (CGRectContainsPoint(boundBox, touchLocation)) {   
        found = YES;
        imageStr = @"help-fight.png";
        text = @"HELPFIGHT";
    }

    boundBox = CGRectMake(60, 230, 50, 50);  //Location of Trade Button
    if (CGRectContainsPoint(boundBox, touchLocation)) {   
        found = YES;
        imageStr = @"help-trade.png";
        text = @"HELPTRADE";
    }

    boundBox = CGRectMake(10, 180, 50, 50);  //Location of Cure Button
    if (CGRectContainsPoint(boundBox, touchLocation)) {   
        found = YES;
        imageStr = @"help-cure.png";
        text = @"HELPCURE";
    }

	... //Other stuff if more needed. 

    [infoLayer removeAllChildrenWithCleanup:YES]; //Remove any prior message.

    if (found == YES) {
        processed = YES;
    	CCSprite *bg = [CCSprite spriteWithFile:@"bg_info_message.png"];
    	CCSprite *image = [CCSprite spriteWithFile:imageStr];
    	CCLabelTTF *label = [CCLabelTTF labelWithString: text fontName:@"Arial" fontSize:12];
    
    	label.position = ccp(0,100);
    
    	[infoLayer addChild:bg z:-1];
    	[infoLayer addChild:image z:1];
    	[infoLayer addChild:label z:2];
    }
    
    return processed;
}

Finished product

Of course, the actual help text, images and backgrounds, and their positions need to be adjusted to your use, but this should be adequate to get you very near a tailored solution.

Our solution seen in a couple of images:

Where to go from here

If the help system needs to be used on sprites/objects that move on the game surface, then above solution will not work in the slightest. You will need to interact with your game play layer and reference all the actual sprites you want to give information about.

To do this, you must assign all the 'interesting' sprites to an array and go through the array of sprites checking for collisions between the touch and the sprite's bounding box.

In some init function add the sprites to a help array:

-(id) init {
	... //regular init code
	helpSprites = [NSMutableArray arrayWithCapacity:2];
	[helpSprites addObject:…….]; //Repeat for all objects that will need help information
	...
}
 

Then in the 'processTouch' method for the HelpLayer class you would loop through the sprites looking for a collision:

	id foundSprite;
	for (id *sprite in gameLayer.helpSprites) {        
        
        //CGPoint boundOrigin = 
        CGPoint worldCoord = [sprite.infectionOverlay convertToWorldSpace: sprite.position];

        CGRect boundBox = CGRectMake(worldCoord.x, worldCoord.y, sprite.boundingBox.size.width, sprite.boundingBox.size.height);
        
        if (CGRectContainsPoint(boundBox, touchLocation)) {   
            foundSprite = sprite;
            break;
        }
    }
 
	//Determine which kind of sprite it is and display the appropriate help message.

A tailored mechanism like this will allow you to quickly add objects to the help system, and detect them anywhere on the game layer they might exist. Such code is much more maintainable because if you move any UI items later in the game design, the code isn't broken (unlike the original implementation which forces you to sync the boundBox to the location of items, which might be changed later). But this system is much more complex to setup.

Gladly, this entire process took less than a day to implement (minus cool help graphics to add), so no game should be w/o at least a rudimentary help system).

Comment below, or with Twitter,

Screenshot taken from our Eradicate project (view all posts here). Also visit Skejo Studios to see all we are doing there.

Should indie game devs do it all?

Running in the game dev circles for the last three months has exposed me to a ton of one or two man shops that undertake the entire development and production of a game on their own. Some are doing well, but others are struggling.

It almost seems like some developers purposely handicap themselves by 'doing it all' just so they can claim the elusive 'indie developer' mantel. I don't want to touch the What is an indie game developer? topic again, but I do want to target the thinking behind doing it all yourself.

Is going it alone wise, productive, or profitable?

Coming from the startup world of Silicon Valley, it is regularly frowned upon to hear about a startup with only one founder (#1 mistake startups make). The reasons are broad, but generally distill down to three core issues:

1) If nobody has partnered with you, you might be a pain to work with.
2) If nobody has partnered with you, your idea probably isn't very good.
3) One person just can't do it all.

I don't really want to touch the first issue as it is a personal issue. I want to assume that all indie developers and designers aren't doing the indie scene because they have been fired from every job they have ever held, but instead choose this path for themselves.

Moving to the second point, I think it is valid to ask a solo dev if they have really tried to flesh out their game idea, bouncing it off their circle of friends and family. If none of them wanted to join, or at least refer a co-developer/co-artist to help the game idea along, maybe the idea doesn't have legs. Listen to this signal. Refine your concepts and ideas until people start biting, and offering to help you. Remember, most likely, your idea sucks anyway.

Is it Productive?

But, assuming your idea is awesome, which will result in the next Zynga or Rovio, why would you still want to do it alone?

Will you, as the one man show be able to produce that quality game that you see in your mind?

Or will have to settle when you hit the roadblocks of your weaknesses?

Art is hard for analytical coders. Game design and balancing is hard for the more artistic among us. Pulling together all the aspects of a game is not a skill everyone has.

Stop thinking that your awesome strengths are going to mask the other weaknesses in your game development process. It won't. Don't be surprised that your product is judged against its weakest aspect, the stuff you aren't good at, not its strengths.

Pull together a team, use your strengths to compliment the rest of your team's strengths.

Is it Profitable?

Finally, assuming you have the best idea, should you keep it to yourself, doing all the work? Will the payout be bigger by keeping the whole pie for yourself?

A widely noted survey also backs up the team theory, versus one man show. Scroll to around Figure 7, which show more returns for more developers working together. / Owen Goss, the author's take:

"The conclusion that I draw from this is that, in general, larger groups of developers are able to create games that earn more money. Wagering a guess, this is perhaps because they are able to create games that are larger in scope, more technically interesting, and more polished, because they have more people to work on the game and provide input into its improvement."

General experience shows that partnerships of 2-5 definitely outperforms solo developers in most situations. As Owen notes, along with many startup founders and investors, a team compensates for the weak links of the individuals. In the same way, a game development team should have a higher standard of quality, polish and completeness when compared to an otherwise average game.

If you don't want to partner with someone, at least use contractors to fill your holes. If you, yourself are not willing to invest $500-$1000 for decent graphics and music/sounds, is your idea really that awesome? Or, if you can't convince your closest family and friends that your game idea really is the next best thing, to help by filling art needs when you are mediocre artist or worse, or at least by buying decent art, should you spend all your time to craft top notch code and crown it with so-so artwork?

If you really are the rock star artist/game designer/developer, I will cheer you on to success. But if you are like me, great a few things, good at some other and down right horrible at many thing, surround yourself with folks whose strengths amplify your own. Stop trying to it all yourself.

The composition of a team is a different articles, so I won't even touch that, and there a few articles already written:
http://www.gamasutra.com/blogs/AlistairDoulin/20100107/4040/Building_A_S...
http://www.lorekings.com/blogs/2011/oct/3rd/ig_building/team-pg1.html
http://www.indiezen.org/index.php?option=com_content&view=article&id=119...

Are there are great examples for one man shows that have succeeded in the long term (I have a few in mind)? Are they the exception to the rule? Any brave souls wanting to describe examples of one man shows that resulted in burn out or unpolished games?

Comment below, or with Twitter,

iOS Game Center Achievement Display

In one of my projects, while I waited for some art work, I wanted to get ahead with my Game Center integration. This tutorial is about how to get Achievements to be displayed in the Game when the achievement is sent to Game Center. I will further explore how to get the achievement images also included. A few simple frameworks will be used.

Also, I am taking it for granted that Game Center is up and running on your app. I was able to get it up and running in a few hours using the methods found in Learning Cocos2D or in numerous tutorials around, here or here.

Once you have a user authenticating, and you have setup a few iTunes Connect achievements, you might want to display an 'Achievement Attained' message when a new achievement has been accomplished. Again, this is different than just showing the Achievements window, that shows all the achievements a player has completed. We want a little notification message displayed.

In iOS 5, Apple finally gave us a prepackaged API call that will show an achievement banner when an achievement is complete (per your code giving a 100.0% to an achievement). Here is the simplest way:

- (void)sendAchievement:(GKAchievement *)achievement {

    achievement.percentComplete = 100.0;   //Indicates the achievement is done
    achievement.showsCompletionBanner = YES;    //Indicate that a banner should be shown
    [achievement reportAchievementWithCompletionHandler:
     ^(NSError *error) {
         dispatch_async(dispatch_get_main_queue(), ^(void)
                        {
                            if (error == NULL) {
                                NSLog(@"Successfully sent archievement!");               
                            } else {
                                NSLog(@"Achievement failed to send... will try again \
                                      later.  Reason: %@", error.localizedDescription);                
                            }
                        });
     }];
}

This code creates the achievement object according to your identifier (whatever you setup in iTunes), you set the completion to 100%, set the 'showsCompletionBanner' property to YES, and shoot it off to Apple. The new iOS property is 'showsCompletionBanner' which defaults to NO, but if updated to YES, will display a cute little banner with the title and description of the achievement, as shown below (yes I am using the http://www.neuroshimahex.com/ game as inspiration, so placed as my dev background. Check it out, very fun strategy game).

But this approach has a few limitations. First off, it uses the generic Game Center icon, instead of the image that I uploaded for my game achievement. Worst off, if the player earns two achievements at the same time, only one of them will be displayed, which I think is a bummer. And lastly, this is an iOS 5 only API calls, so will crash any device not running iOS5, oops!

So to repair all of these issues, we will not be using the 'showsCompletionBanner' property, but will be implementing our own notification, or more correctly using and modifying some code of people who have gone before us.

To get started, I used the great code that Type One Error demonstrated in http://www.typeoneerror.com/articles/post/game-center-achievement-notifi.... Read that article for some background if you want, and then grab the code at https://github.com/typeoneerror/GKAchievementNotification and install into your project. We will be using the GKAchievementNotification and GKAchievementHandler classes, with some updates and modifications. First off, if you are using ARC for your game, do a quick scan of the code and remove the few release, retain and autoreleases you find in that code. If you don't want to scan, just try to build after you place the files in your project and fix wherever the compiler squawks at.

The Type One Error classes will display a notification that is similar to the one that the iOS 5 call gives, but your code needs to know what the achievement title and description is. To do this you need to populated a'GKAchievementDescription' object.

One great thing about GKAchievementDescription objects is that they are already localized according to the language setting of the user (if you support that language) and thus don't have to worry about any localization issue if you use this method.

The bummer is that you can't load just one Achievement description, you have to load them all. I believe the best time to do this is when a user has authenticated Game Center on your app, you should do an async call to get them. Galdly Apple does give an API call for this, which I place in the CompletionHandler of the user authentication call.

If you are using the code by Ray Wenderlich, then you have a method like this, which I add one line to, and a new method. Also add an NSMutableDictionary * self.achievementsDescDictionary to whatever class is processing your Game Center code, which will store the achievement data for the rest of the active session.

- (void)authenticateLocalUser { 
    
    if (!gameCenterAvailable) return;

    NSLog(@"Authenticating local user...");
    if ([GKLocalPlayer localPlayer].authenticated == NO) {     
        [[GKLocalPlayer localPlayer] 
         authenticateWithCompletionHandler:^(NSError *error) {
             if([GKLocalPlayer localPlayer].isAuthenticated){
                 [self retrieveAchievmentMetadata];         //Here is the new code
             }
         }];        
    }
}


//Here is the new method.
- (void) retrieveAchievmentMetadata
{
    self.achievementsDescDictionary = [[NSMutableDictionary alloc] initWithCapacity:2];
    
    [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:
     ^(NSArray *descriptions, NSError *error) {
         if (error != nil) {
             NSLog(@"Error %@", error);
             
         } else {        
             if (descriptions != nil){
                 for (GKAchievementDescription* a in descriptions) {
                     [achievementsDescDictionary setObject: a forKey: a.identifier];
                 }
             }
         }
     }];
}

The 'retrieveAchievmentMetadata' method initializes the dictionary then calls to get all the Achievement descriptions for your game, and cycles through and adds them to the dictionary. This is an async call, so it shouldn't slow down the start of your game or project.

Now that we have all the titles and descriptions for all your achievements, we can modify our original code to create an iOS 4/5 friendly notification, that will also show all achievements in succession using the Type One Error code, again inside of Ray Wenderlich's code (resource links at the top and bottom of this post).

- (void)reportAchievement:(NSString *)identifier 
          percentComplete:(double)percentComplete {    
        
    GKAchievement* achievement = [[GKAchievement alloc] 
                                   initWithIdentifier:identifier];
    achievement.percentComplete = percentComplete; 
    
    if (percentComplete == 100.0) {
        //Show banners manually
        GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier]; //Update pull achievement description for dictionary
        
         [[GKAchievementHandler defaultHandler] notifyAchievement:desc];  //Display to user


    }
    [achievementsToReport addObject:achievement];    //Queue up the achievement to be sent
    [self save]; 
    
    if (!gameCenterAvailable || !userAuthenticated) return;
    [self sendAchievement:achievement];   //Try to send achievement 
}


- (void)sendAchievement:(GKAchievement *)achievement {
    [achievement reportAchievementWithCompletionHandler:
     ^(NSError *error) {
         dispatch_async(dispatch_get_main_queue(), ^(void)
                        {
                            if (error == NULL) {
                                NSLog(@"Successfully sent archievement!");
                                [achievementsToReport removeObject:achievement];   //Remove Achievement from queue.             
                            } else {
                                NSLog(@"Achievement failed to send... will try again \
                                      later.  Reason: %@", error.localizedDescription);                
                            }
                        });
     }];
}

The additional checks to see if the achievement is 100% complete, and if so, grabs the correct achievement description object and displays it to the user. Then it continues on with telling Apple about the new achievement, and if you have a landscape game, it will look something like this.

But, I think it would be even better to also have the achievement image displayed, instead of the default image. So to do that, update the code with the notification part to this:


    if (percentComplete == 100.0) {
        //Show banners manually
        GKAchievementDescription *desc = [achievementsDescDictionary objectForKey:identifier];

        [desc loadImageWithCompletionHandler:^(UIImage *image, NSError *error) {
            if (error == nil)
            {
                [[GKAchievementHandler defaultHandler] setImage:desc.image];   //If image found, updates the image to the achievement image.
            } 
            [[GKAchievementHandler defaultHandler] notifyAchievement:desc];
        }];

    }

Since that code is inside a completion handler block, it will only execute once the handler returns. If it returns an image, then the notification is updated with that image, and then it displays to the user.

Yeah, yeah, I have temporary art in there. I told you the art was falling behind. Anyway, using this method out of the box you will notice that if you have a landscape game, that the notifications are off to the side and sideways (the Type One Error guys made it for portrait only). To fix this for landscape you need to do two things, adjust the frame and the rotation.

Find the 'notifyAchievement' method in the GKAchievementHandler class and update to:

- (void)notifyAchievement:(GKAchievementDescription *)achievement
{

    GKAchievementNotification *notification = [[GKAchievementNotification alloc] initWithAchievementDescription:achievement];
    notification.frame = kGKAchievementFrameStart;
    notification.handlerDelegate = self;
    
    //Adjusting rotation.
    
    if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationLandscapeLeft) {
        notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(-90));
    } else {
        notification.transform = CGAffineTransformRotate(notification.transform, degreesToRadian(90));
    }
    
    notification.frame = kGKAchievementFrameStartLandscape;  //Update the frame, you need to create this definition.
    
    [_queue addObject:notification];
    if ([_queue count] == 1)
    {
        [self displayNotification:notification];
    }
}

Also adjust the 'animateIn' and 'animateOut' frames as needed. I found these frames to be useful:

#define kGKAchievementFrameStartLandscape    CGRectMake(-53.0f, 350.0f, 104.0f, 284.0f);
#define kGKAchievementFrameEndLandscape      CGRectMake(20.0f, 350.0f, 104.0f, 284.0f);

So, by using the Game Center code from Ray Wenderlich's
tutorial as a starting point, along with the Type One Error notification code, we then added adjustments so our final solution does the following:

1) Display one or more achievement notifications (the Type One Error code queues the display of many notifications)
2) Displays the notifications with images and full title and descriptions.
3) In a manner that is iOS version independent.

You determine a player had completed an achievement, sprinkle in:

[GCHelper sharedInstance] reportAchievement:identifier 
          percentComplete:percentComplete];  

Or whatever way you access your Game Center achievements

Lastly, if you believe pulling all the achievement data early in the authentication call is a performance or data issue, you can wait and place the 'retrieveAchievmentMetadata' call until the player earns an achievement, and place in its completion handler, add the code to display the achievement notification. But there is a little extra legwork needed to save the achievement until you have retrieved all the description data. I leave it to the reader to finish off that particular use case.

Resources:
http://developer.apple.com/library/ios/#documentation/NetworkingInternet...
http://www.typeoneerror.com/articles/post/game-center-achievement-notifi...
https://github.com/typeoneerror/GKAchievementNotification
http://www.raywenderlich.com/3276/how-to-make-a-simple-multiplayer-game-...

Comment below, or with Twitter,

Cocos2d Menus and arguments

I was toying with the idea of writing a post about why I went independent, but I figure that wasn't appropriate for the wider audience of iDevBlogADay.com. Check my blog for those posts. So I decided to post a more technical piece regarding cocos2d menus and how to pass arguments through the Cocos2d menu system. But I was facing two issues. One I hated rewriting similar code over and over again. Second to make menu items more reusable, I needed to be able to pass arguments to the selector of the menu, which wasn't readily apparent how to do this. Also, checking the cocos2d forums and other places I saw that many others have had this issue.

So my goal is to create a reusable button factory which allows for the passing of arguments to the selector (read check this tutorial to get the basics for Button and Text Menu Items in Cocos2d).

For starters, here is a very typical pattern for adding a text menu item:

-(void) addMenu {
    //Create the label for the menu
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Button Text fontName:@"Arial" fontSize:12];

    //Add label to a menu item.
    CCMenuItemLabel *menuItem = [CCMenuItemLabel itemWithLabel:label target:self 
                                                      selector:(menuItemPressed:)]; 
    //Add menu item to a menu.   
    CCMenu *menu = [CCMenu menuWithItems:menuItem, nil];
    menu.position = ccp(0,0);

    //Add menu to a layer.
    [self addChild:menu];
}

//Method to receive button pressed action
-(void) menuItemPressed: (id)sender {
    [self doSomething];
}

As you might have noticed, the argument for the menu select is automatically supplied as a CCMenuItem of some sort or another, but generically it is just an id object. The question is how do you forward some information to the menuItemPressed method, from the menu item you created, and to no have to go through the effort of creating this sequence of code over and over again.

Example, this is ugly.

//Method to receive button1 pressed action
-(void) menuItemPressed1: (id)sender {
    [self doSomething: 1];
}
//Method to receive button2 pressed action
-(void) menuItemPressed2: (id)sender {
    [self doSomething: 2];
}
//Method to receive button3 pressed action
-(void) menuItemPressed3: (id)sender {
    [self doSomething: 3];
}

I wanted something like this.

-(void) menuItemPressed: (id)sender {
    [self doSomething: sender.passedVariable];
}

Gladly, all the CCMenuItem classes and subclasses all have a userData property that you can use to assign data to like this:

menuItem.userData = someObj;

To use the userData, and to make sure there weren't warnings or error in XCode, I explicitly cast the object to what is should, and assign it to a temp variable.

Update the code a bit and it becomes:

-(void) addMenu {
    //Create the label for the menu
    CCLabelTTF *label = [CCLabelTTF labelWithString:@"Button Text fontName:@"Arial" fontSize:12];

    //Add label to a menu item.
    CCMenuItemLabel *menuItem = [CCMenuItemLabel itemWithLabel:label target:self 
                                                      selector:(menuItemPressed:)]; 
    //Add menu item to a menu.   
    CCMenu *menu = [CCMenu menuWithItems:menuItem, nil];
    menuItem.userData = someObj;  //Of type SomeObj.
    menu.position = ccp(0,0);

    //Add menu to a layer.
    [self addChild:menu];
}

//Method to receive button pressed action
-(void) menuItemPressed: (id)sender {
    (SomeObj*) tempObj = (SomeObj*) sender.userData; 
    [self doSomething: sender.userData];
}

So now, we have a passed variable being used in a receiver of a pressed menu item. Great. Now write this code over and over again. OR, create a button factory that does the heavy lifting for you. Since I wanted to pass the position, and have a general layer to use, this method returns a CCLayer, but you could just return a CCMenu instead.

Here is my final button factory code, and an example usage (subject to improvements in the future, I will try to keep this article up to date).

-(CCLayer*) actionTrayButtonFactory: (NSString*) text withPosition: (CGPoint) pos withUserData: (id) userData selector: (SEL) selector {
    
    CCLayer *layer = [CCLayer node];
    
    CCLabelTTF *label = [CCLabelTTF labelWithString:text fontName:@"Arial" fontSize:13];
    label.color = ccc3(255, 255, 255); //Set your own color.
    
    CCMenuItemLabel *menuItem = [CCMenuItemLabel itemWithLabel:label target:self 
                                                      selector:selector];
    menuItem.userData = [userData retain];
    
    CCMenu *menu = [CCMenu menuWithItems:menuItem, nil];
    menu.position = pos;

    [layer addChild:menu];
    
    return layer;
}

Usage:

        CCLayer *layer = [self actionTrayButtonFactory: @"Button Name" withPosition:ccp(100, 200) withUserData:[NSNumber numberWithInt:1] selector:@selector(menuItemPressed:)];
        [self addChild: layer];

I would use this inside a loop where I am incrementing the button name, position height and the userData passed in.

Next, I will be making a similar button factory that takes in images and will create CCMenuItemImages instead. The same format will work. Also, a further extension would be to add in another argument for button type incase you wanted to adjust the size/shape/color of the manufactured menu item.

Also, if you are making a localized app, the button factory method can update the 'labelWithString:text' portion to 'labelWithString:NSLocalizedString(text, nil)', which is what I am doing in my game.

I am not sure if I needed to use objects in the userData property, instead of just integers or floats, but that is what was need when I got it to start working. I also at times needed to place a 'retain' on the object to maintain the data. Not exactly sure why. Any help from my readers on why that is the case will help clean up this code long term.

This code will show up in the Skejo Studios Outbreak project. Check out the game development diaries. This post is a part of the iDevBlogADay series. Check out some other recent posts including Who is an Indie Dev and What's my motivation.

Syndicate content