Tag: cocos2d

How to take in-game screenshots with Cocos2D and upload them to a Facebook album

 

I’ll be covering a very cool feature to add a new social feature in your game: posting in-game screenshots straight from the game to a Facebook album! I managed to do it today for a client game and it worked smoothly, so why not sharing?

What is covered in this article?

  1. Taking a screenshot via code from your Cocos2D game and storing it in an UIImage.
  2. Integrating Facebook into your Cocos2D game.
  3. Posting the screenshot to the Facebook account of the player (upon permission).

Taking Screenshots in Cocos 2D

This step was the easiest one for me. Oh wait, it’s not that easy to take a screenshot of the actual state of your game: what I have done was using a code written by Manu Corporat (Infinity Field developer). Grab the “Cocos2D Screenshot” methods here and add them inside the class CCDirectorIOS (cocos2d/Platforms/iOS/CCDirectorIOS.m) – it works for iPhone, iPhone 4 and iPad screenshots, e.g. all iOS devices and versions.

You can now take screenshots from your game by just calling:

UIImage *screenshot = [[CCDirector sharedDirector] screenshotUIImage];

You can even save this image in a folder (or even the Photo Album):

NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Screenshot.png"];

// Write image to PNG
[UIImagePNGRepresentation(tempImage) writeToFile:savePath atomically:YES];

Integrating Facebook into your Cocos2D game

- First of all, Setup a New App on Facebook: http://www.facebook.com/developers/. Once the application is created, click on the left tab “Mobile and Devices”, change the “Application type” to “Native App” and copy the “Application ID”.

- Open your Xcode project and add the following keys to your info.plist: Key: URL types -> Key: Item 0 -> Key: URL Schemes -> Key: Item 0 -> Value: fbYOUR_APP_ID (include the fb), it should look like:

Facebook - info.plist

- Clone the Facebook iOS-SDK from Git: https://github.com/facebook/facebook-ios-sdk.

Drag the “src” folder into your Xcode project.

- If you want the official “Login with Facebook” blue button, open the folder “sample” that you cloned with the Facebook SDK, and right click “FBConnect.bundle” -> Show Package Contents -> copy and paste the images you want in your Cocos2D project. Consider renaming @2x to -hd.

- Import FBConnect.h into your Cocos2D Scene or Layer, the one in which you want to open the Facebook connection:

#import "FBConnect.h"

- Your class interface has to implement the Facebook delegates, as well have some members:

@interface HelloWorld : CCLayer
{
	// Facebook
	Facebook *facebook;
	BOOL isFBLogged;

	// GUI
	CCLayer *shareLayer;
	CCMenuItem *facebookLoginButton, *facebookLogoutButton;
	CCLabelTTF *message;
}

- Add the GUI to handle facebook messages, as well the Login button (in this case you do as you wish, the way I’m doing is just an easy example). Although my GUI code is just an example, note that I’m inserting them inside a child CCLayer. When we are going to take the screenshot, we won’t want the Facebook button in the screenshot, nor the label saying “SHARE”, so I’ll just turn visibility of the layer on and off, instead of turning every element individually.

-(id) init
{
	if( (self=[super init] )) {
		CGSize size = [[CCDirector sharedDirector] winSize];

		CCSprite *gameElement = [CCSprite spriteWithFile:@"poolplane.png"];
		gameElement.position = ccp(size.width * .5, gameElement.contentSize.height * .5);
		[self addChild:gameElement];

		shareLayer = [CCLayer node];
		[self addChild:shareLayer];

		facebookLoginButton = [CCMenuItemImage itemFromNormalImage:@"LoginWithFacebookNormal.png" selectedImage:@"LoginWithFacebookPressed.png" disabledImage:@"LoginWithFacebookPressed.png" target:self selector:@selector(facebookLogin)];

		CCMenu *fbMenu = [CCMenu menuWithItems:facebookLoginButton, facebookLogoutButton, nil];
		fbMenu.position = ccp(size.width * .5, size.height * .5 + facebookLoginButton.contentSize.height * 3);
		[shareLayer addChild:fbMenu];

		message = [CCLabelTTF labelWithString:@"Share in Facebook!" fontName:@"Marker Felt" fontSize:24];
		message.position = ccp(size.width * .5, fbMenu.position.y + facebookLoginButton.contentSize.height);
		[shareLayer addChild:message];
	}
	return self;
}

Logging in into Facebook and getting permissions

We may enable the user to login into his Facebook account by simply calling the Facebook:authorize method passing in the permissions we want to get. We also may already hide unecessary items for the screenshot before calling the Facebook authorize method. You will know why later on.

- (void) facebookLogin
{
	// The screenshot is going to be taken instantly after the login,
	// so already hide GUI/unecessary stuff
	shareLayer.visible = NO;

	if (facebook == nil) {
		facebook = [[Facebook alloc] initWithAppId:@"FACEBOOK-APP-ID"];
	}	

	NSArray* permissions =  [[NSArray arrayWithObjects:
							  @"publish_stream", @"offline_access", nil] retain];

	[facebook authorize:permissions delegate:self];
}

Now we implement the delegate functions to handle the login request responses. They are very simple. The game will take the screenshot right after logging in (inside FBSessionsDelegate:fbDidLogin) and that is why we’ve hidden the GUI before logging in (the takeScreenshot screen is detailed below).

#pragma mark -
#pragma mark FBSessionDelegate
/**
 * Called when the user has logged in successfully.
 */
- (void)fbDidLogin {
	isFBLogged = YES;
	[self takeScreenshot];
}

/**
 * Called when the user canceled the authorization dialog.
 */
-(void)fbDidNotLogin:(BOOL)cancelled {
	if (cancelled) {
		[message setString:@"Login cancelled. No Login, No Share, No Game! :)"];
	} else {
		[message setString:@"Error. Please try again."];
	}

	shareLayer.visible = YES;
}

Taking the screenshot, uploading to Facebook and handling the responses

This is where the real magic happens: sending the screenshot to Facebook. It’s a very simple GRAPH API call to “me/photos” that sends the UIImage we make with the CCDirector:screenshotUIImage method.

According to the documentation this call uploads an image to the application’s album in the user account: “We automatically create an album for your application if it does not already exist. All photos from your application will be published to the same automatically created album.”

- (BOOL) takeScreenshot
{
	UIImage *tempImage = [[CCDirector sharedDirector] screenshotUIImage];

	NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
								   tempImage,@"message",
								   nil];

	[facebook requestWithGraphPath:@"me/photos"
						 andParams:params
					 andHttpMethod:@"POST"
					   andDelegate:self];

	[message setString:@"Uploading screenshot. Please wait..."];
	shareLayer.visible = YES;

	return YES;
}

The last step is handling the responses: the upload may fail or be successful. For the first case we would need to alert the user about the error andshow the Facebook button again and enable a new upload, for the later we have to show a positive notification for the user. In both case we need to show the GUI layer again.

#pragma mark -
#pragma mark FBRequestDelegate
/**
 * Called when a request returns and its response has been parsed into
 * an object. The resulting object may be a dictionary, an array, a string,
 * or a number, depending on the format of the API response. If you need access
 * to the raw response, use:
 *
 * (void)request:(FBRequest *)request
 *      didReceiveResponse:(NSURLResponse *)response
 */
- (void)request:(FBRequest *)request didLoad:(id)result {
	[message setString:@"Photo posted in the \"APP NAME\" album on your account!"];
	shareLayer.visible = YES;

}

/**
 * Called when an error prevents the Facebook API request from completing
 * successfully.
 */
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
	[message setString:@"Error. Please try again."];
	shareLayer.visible = YES;
}

Example/Template project

I’ve packed everything in a Cocos2D Xcode project, ready to be used and compiled: just change your Facebook App’s ID and adapt in your project.
Download the 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.

Tips #1: Cornerstone, AgileZen and Compressed Cocos2D textures with Texture Packer

 

I’m really busy this week, so this is not an article. I wanted to share some tips from what I’ve been dealing recently, that I found to be very useful.

Cocos2D pixel formats and highly compressed textures with Texture Packer

One of the games I’m working on has dozens of sprite sheets, and most of them are 2048×2048. That is a killer even for the iPhone 4 and iPad, and I can’t even consider older devices.

Consider using 4 Sprite Sheets at once that are 2048×2048 each and PNG: the game wouldn’t even run, because the consumed memory would be too big. Also, the loading times would be terrible.

What is the solution?

  1. Get Texture Packer.
  2. Group background images and other squared sprites in the same sprite sheet, choose the RGB565 pixel format, select “FloydSteinberg+Alpha” as the Dithering algorithm and export it as a compressed PVR texture (pvr.ccz). BINGO! The image looks the same as 32-bits pixel format, the file size is smaller than PNG, and the loading time is decreased from around 15s to 1s (at least with my 2048×2048 spritesheet!).
  3. For sprites with alpha/transparency required, you may use RGBA4444 + FloydSteinberg+Alpha for those with a few to no gradients, or even RGBA8888, but in both cases export them as pvr.ccz! Using RGBA4444 reduces the memory usage by half. For RGBA8888 you still have the same memory usage, but since it is pvr.ccz, at least the loading times are cut.The problem is that most of the times RGBA4444 looks bad, so you may give a chance to RGGBA8888 + PVR.CCZ.

To learn more about Texture Packer and Cocos2D textures, read How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats by Ray Wenderlich!

On the end: Texture Packer is probably the most important tool for a Cocos2D developer.

The real good Mac SVN Client: Cornerstone!

After I wrote the last article dealing with SVN, where I recommended Versions as the best Mac client, I received lots of suggestions in Twitter and in the comments to use Cornerstone. I decided to try it, and now I can’t even open Versions anymore. The only problem is buying another $59 license!

From a tweet I posted (that got retweeted by the developers of Cornerstone): “After using Cornerstone for some days, I can’t even use Versions anymore. It lacks everything and looks old. #svn”.

AgileZen and Lean project management

Got to know about agile lean project management yesterday, which lead me to meet AgileZen – probably the simplest project management system on earth, yet probably the most efficient.

You can read a good overview of AgileZen here: AgileZen for Solo Remote Development.

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.

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.

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.

Learning Diary #9: Cocos2D and Tile maps and more Box2D

 

06/Jul/2010

Tiled (my map is awful, I know)

Tiled (my map is awful, I know)

  • Another day invested reading Ray Wenderlich tutorials! This time, I’ve read his last two tutorials @Box2D and the ones about Cocos2D with tiled maps from Tiled. Pretty easy and clear:
    - How To Create A Breakout Game with Box2D and Cocos2D Tutorial: Part 1 and Part 2.
    - How To Make a Tile Based Game with Cocos2D and Collisions and Collectables: How To Make a Tile Based Game with Cocos2D Part 2.
  • What can I say about these tutorials? Well, I learned almost every concept behind Cocos2D, Box2D, tiled maps and some more concepts (like general game structure, how to put together Physics, general game loop, AI – even if he doesn’t cite AI, and so on). I already had some game development background (I read gamedev books for 6 years already), but even if you are starting, you will get a lot of knowledge reading them.
  • Objective-C: GamingHorror commented on last post that Objective-C can remove an object from an array while iterating through it if using a regular loop (as in C and C++). We just can’t remove an object if using a fast numerator (for..in). Thanks Steffen for the tip!
  • I was reading the source code from C++ STL find iterator and I saw on the documentation:
    // @return The first iterator @c i in the range @p [first,last) such that @c *i == @p val, or @p last if no such iterator exists.

    I was scared for not remembering what [a,b) meant. So, time for some Wikipedia about math and here we have a little refreshment on math sets and intervals notations:

    () exclude
    [] include
    ][ exclude
    Ex: [a,b) = a <= x < b

Cocos2D and Tiled

  • For the sake of curiosity, on 2004 I posted on Gamedev.net (I am the poster Maquiavel) forums a topic with links to sprites' sites: http://www.gamedev.net/community/forums/topic.asp?topic_id=272386. It is still rocking! Although most of the listed sprites are copyrighted, they may be useful to in-house prototyping or just curiosity. I don't know why I made that topic, since I'm only make into game development now, maybe because I love to see those sheets full of colors and life.
  • We get performance if we put all of our animations in one big sprite sheet (max. dimension: 1024x1024). That can be easily accomplished using Zwoptex.
  • Tiled has tile layers and object layers (boxes around portions of the map to specify events).
  • Cocos' convertToNodeSpace: as an example the user clicks in the viewpoint (scrolling camera) at 100,100. But let's say the map is scrolled to 800,800. convertToNodeSpace matches the touch with the scrolling / node zoom / etc.
  • CCTMXTiledMap: it's a CCNode (position, scale, rotation, etc). Its children are layers (CCTMXLayer) of the map generated with Tiled. CCTMXLayer is a CCSpriteSheet, which means we can only have one tileset per layer.
  • Helper function to convert from screen coordinates to tile coordinates:
    // Helper: Position to Tile Coord (upper left, increments each tile)
    // @author http://www.raywenderlich.com
    - (CGPoint)tileCoordForPosition:(CGPoint)position {
        int x = position.x / _tileMap.tileSize.width;
        int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
        return ccp(x, y);
    }

Box2D

  • Box2D

    When giving values to Box2D: pixels/PTM_RATIO

  • When getting values from Box2D: boxvalue * PTM_RATIO (obviously)
  • Mouse joint: makes a body move toward a specific point. Requires:
    - 2 bodies: static or moving body and body you want to move (Box2D manual note: All joints are connected between two different bodies. One body may static. Joints between static and/or kinematic bodies are allowed, but have no effect and use some processing time.).
    - Target: where to move.
    - Collide Connected: when both bodies collide, treat as collision.
    - Max Force: less force, less reaction from our movements.
  • setAwake: for objects that sleep.
  • linearDamping: to reduce speed from a moving body.
  • Contact Listener: it will be called by Box2D when 2 objects begin to touch and stop touching. Btw, we can't store references to the contact points, because Box2D reuses them. We need to copy them inside our contact listener.
  • setAsBox: we have to pass half dimensions.

Learning Diary #8: A*, Cocos2d and Box2d concepts

 

05/Jul/10

A* Search algorithm

Cocos2D

  • Transform anchor: coordinates used by Cocos to rotate objects on screen. For sprites, the default is the middle of the image.
  • ccp(x, y) is Cocos shortcut macro to CGPointMake.
  • Scene: a container of all the stuff you’re going to show on screen in a specific part of your game: Main menu, level, help, highscores (each one is a different scene).
  • Hierarchy: Scene : Layer : Node : Node.

    Cocos2D Scene and Layers

    Cocos2D Scene and Layers

  • A node can be a sprite, label, etc. Note that a sprite may have a child sprite.
  • Add nodes to a layer with addChild method.
  • Scenes have depth ordering (z): lower Z objects appear behind higher Z ones (er, ok, very old thing, we learn this when we are 8? but always worth noting :) ).
  • Cocos auto dealloc all children.
  • Run an action:
    [node (sprite, etc) runAction:[CCSequence (or CCSpawn) actions:action1, action2, CCCallFunN (callback on the object when the actions are performed)]].
  • How to load a sprite:
    CCSprite *sprite = [CCSprite spriteWithFile:@"image.png" rect:CGRectMake(0, 0, w, h)];
    sprite.position = ccp(x, y);

Coordinates

  • UIKit: 0,0 from top left.
  • Cocos2d: 0,0 from bottom left.
  • Sprites: 0,0 from bottom left.

Box2D

  • Box units are in “meters” ranging from 0.1 to 10. Use macro: PTM_RATIO 32.0 to convert pixels to meters, example:
    b2Vec2(winSize.width/PTM_RATIO, 0);
  • World object: manages all the objects and the physics simulation.
  • Bodies: movable and static.

Body

  1. Definition (b2BodyDef): The body definition holds the data needed to create and initialize a body – position, velocity, type.
  2. Object (b2Body): “body factory”: myWorld->CreateBody(&bodyDef);
  3. Shape (b2PolygonShape, b2CircleShape, etc): geometry you wish to simulate.
  4. Fixture definition (b2FixtureDef): binds a shape to a bodys. Shapes don’t know about bodies, that’s why we need fixtures. Defines:
    4.1) Density (more dense, more mass = harder to move).
    4.2) Friction (0…1 – how hard for objects to slide against each other).
    4.3) Restitution (how “bouncy” is an object. 0 = no bounce, 1 = perfectly elastic).
  5. Fixture object (b2Fixture): b2Fixture* myFixture = myBody->CreateFixture(&fixtureDef);. A body may have any number of fixtures.

Cocos2d Image credits: Official wiki

Learning Diary #7: Cocos2D example codes and Box2D engine

 

30/Jun/10

  • I bought an iPod Touch and already got my Apple Developer Certificate.
  • Box2D

  • Started playing around with Cocos2D test codes. It comes packed with a lot of examples, being pretty easy and straightforward to learn. I’m loving it. It makes everything easy.
  • Decided I’ll use Box2D to the physics. It has a complete documentation, as I read it is more mature, and it is C++ (which I prefer instead of straight C). Also, I understood easier its code comparing to Chipmunk.
  • Spent the rest of the day trying to fix the timestep from Box2D examples which come with Cocos2D. I was following the famous Gaffer’s article and managed to put the code and make it worked, but I don’t know where I failed that the code started running at 50-60 fps, and then when I added 15 boxes the fps dropped to 0.5 ~ 1.0! Until now I don’t know how to fix it.
  • At least I got a good Box2D understanding and got some more knowledge about Game performance and when dealing with a lot of objects in the same screen.
  • Also downloaded some examples using Box2D, but none of them have fixed timestep.

Source Code from Box2D example with fixed timestep:

-(void) tick: (ccTime) dt
{
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
	float fixedTimeStep = 1.0/60.0f;
	float timeToRun = dt + timeAccumulated;	

	while(timeToRun >= fixedTimeStep) {
		world->Step(fixedTimeStep, velocityIterations, positionIterations);

		//Iterate over the bodies in the physics world
		for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
		{
			if (b->GetUserData() != NULL) {
				//Synchronize the AtlasSprites position and rotation with the corresponding body
				CCSprite *myActor = (CCSprite*)b->GetUserData();
				myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
				myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
			}
		}

		timeToRun -= fixedTimeStep;
	}

	timeAccumulated = timeToRun;
}

Note that I implemented the accumulator. I think I’m going wrong when stepping Box2D. But I’ll discover that later.

Links:

Resources:

Image credits: Box2D logo, from http://box2d.org/

Learning Diary #5: iPhone inspirational stories and Cocos2D concepts

 

26/Jun/10

Developers Stories

  • iPhone Layout

    15 years old spanish teen that made a successful iPhone game and contributes to Cocos2D (wrote CCArray as a substitute to NSArray = performance): Manuel Martínez-Almeida from http://abstractionworks.com/ – I started when I was 8, but with web programming, so very impressive! Congratulations Manuel!

  • The top AppStore sellers have some good inspirational stories: Lima Sky (Doodle Jump – 5 million downloads), Demiforce (Trism – one of the first iPhone game dev and “From Rags to Riches“), Ethan Nicholas (iShoot history).
  • Ethan Nicholas, developer of a tank artillery game called iShoot, told Wired.com he quit his job the day his app rose to No. 1 in the App Store, earning him $37,000 in a single day.

  • All of Pangeasoft‘s (Brian Greenstone) videos are educative, fun and inspirational. Engimo‘s history and video is very interesting. Also don’t forget to check all of his videos.

Cocos2D

Some Cocos2D API:

  • Actions simultaneously: Spawn
  • Actions one after another: Sequence
  • CallFunc: put it as a param to a sequence/spawn
  • Repeat/RepeatForever

General

Learning Diary #4: Switching to Cocos2D and Objective-C

 

24/Jun/10

  • Cocos2D

    After studying deep the licenses behind Unity I decided I’m not going to use it anymore.

  • Since most of the games I have in mind are 2D there is no need to Unity (but this can be controversial to my first entry: programming the game X programming the engine).
  • My choice now is Cocos2D. Why? There are so many published games that use Cocos2D, so it has proven its value. Also, I’ll save a thousand dollars, since cocos is free and open source.
  • The only drawback (or not) is that I’ll have to code stuff that Unity makes painless, but I think I can get along with that pretty fast. Cocos2D has hundreds of resources, and a lot of open source games and code examples. Also, most cocos powered games are very polished, and of all kinds. I just felt in love with Cocos2d!
  • Studied a lot about the iPhone touches and multi touch.

Objective-C

I’ve studied Objective-C on March, so I still have the notes and the mind map I made. It was easy to refresh the mind about it. I like this language – it makes me feel “warm and safe”.

  • NSCoding – serializer.
  • NSKeyedArchiver
  • NSUserDefaults
    [NSUserDefaults standardUserDefaults]
  • Selectors: function pointers. The type is SEL.
  • SEL compare Selector = @selector(compare:options:)
  • SEL name = NSSelectorFromString / NSStringFromSelector
  • To test:
    [object respondsToSelector:selectorVar]
  • To call:
    [object performSelector:selectorVar]

Books: