Month: November, 2010

Universal applications asset naming conventions, directory structure and macros

 

If you follow me on Twitter you probably noticed that I’m working on 2 Christmas games (if not, please check them here :), and both will be Universal. Since this is the first time I’m doing an Universal App (Game), I had to decide on an asset management strategy: how to manage, name and structure files for iPhone 3GS-, iPod Touch, iPad and iPhone 4?

The most common route is to name iPhone and iPod Touch’s assets as the plain name: texture.png and then for the iPad add a suffix to the file name with  “ipad”: texture-ipad.png. But going through this route add a bunch of if’s to your code to check whether the game is running on the iPad otherwise it is running on the iPhone / iPod Touch:

NSString *fileName;
if ((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad))
    fileName = @"texture-ipad.png";
else
    fileName = @"texture.png";

Could you imagine this in a game code? Hundreds (or thousands) of additional work. I came to a simple solution: files always have the same name. The only difference is that iPhone and iPod Touch assets are inside a “graphics” folder, while iPad ones are inside “ipad/graphics”.

Wait – wouldn’t we still need to write those hundreds of if’s? Yes. But before I show you how to solve this issue, let’s talk about Folders References and Groups in Xcode.

Game Assets: Directory Structure

I’m not going to write about this subject, because there are 2 #iDevBlogADay articles (I found them via iDevBlogADay’s delicious account) on this subject and also one from Majic Jungle:

I really recommend that you read them before continuing. I’ll wait.

… ok, are you back? For my directory structure, I’m using David’s recommendations: a GameResources folder inside Resources, and then a Folder Reference (blue folder) to it in Xcode’s project. Also, don’t forget to add the script posted by David that notices Xcode of file changes and that automatically adds/removes/updates them from builds.

Directory Structure

This way you can freely add/remove/update game assets without ever worrying about referencing them on the project. Also you can have multiple files with the same name without problems (as opposite to using folder Groups – the yellow folders).

Xcode Folder References

One line macro for iPad or iPhone detection and for getting a file’s full path according to the device

How to get the path to an iPad or iPhone version of a file without writing if’s everywhere? Through a simple class (and then later a macro):

// Path.h
@interface Path : NSObject {
}

+ (NSString *)graphicsPath:(NSString*)filePath;
+ (NSString *)resourcePath:(NSString*)filePath;
@end

// Path.m
#import "Path.h"

@implementation Path
+ (NSString *)graphicsPath:(NSString*)filePath
{
	NSString *finalPath = @"GameResources/";

	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		finalPath = [finalPath stringByAppendingString:@"ipad/"];
	}

	finalPath = [finalPath stringByAppendingString:@"graphics/"];
	return [finalPath stringByAppendingString:filePath];
}

+ (NSString *)resourcePath:(NSString*)filePath
{
	NSString *finalPath = @"GameResources/";
	return [finalPath stringByAppendingString:filePath];
}
@end

To load a graphical asset:

// Cocos2D sprite loading
CCSprite *enemy = [CCSprite spriteWithFile:[Path graphicsPath:@"enemies/devil.png"]];
  1. [Path graphicsPath:] first sets the starting path to “GameResources”, then checks if the device is the iPad, if positive, add “ipad” to the path. So far we this path: GameResources/ipad/ or GameResorces/ (in case of iPhone or iPod Touch).
  2. Next it adds the “graphics” folder name  and then your given path, so you could get 2 different responses:
    • iPad: GameResources/ipad/graphics/enemies/devil.png
    • iPhone / iPod Touch: GameResources/graphics/enemies/devil.png

Let’s make it even simpler? Add the following macros to Path.h:

#define graphicsPath(_path) [Path graphicsPath:_path]
#define gameResourcePath(_path) [Path resourcePath:_path]

Add the following line to your ApplicationName_Prefix.pch file:

#import "Path.h"

Now every time you need to load an asset you may use these macros:

// Cocos2D sprite loading for Universal games
CCSprite *enemy = [CCSprite spriteWithFile:graphicsPath(@"enemies/devil.png")];

// Getting path to a sound asset inside GameResources/sounds/enemies
NSString *soundFilePath = gameResourcePath(@"sounds/enemies/devil.caf")];

// Getting path to a plist inside GameResources
NSString *randomFilePath = gameResourcePath(@"state.plist")];

Another useful macro for iPad detection

Even with the directory and naming question solved we may still need to check whether the application is running on the iPad or not, so I would like to share another super simple but useful macro. Add this to your .pch file:

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

Use it this way:

if (IS_IPAD)
    position = 300;
else
    position = 20;

Christmas Games

Now that I taught you the deep secrets about Universal Applications asset management, I’ll relax and tell a little about the two Christmas games I’m making.

Santa in a Hurry

Santa in a Hurry is about flying your sleigh! But you may be thinking that this is boring! What if I tell you that you are flying AND racing with your Santa holding his sleigh while trying to avoid and slide obstacles and still having to save the Christmas and avoiding different things and the BAD Santas (!?) and dropping presents and seeing nice and warm graphics and listening to Christmas musics and…. and… and…! Well, you will see!

But do you want to know the real hottest thing about Santa in a Hurry?

Once you play and complete “some things”, you will earn a present. And this present may turn itself into iTunes Gift Cards or Game Promo Codes on Dec 25th!

Present CatcherPresent Catcher is all about… catching presents! Oh, again you probably are thinking: that’s so “old”. Not with Present Catcher! Instead of telling you about it I’ll just ask that you start telling your friends about it until I publish the first screenshots and videos. Then you will see what catching presents is really all about!

Here is an exclusive conceptual screenshot of Santa in a Hurry (click to zoom):

Christmas Games - Santa in a Hurry - Night Level

Don’t forget to follow @PlayChristmas and @KarnakGames to be notified about news, and of course, there is an official site: http://karnakgames.com/christmas.

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, Twitter or delicious.

Santa Race and Present Catcher coming to the AppStore!

 

Prepare yourself for the BIGGEST CHRISTMAS CHALLENGE ever!

I’m excited to announce that we’re developing two games for the Christmas. They will hopefully be available on the AppStore in 15 days.

Santa Race

Present Catcher

Also, the games will come with some surprises :)
Visit the official site now to see what Santa Race and Present Catcher are all about! http://karnakgames.com/christmas

Follow us @KarnakGames and @PlayChristmas to be notified!

Infinite scrolling background with Cocos2D

 

My 360 iDev Game Jam entry Smile on Rails features an infinite scrolling background and @GeekAndDad asked me to write a tutorial about how to do it. Why not? Since it was my first time implementing such a feature (which is very common) and I had a hard time trying to figure out the logic behind it, Geek and Dad suggestion sounded like a good idea.

Before we begin, notice that this tutorial assumes you already know Cocos2D (like loading a sprite, setting up their attributes, etc). Also the code shown is not optimized and doesn’t take care of best practices nor performance issues. I tried the best way to show the logic for an infinite scrolling “background”.

If you noticed, I wrote “background” above. Why? Because what will be infinitely scrolled is not the background itself. What really scrolls are some reusable sprites (in my code they aren’t reusable, but you should your code reuse instances for this case).

I will be using the term “building”, because let’s assume our example is a game with a city background showing infinite random buildings :)

Brainstorming your game elements

Random Infinite Elements Example

Random Infinite Elements Example

First you need to know how many different elements you want to randomly show, like 5 different types and sizes of buildings, 10 different types and sizes of trees, etc:

#define BUILDINGS_VARIETY	4

Next define a minimum space between them:

#define BUILDINGS_SPACE_BETWEEN 10

Now we have to know how many buildings have to be loaded on startup to not have non populated areas. To get to this amount we first need to know the narrowest building width. Next we check how many of them can be placed inside the screen size including the space between them:

int lastBuildingWidth = -1;

// Get narrowest width
for (int buildingIndex = 1; buildingIndex <= BUILDINGS_VARIETY; ++buildingIndex) {
	CCSprite *building = [CCSprite spriteWithFile:[NSString stringWithFormat:@"building%d.png", buildingIndex]];

	if (building.contentSize.width < lastBuildingWidth || lastBuildingWidth == -1) {
		lastBuildingWidth = building.contentSize.width;
	}
}

// Define amount to load
amountOfBuildingsToLoad = (winSize.width / (lastBuildingWidth + BUILDINGS_SPACE_BETWEEN));

Startup random load and positioning

  1. Get a random building type.
  2. Load its sprite and set its tag (don’t forget the tag!).
  3. Position the building before the last inserted building (if already present) with the distance we setup earlier.
  4. Keep track of the last inserted building CGRect, to position the next building.
int buildingType = -1;
CGRect lastBuildingRect = CGRectMake(winSize.width, 0, 0, 0);

for (int buildingIndex = 0; buildingIndex < amountOfBuildingsToLoad; ++buildingIndex) {
	// Get a random type (this could be improved to avoid repetition)
	buildingType = (arc4random() % BUILDINGS_VARIETY) + 1;

	CCSprite *building = [CCSprite spriteWithFile:[NSString stringWithFormat:@"building%d.png", buildingType]];
	building.tag = BUILDINGS_STARTING_TAG + buildingIndex;

	// Position based on before inserted building
	float newX = lastBuildingRect.origin.x - lastBuildingRect.size.width - building.contentSize.width/2 + BUILDINGS_SPACE_BETWEEN;
	building.position = ccp(newX, building.contentSize.height/2);
	[self addChild:building];

	// Keep track of this building's CGRect
	lastBuildingRect = CGRectMake(building.position.x, building.position.y,
								  building.contentSize.width, building.contentSize.height);
}

Scroll Infinitely

Now to the real action: we need to move the buildings and re-position them after they are outside the screen. Will probably will be implementing this inside your update / tick, etc.

  1. Define a movement speed
  2. Loop through all buildings (via their tags).
  3. Increase their X position (and/or Y if it fits your game).
  4. If the building is already off screen get its right side neighbor tag. This element new position will be to the left of this neighbor.
  5. Get a new random building type.
  6. Remove old building and load this new positioned one.
-(void)tick:(float)dt {
	float speed = BUILDINGS_SPEED * dt;

	for (int buildingTag = BUILDINGS_STARTING_TAG;
		 buildingTag < (BUILDINGS_STARTING_TAG + amountOfBuildingsToLoad);
		++buildingTag)
	{
		CCNode *building = [self getChildByTag:buildingTag];

		// Move building
		building.position = ccp(building.position.x + speed, building.position.y);

		// Check if building is already off screen
		if (building.position.x >= (winSize.width + BUILDINGS_SPACE_BETWEEN + building.contentSize.width)) {
			int tagToFollow;

			// Get the neighbor to the right.
			if (building.tag == BUILDINGS_STARTING_TAG) {
				tagToFollow = BUILDINGS_STARTING_TAG + amountOfBuildingsToLoad - 1;
			} else {
				tagToFollow = building.tag - 1;
			}

			CCNode *buildingToFollow = [self getChildByTag:tagToFollow];			

			// New building starting position (to the left of its neighbor)
			float newX = buildingToFollow.position.x - buildingToFollow.contentSize.width - BUILDINGS_SPACE_BETWEEN;

			// Get a random new building
			int buildingType = (arc4random() % BUILDINGS_VARIETY) + 1;
			CCSprite *newBuilding = [CCSprite spriteWithFile:[NSString stringWithFormat:@"building%d.png", buildingType]];
			newBuilding.tag = building.tag;
			newBuilding.position = ccp(newX - newBuilding.contentSize.width/2, newBuilding.contentSize.height/2);

			[self removeChildByTag:building.tag cleanup:YES];
			[self addChild:newBuilding];
		}
	}
}

Of course, as I said before, you may implement reusable sprites and a better random algorithm, but the idea behind scrollable infinite elements is this. You can download an example project here.

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, Twitter or delicious.

Constraints are good: what I learned after the 360iDev GameJam

 

Participating on the 360 iDev Game Jam proved me two things I’ve read on the book Rework:

“We all have that one friend who says, “I had the idea for eBay. If only I had acted on it, I’d be a billionaire!” That logic is pathetic and delusional. Having the idea for eBay has nothing to do with actually creating eBay. What you do is what matters, not what you think or say or plan.” (p. 38).

“I don’t have enough time/money/people/experience. Stop whining. Less is a good thing. Constraints are advantages in disguise. Limited resources force you to make with what you’ve got. There’s no room for waste. And that forces you to be creative.” (p. 67).

As any game jam (#360iDevGJ was the first one I participated) there was a time limit to make a working game, 13 hours, and let’s be honest, time is the biggest constraint for a game developer, as any game may take months or years. With the time constraint we had to go straight to the point: Just do it. I tried to “just do it”, I managed to come with a game almost playable, which I’ll talk next.

My 360iDevGJ game: Smile on Rails

The idea for Smile on Rails (http://gamejam.360idev.com/smile-on-rails/) came after the theme (Change the World) was announced, which was something like 6 hours before the Jam started. I wanted to make a game where you are riding a train and bringing attention to those in need of something: abandoned and invisible people, starving dogs; or even just cleaning a river while the train keeps going on around the world. But the concept was just to vague: how would you help people? How would you clean the river? How would the train work?

Then it was time for the Jam and the time constraint was on. I had to think of a playable concept or otherwise just give up to the previous idea and think of a new one.

After some talking with my wife, we came up with an idea: the train is always going on (infinite scrolling levels), and random persons/dogs/etc keep appearing with random needs: a need for a smile, food, bone, toy, etc. And you have to click on an action on your toolbar, like the Smile action, and click on this person before the train leaves him behind and he keeps being abandoned/invisible on the cities. A person can also appear with more than one need (always random needs with random ordering), so you have to help this person in the right order according to his needs. Time spent discussing the idea: 1 hour.

Easy concept to apply, right? In theory yes, but when you have to do art + programming in just 13 hours, that can be quite challenging.

The art constraint

Although I talked about doing art by myself on an earlier post, I still am pretty bad with graphics work or I just take too long to do something, even basic stuff. And Smile on Rails required me to draw some hard stuff (which I didn’t think of while coming with the idea): persons and animals and some easier ones: buildings, train, smiles, etc. I spent 2 hours trying to draw something using Flash (which is the program I’m most comfortable to draw something so far), and I ended up with nothing.

10 hours left and I had nothing but an idea. So, why not search for free stuff or even buy stock art? I chose the last one. I bought a cheap ($10) 500 royalty free vector art package from Cartoon Smart, that had everything I needed for the game, except the main need persons and animals (which I discovered after I bought and downloaded the zip package to see the contents). Well, I decided to stick to what I know and what I could do with my limited art ability: the “persons” and “dogs” would be just a simple and plain face/ball with cartoon balloons expressing their needs. Bingo! I could draw them with Flash, mockup a game screen and export everything to a texture atlas. The style of the characters even fitted with the vector art package (I shouldn’t have cared about the style). Time spent with the graphics: 4:32 hours.

Smile On Rails - Game Screen Mockup

Smile On Rails - Game Screen Mockup

Programming a working game in 7 hours

Art, my biggest problem, was solved. Now I just had to do the thing I know and love: develop the game! For this step I didn’t think twice: I used Cocos 2D, because is the only thing I know for iOS game development so far and I have some experience with it (and ironically no game published yet). I could have chosen Unity3D. But I’m still learning it, hence it would take me a lot of time to do basic stuff.

I spent most of the programming time with the “infinite random” scrolling background, since it was my first time doing something like this. I think I spent 4 hours just on this task trying to correcting two bugs on the random generation (some buildings were appearing above others, and the other bug was caused after some train traveling: the buildings just disappeared), which was a mistake. If I had left it bugged, it would still work – remember, I just needed a working game prototype, not a polished full game! For investing that time just on the background, I had only about 3 hours left for the characters and controls.

I managed to make the characters work, with random generation of needs, except for no overlapping checking. Also I managed to make an adjustable difficulty: as the time passes: characters appear faster. But the Jam had ended and I just didn’t work on one of the most important elements to make a playable game: the controls.

Here is a small video without working controls and scoring. Also notice that the lives (the smiles on left upper corner) disappear without effect:

Lessons Learned

Anyway I’m satisfied with the results. I managed to do a lot in a short time span. Now I have an almost working game that needs some polish (and sounds and controls and new custom graphics and [...]), and I plan to release it on the AppStore. Also as I describe on Smile on Rails page, I’ll donate 30% of every sale, this way the game will stick to its theme: Change the World.

Some things I learned and I want to share:

  • Stick to what you know;
  • Don’t worry about art if you aren’t an artist or if you are alone on the task;
  • Worry about the fundamentals (remember when I said that was a mistake worrying about the background bug? I ended up with no controls! A FUNDAMENTAL PART OF A GAME!), details later or never;
  • Your family is the best thing you have (again, remember when I said I discussed ideas with my wife? :) Also she kept me awake during the Jam and bring me coffee all the time);
  • Constraints are amazing, they drive you to MAKE IT HAPPEN and to see what  is important.
  • Try to be part of game jams. They really help you make games: @clinttredway: the #360iDevGJ inspired me to finally build a game, going to finish it :)”

Related read:

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, Twitter or delicious.

* “Less is a good thing” image credits: Rework illustrations from Flickr.

LH: our first game and its game design criteria

 

It’s finally time to write about Karnak Game’s first game! Let’s refer to it as LH for now. I prototyped at least 5 different games before deciding that I would make LH (all these prototypes were different games with varied mechanics and styles).

I decided to make LH because it is the only one that is capable of meeting or meets the following criteria:

  • 2D platformer.
  • Controls that make use of iPhone, iPod Touch and iPad hardware capabilities, be it accelerometer and/or the nice touch screen, instead of virtual d-pad: it’s so easy and intuitive that you can play LH even if you are holding the device with only one hand.
  • No entry barriers: you won’t have to read extensive and boring tutorials before you play the game. Just start it and play it.
  • A pick and play game: want to play your favorite level again? Want to restart the actual level? Want to skip this level and go to the next? Are you playing the game at a bus stop and the bus just arrived and you don’t want to lose your progress? Want to skip the next 10 levels? You will be able to do it (with some small restrictions sometimes).
  • Simple, memorable, fun and hysteric characters. Do you know that game about pigs and birds? Even a baby can remember about Angry Birds, because it deals with Birds Versus Pigs. LH follows the same roles.
  • An universal story: LH stands for something that every person in the world fights for everyday. It is the subject of most movies, books and poems.
  • Play it in any device: ok, by any I mean any iOS device, an universal game (iPod Touch, iPhone or iPad).
  • It meets some technical requirements proposed by players, which even John Carmack was looking for.
  • And yet it stills is innovative: even although LH is using proven mechanics and criteria it brings new elements and a new way of gameplay, which I’ll talk on future posts.

Next week I’ll show our artwork and maybe I’ll tell you what LH stands for, which means I may talk about LH game history too!

LH - Prototype 1

LH - Prototype 1

Resources:

This post is part of iDevBlogADay, a group of indie iOS development blogs featuring two posts per day. You can keep up with iDevBlogADay through the web site, RSS feed, Twitter or delicious.