cocos2d for iPhone - WordPress.com · 2009-12-25 · Demo Suite •In addition to the project...

Preview:

Citation preview

cocos2d for iPhoneiPhone and iPod touch Development

Fall 2009 — Lecture 25

Questions?

Announcements

• Details about final project deliverables will be posted in the next day or so

Today’s Topics

• What is cocos2d?

• Getting Started with cocos2d

• cocos2d Basics

• cocos2d Classes

• Hello World

• Simple Example

• Sprites

• Animating Sprites

• Maps

• Physics and Collision Detection

Notes

• Portions of tonight’s lecture adapted from 360iDev cocos2d talk by Serban Porumbescu

• I’m using sprites that surely fall under some copyright

• If you use sprites in your app (beyond educational purposes) you’ll want to get create your own of find some that are open source

What is cocos2d?

cocos2d

• cocos2d is a framework for building 2D games, demos, and other graphical/interactive applications

• Original implementation written in Python

• Open source — BSD license

• http://www.cocos2d.org/

cocos2d for iPhone

• cocos2d for iPhone is a port of the Python-based cocos2d to Objective-C and the iPhone OS

• Open source — GNU LGPL v3 with extensions (see site)

• http://www.cocos2d-iphone.org/

Apps using cocos2d

• Over 200 games in app store using cocos2d

Main Features

• Scene management (workflow)

• Transitions between scenes

• Sprites and Sprite Sheets

• Effects: Lens, Ripple, Waves, Liquid, Twirl, etc.

• Actions (behaviors):

• Trasformation Actions: Move, Rotate, Scale, Jump, etc.

• Composable actions: Sequence, Spawn, Repeat, Reverse

• Ease Actions: Exp, Sin, Cubic, etc.

• Misc actions: CallFunc, OrbitCamera

Main Features

• Basic menus and buttons

• Integrated physics engine (both Box2d and Chipmunk)

• Particle system

• Text rendering support (variable and fixed width fonts)

• Texture Atlas support

• Tile Map support

• Parallax scrolling support

• Sound support

• Streak Motion support

Main Features

• High Score server (Cocos Live)

• Touch/Accelerometer support

• Portrait and Landscape mode

• Integrated Pause/Resume

• Fast Textures: Supports PVRTC textures, 16-bit textures and 32-bit textures

• Open Source: Compatible with open and closed source projects

• OpenGL ES 1.1 based

• Community supported (forum, IRC)

Getting Started

Getting the Source

• You can grab the source code as a tarball form the project’s Google code page at...

• http://code.google.com/p/cocos2d-iphone/

• cocos2d provides an installer script (install_template.sh) that you can run from the shell to install 3 different cocos2d project templates...

Demo Suite

• In addition to the project templates, cocos2d also comes with a project (cocos2d-iphone.xcodeproj) that contains a detailed demo suite that shows how to use the various APIs

• However, people frequently have issues running the built-in demo apps...

• You need to be sure to set the “Active Target” and “Active Executable” in Xcode, as this project can build many apps

Demo Suite

cocos2d Basics

cocos2d Basics

• A game is composed of multiple scenes

• Each scene is composed from some number of layers

• Layers capture user interaction and contain sprites

• The director manages the scenes of the application

Scenes

Intro Menu Level 1 Cutscene 1 Level 2 Winning Cutscene

Losing Cutscene

High Scores

Layers

• A layer takes up the entire screen space

• Layers can be setup to handle touches and accelerometer events

• Layers can be composed of other layers, sprites, etc.

Layers within a Scene

Sprites

• A sprite is an image that can move within a larger graphic

• Sprites may be animated, typically by cycling through a number of different images

• Typically each sprite has a set of rules that govern how it moves and behaves when it comes in contact with another sprite

Director

• Manages moving between different scenes of the application

• Handles pausing and running scenes

• Sets up OpenGL ES

• Layer asks Director to change scene

cocos2d Classes

Important cocos2d Classes

• CocosNode

• Scene

• Layer

• Director

• Sprite

• AtlasSprite

• AtlasSpriteManager

CocosNode

• Most objects in cocos2d inherit from CocosNode

• Anything that gets drawn, or contains things that get drawn is a CocosNode

• Key aspects of CocosNodes...

• Can contain other CocosNodes

• Can schedule periodic callbacks

• Can execute actions

CocosNode

• Position

• Scale

• Rotation

• Camera

• GridBase

• Anchor point

• Size

• Visibility

• Z-order

• OpenGL z-position

CocosNode

• Common CocosNode subclasses include...

• Scene

• Layer

• Sprite

• Menu

Scene

• Subclass of CocosNode

• A Scene is basically a container in which to place other drawable elements

• Scene has its anchor point (by default) at the center of the screen

• It’s a good practice to a Scene as the parent of your nodes

Layer

• Subclass of CocosNode

• Implements the UIAccelerometerDelegate, StandardTouchDelegate and TargetedTouchDelegate protocols

• Basically gets all of CocosNode’s functionality via inheritance and adds the following...

• Ability to receive iPhone touch events

• Ability to receive accelerometer data

StandardTouchDelegate

• Nearly identical to UIResponder’s touch events, except you can return kEventHandled (YES) to prevent further event propagation...

@protocol TouchEventsDelegate <NSObject>@optional- (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;- (BOOL)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;- (BOOL)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;@end

TargetedTouchDelegate

• There’s also a targeted version of a touch delegate that facilitates 2 things...

• You needn’t unwrap touched from an NSSet — you get a single touch per call

• You can claim (prevent propagation) of a touch by returning YES in the began method

@protocol TargetedTouchDelegate <NSObject>- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event;@optional- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event;- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event;- (void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event;@end

Sprite

• Subclass of TextureNode, which is a subclass of CocosNode

• Capable of rendering a texture on the screen

• Supports frames (animation)

AtlasSprite

• In general, try to use AtlasSprites over Sprites, as they are significantly faster

• Boils down to how textures are handled in OpenGL ES

Menu & MenuItem

• Menu is a subclass of CocosNode

• Menu provides a mechanism for creating menus within your application

• Menus can only accept MenuItem objects as children

• MenuItem has several subclasses for different menu item types...

• MenuItemLabel

• MenuItemSprite

• MenuItemToggle

Director

• Class that creates and handles the main window

• Manages how and when to execute the scenes

Hello World

New Project

• The cocos2d Application template creates a project that contains all of the necessary source files to get started...

HelloWorldAppDelegate.m

#import "HelloWorldAppDelegate.h"#import "cocos2d.h"#import "HelloWorldScene.h"

@implementation HelloWorldAppDelegate

@synthesize window;

- (void) applicationDidFinishLaunching:(UIApplication*)application { // Init the window window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];! // cocos2d will inherit these values [window setUserInteractionEnabled:YES];! [window setMultipleTouchEnabled:YES];! // Try to use CADisplayLink director // if it fails (SDK < 3.1) use Threaded director if( ! [Director setDirectorType:CCDirectorTypeDisplayLink] ) [Director setDirectorType:CCDirectorTypeDefault];! // Use RGBA_8888 buffers // Default is: RGB_565 buffers [[Director sharedDirector] setPixelFormat:kPixelFormatRGBA8888];! // ...

HelloWorldAppDelegate.m

// ...! // Create a depth buffer of 16 bits // Enable it if you are going to use 3D transitions or 3d objects //! [[Director sharedDirector] setDepthBufferFormat:kDepthBuffer16];! // Default texture format for PNG/BMP/TIFF/JPEG/GIF images // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565 // You can change anytime. [Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];!! // before creating any layer, set the landscape mode [[Director sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft]; [[Director sharedDirector] setAnimationInterval:1.0/60]; [[Director sharedDirector] setDisplayFPS:YES];! // create an openGL view inside a window [[Director sharedDirector] attachInView:window];! [window makeKeyAndVisible];!!! ! ! [[Director sharedDirector] runWithScene: [HelloWorld scene]];}

// ...

HelloWorldAppDelegate.m

// ...

- (void)applicationWillResignActive:(UIApplication *)application {! [[Director sharedDirector] pause];}- (void)applicationDidBecomeActive:(UIApplication *)application {! [[Director sharedDirector] resume];}- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {! [[TextureMgr sharedTextureMgr] removeUnusedTextures];}- (void)applicationWillTerminate:(UIApplication *)application {! [[Director sharedDirector] end];}- (void)applicationSignificantTimeChange:(UIApplication *)application {! [[Director sharedDirector] setNextDeltaTimeZero:YES];}- (void)dealloc {! [[Director sharedDirector] release];! [window release];! [super dealloc];}

@end

HelloWorldScene.h

// When you import this file, you import all the cocos2d classes#import "cocos2d.h"

// HelloWorld Layer@interface HelloWorld : Layer{}

// returns a Scene that contains the HelloWorld as the only child+(id) scene;

@end

HelloWorldScene.m

// Import the interfaces#import "HelloWorldScene.h"

// HelloWorld implementation@implementation HelloWorld

+(id) scene {

! // 'scene' is an autorelease object.! Scene *scene = [Scene node];!! // 'layer' is an autorelease object.! HelloWorld *layer = [HelloWorld node];!! // add layer as a child to scene! [scene addChild: layer];!! // return the scene! return scene;}

// ...

HelloWorldScene.m

// ...

// on "init" you need to initialize your instance-(id) init { // always call "super" init // Apple recommends to re-assign "self" with the "super" return value if( (self=[super init] )) {! ! // create and initialize a Label Label* label = [Label labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:64];

// ask director the the window size CGSize size = [[Director sharedDirector] winSize];! // position the label on the center of the screen label.position = ccp( size.width /2 , size.height/2 );! ! // add the label as a child to this Layer [self addChild: label]; } return self;}

// ...

HelloWorldScene.m

// ...

// on "dealloc" you need to release all your retained objects- (void) dealloc {

! // in case you have something to dealloc, do it in this method! // in this particular example nothing needs to be released.! // cocos2d will automatically release all the children (Label)!! // don't forget to call "super dealloc"! [super dealloc];}

@end

Hello World

• You will probably need to set the Active SDK (under Overview) to build and test the app

• The empty project template gets you up and running with a “Hello World” project using cocos2d...

A Simple Example

A Simple Example

MenuTransitionsAppDelegate.m

#import "MenuTransitionsAppDelegate.h"#import "cocos2d.h"#import "MainMenuScene.h"

@implementation MenuTransitionsAppDelegate

@synthesize window;

- (void) applicationDidFinishLaunching:(UIApplication*)application { // Init the window window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];! // cocos2d will inherit these values [window setUserInteractionEnabled:YES];! [window setMultipleTouchEnabled:YES];! // Try to use CADisplayLink director // if it fails (SDK < 3.1) use Threaded director if( ! [Director setDirectorType:CCDirectorTypeDisplayLink] ) [Director setDirectorType:CCDirectorTypeDefault];! // Use RGBA_8888 buffers // Default is: RGB_565 buffers [[Director sharedDirector] setPixelFormat:kPixelFormatRGBA8888];! // ...

MenuTransitionsAppDelegate.m

// ...! // Create a depth buffer of 16 bits // Enable it if you are going to use 3D transitions or 3d objects //! [[Director sharedDirector] setDepthBufferFormat:kDepthBuffer16];! // Default texture format for PNG/BMP/TIFF/JPEG/GIF images // It can be RGBA8888, RGBA4444, RGB5_A1, RGB565 // You can change anytime. [Texture2D setDefaultAlphaPixelFormat:kTexture2DPixelFormat_RGBA8888];! // before creating any layer, set the landscape mode [[Director sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft]; [[Director sharedDirector] setAnimationInterval:1.0/60]; [[Director sharedDirector] setDisplayFPS:YES];! // create an openGL view inside a window [[Director sharedDirector] attachInView:window];! [window makeKeyAndVisible];!!! ! MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] runWithScene:scene];!}

// ...

MenuTransitionsAppDelegate.m

// ...

- (void)applicationWillResignActive:(UIApplication *)application { [[Director sharedDirector] pause];}- (void)applicationDidBecomeActive:(UIApplication *)application { [[Director sharedDirector] resume];}- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { [[TextureMgr sharedTextureMgr] removeUnusedTextures];}- (void)applicationWillTerminate:(UIApplication *)application { [[Director sharedDirector] end];}- (void)applicationSignificantTimeChange:(UIApplication *)application { [[Director sharedDirector] setNextDeltaTimeZero:YES];}- (void)dealloc { [[Director sharedDirector] release]; [window release]; [super dealloc];}

@end

MainMenuScene.h

#import <UIKit/UIKit.h>#import "cocos2d.h"

@interface MainMenuScene : Scene { }

@end

@interface MainMenuLayer : Layer { }

-(void)newGame:(id)sender;-(void)help:(id)sender;

@end

MainMenuScene.m

#import "MainMenuScene.h"#import "World1Level1Scene.h"#import "HelpScene.h"

@implementation MainMenuScene

- (id) init { self = [super init]; if (self != nil) { Sprite *bg = [Sprite spriteWithFile:@"main-background.png"]; [bg setPosition:ccp(240, 160)]; [self addChild:bg z:0]; [self addChild:[MainMenuLayer node] z:1]; } return self;}

@end

// ...

MainMenuScene.m

// ...

@implementation MainMenuLayer

- (id) init { self = [super init]; if (self != nil) { [MenuItemFont setFontSize:48]; [MenuItemFont setFontName:@"Marker Felt"]; MenuItem *start = [MenuItemFont itemFromString:@"New Game" target:self selector:@selector(newGame:)]; MenuItem *help = [MenuItemFont itemFromString:@"Help" target:self elector:@selector(help:)]; Menu *menu = [Menu menuWithItems:start, help, nil]; [menu alignItemsVertically]; [self addChild:menu]; } return self;}

// ...

MainMenuScene.m

// ...

-(void)newGame:(id)sender { World1Level1Scene *scene = [World1Level1Scene node]; [[Director sharedDirector] replaceScene:scene];!!}

-(void)help:(id)sender { HelpScene *scene = [HelpScene node]; [[Director sharedDirector] replaceScene:scene];!!}

@end

World1Level1Scene.h

#import <UIKit/UIKit.h>#import "cocos2d.h"

@interface World1Level1Scene : Scene {}@end

@interface World1Level1Layer : Layer {}@end

World1Level1Scene.m

#import "World1Level1Scene.h"#import "MainMenuScene.h"

@implementation World1Level1Scene- (id) init { self = [super init]; if (self != nil) { [self addChild:[World1Level1Layer node] z:0]; } return self;}@end

// ...

World1Level1Scene.m

// ...@implementation World1Level1Layer- (id) init { self = [super init]; if (self != nil) {

// respond to touches isTouchEnabled = YES;! ! // create and initialize a Label Label *label = [Label labelWithString:@"World 1 Level 1" fontName:@"Marker Felt" fontSize:64];! ! // ask director the the window size CGSize size = [[Director sharedDirector] winSize];! ! // position the label on the center of the screen label.position = ccp( size.width /2 , size.height/2 );! ! // add the label as a child to this Layer [self addChild: label]; } return self;}

// ...

World1Level1Scene.m

// ...

- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] replaceScene:scene]; return kEventHandled;}

@end

HelpScene.h

#import <UIKit/UIKit.h>#import "cocos2d.h"

@interface HelpScene : Scene {}@end

@interface HelpLayer : Layer {}@end

HelpScene.m

#import "HelpScene.h"#import "MainMenuScene.h"

@implementation HelpScene- (id) init { self = [super init]; if (self != nil) { Sprite *bg = [Sprite spriteWithFile:@"help-background.png"]; [bg setPosition:ccp(240, 160)]; [self addChild:bg z:0]; [self addChild:[HelpLayer node] z:1]; } return self;}@end

// ...

HelpScene.m

// ... @implementation HelpLayer- (id) init { self = [super init]; if (self != nil) {! ! // respond to touches isTouchEnabled = YES;! ! // create and initialize a Label Label *label = [Label labelWithString:@"Help Screen" fontName:@"Marker Felt" fontSize:64];! ! // ask director the the window size CGSize size = [[Director sharedDirector] winSize];! ! // position the label on the center of the screen label.position = ccp( size.width /2 , size.height/2 );! ! // add the label as a child to this Layer [self addChild: label]; } return self;}

// ...

HelpScene.m

// ...

- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] replaceScene:scene]; return kEventHandled;}

@end

Sprites

Sprites

• For this example, we’ll extend out World1Level1Scene to be able to display a player (Mario) and move animate moving him to a new location when we press on the screen

World1Level1Scene.m

#import "World1Level1Scene.h"#import "MainMenuScene.h"

@implementation World1Level1Scene- (id) init { self = [super init]; if (self != nil) { [self addChild:[World1Level1Layer node] z:0]; } return self;}@end

// ...

World1Level1Scene.m

// ...

@implementation World1Level1Layer- (id) init { self = [super init]; if (self != nil) {

// respond to touches isTouchEnabled = YES;

player = [[Sprite spriteWithFile:@"mario.png"] retain]; [self addChild: player z:1]; CGSize s = [[Director sharedDirector] winSize]; [player setPosition: ccp(s.width/2, s.height/2)];

} return self;}

// ...

World1Level1Scene.m

// ...

- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if ([touch tapCount] == 2) { MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] replaceScene:scene]; } else { CGPoint pt = [touch locationInView:touch.view]; // x, y swapped since in landscape id actionTo = [MoveTo actionWithDuration: 1 position:ccp(pt.y, pt.x)]; [player runAction: actionTo]; } return kEventHandled;}

- (void) dealloc { [player release]; [super dealloc];}

@end

The Resulting App

Animating Sprites

Animating Sprites

• Extending the previous example, this time in addition to moving the player to a new location using a move animation, we’ll also use a custom animation to cycle through various images to make it appear that he’s running

World1Level1Scene.m

#import "World1Level1Scene.h"#import "MainMenuScene.h"

@implementation World1Level1Scene- (id) init { self = [super init]; if (self != nil) { [self addChild:[World1Level1Layer node] z:0]; } return self;}@end

// ...

World1Level1Scene.m

// ...

@implementation World1Level1Layer- (id) init { self = [super init]; if (self != nil) {

// respond to touches isTouchEnabled = YES;

player = [[Sprite spriteWithFile:@"mario0.png"] retain]; [self addChild: player z:1]; CGSize s = [[Director sharedDirector] winSize]; [player setPosition: ccp(s.width/2, s.height/2)];

} return self;}

// ...

World1Level1Scene.m

// ...

- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch = [touches anyObject]; if ([touch tapCount] == 2) { MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] replaceScene:scene]; } else { CGPoint pt = [touch locationInView:touch.view]; Animation* animation = [Animation animationWithName:@"run" delay:0.1f]; [animation addFrameWithFilename: @"mario1.png"]; [animation addFrameWithFilename: @"mario2.png"]; id action = [Animate actionWithAnimation: animation]; id actionRepeat = [Repeat actionWithAction:action times:5]; [player runAction:actionRepeat]; id actionTo = [MoveTo actionWithDuration: 1 position:ccp(pt.y, pt.x)]; [player runAction: actionTo]; } return kEventHandled;}- (void) dealloc { [player release]; [super dealloc];}

@end

The Resulting App

Maps

Maps

• The cocos2d library also supports being able to import world maps in one of two formats...

• TMX Tile Map format (newer, more flexible, recommended)

• PGU Tile Map format (older, deprecated)

Map Editors

• cocos2d supports maps exported from the Tiled map editor

• http://mapeditor.org/

• This free Java-based program allows you...

• Create maps

• Load tiles from images

• Paint your map

• Export the map in a TMX format

Tiled

• The Tiled editor is an executable jar file

• An easy way to launch it is to open up Terminal, cd into the directory containing the jar file and issue the following command...

bash-3.2$ java -jar tiled.jar

Creating a New Map

• To create a new map in Tiled, select File → New...

• Tiled supports several different map views, Orthogonal is a normal 2D rectangular grid

• You can specify the size of the map and the size of the tiles

The Empty Map

Creating a New Tileset

New Tileset

• In the New Tileset dialog, you can specify the size of your tiles and most importantly import an image to be used as your “palette” from which to draw your world

The Imported Tileset

Our Drawn World

Exporting

• When done creating your world, save the file as a TMX type

• You can then copy in the image used for the palette and the saved TMX map file into your project

• Next, we’ll change our World1Level1Scene code to load the map instead

World1Level1Scene.m

#import "World1Level1Scene.h"#import "MainMenuScene.h"

enum {! kTagTileMap = 1,};

@implementation World1Level1Scene- (id) init { self = [super init]; if (self != nil) { [self addChild:[World1Level1Layer node] z:0]; } return self;}@end

// ...

World1Level1Scene.m

// ...

@implementation World1Level1Layer- (id) init { self = [super init]; if (self != nil) {

// respond to touches isTouchEnabled = YES;! ! TMXTiledMap *map = [TMXTiledMap tiledMapWithTMXFile:@"world1level1.tmx"]; [self addChild:map z:0 tag:kTagTileMap]; } return self;}

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

// ...

World1Level1Scene.m

// ...

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { return YES;}

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint touchLocation = [touch locationInView: [touch view]];! CGPoint prevLocation = [touch previousLocationInView: [touch view]];!! touchLocation = [[Director sharedDirector] convertToGL: touchLocation]; prevLocation = [[Director sharedDirector] convertToGL: prevLocation];! CGPoint diff = ccpSub(touchLocation,prevLocation);! CocosNode *node = [self getChildByTag:kTagTileMap]; CGPoint currentPos = [node position]; [node setPosition: ccpAdd(currentPos, diff)];}

// ...

World1Level1Scene.m

// ...

- (void)ccToucheEnded:(UITouch *)touch withEvent:(UIEvent *)event { if ([touch tapCount] == 2) { MainMenuScene *scene = [MainMenuScene node]; [[Director sharedDirector] replaceScene:scene]; }}

- (void) dealloc { [super dealloc];}

@end

The Resulting App

Physics & Collision Detection

Physics & Collision Detection

• Physics engines model variables such as mass, position, rotation, velocity, etc and simulate effects of objects interacting with each other

• The cocos2d library comes with 2 different physics/collision detection systems integrated right in

• You can use either Box2d or Chipmunk

Box2d

• Box2D is a feature rich 2d rigid body physics engine

• Written in “straight” C++ (no STL usage)

• Licensed under the zlib license

• http://www.box2d.org

Chipmunk

• Fast and lightweight 2D rigid body physics library in C

• Licensed under the MIT license

• http://code.google.com/p/chipmunk-physics/

Demos

• Check out the physics demos that come with cocos2d to get a feel for what’s possible...

Additional Resources

• Tiled Homepage

• http://mapeditor.org

• Box2d Homepage

• http://www.box2d.org

• Chipmunk Homepage

• http://code.google.com/p/chipmunk-physics/

Recommended