A SpaceManager Game

This article is going to build upon the basics described in the previous SpaceManager article written some time ago which can be found here: http://www.cocos2d-iphone.org/archives/677

About the Author:

My name is Rob, I’m one of the guys working under the mobile bros. LLC title. We’ve released a few games in the recent years, all using SpaceManager, including: Pachingo, Trundle, and Kill Timmy. I am personally interested in physics myself and always looking for new ways to incorporate them in our games.

Goals

Today’s goal is to design a basic game using Cocos2d, Chipmunk, and SpaceManager. I believe the best lessons are those learned from example, so for this article I’ll walk you through building a small example of a game and show off some of the features of SpaceManager. Some of the things we’ll demonstrate here are:

* Save and Load entire game state
* Explosions in Chipmunk
* Creating a debug-layer
* Using impulses
* Retina Support

So what type of game should we do… perhaps one where we slingshot grenades at structures hoping to kill some kind of ninja animal inside? Sounds like a plan, so lets dive right in. This tutorial will use Cocos2d 0.99.5 and SpaceManager 0.0.6. I HIGHLY recommend you download the accompanying source code for this article so you can follow along; this will have everything you need and you can skip the setup steps. Source is found here:

Download the Source-Code: GrenadeGame.zip

Edit: Updated source location

Basic SpaceManager Game Setup:

You’ll want to create a new project, I’m naming mine GrenadeGame and I’m choosing the Cocos2d Chipmunk Application template. Once created, jump into the root of your project directory in Finder and place the “src” folder from your previously downloaded SpaceManager folder right here in the root and rename it from “src” to “SpaceManager”…. or perhaps wherever you want below the root.

No go back to Xcode and add the “SpaceManager” directory to your project… almost done. In order to get GrenadeGame to compile you must go to XCode’s menu bar and click Project->Edit Active Target “GrenadeGame”, and then find the “Header Search Paths” setting and add a new value; this value being:

“$(SRCROOT)/libs/Chipmunk/include/chipmunk”

Please keep the quotes or XCode will get it wrong most likely. Now you should be able to compile and run! You should see the default grossini dance for now.

Doing Some Good Stuff:

Now that your project is all set up, go ahead and delete both the HelloWorldScene files and then add a new Objective-C class; I’m calling mine simply “Game”. I then modify the .h to look like this:

#import "SpaceManagerCocos2d.h"
 
@interface Game : CCLayer
{
	SpaceManagerCocos2d *smgr;
}
 
+(id) scene;
@end

and the .m to look like this:

#import "Game.h"
 
@interface Game (PrivateMethods)
@end
 
@implementation Game
 
+(id) scene
{
	CCScene *scene = [CCScene node];
	[scene addChild:[Game node]];
	return scene;
}
 
- (id) init
{
	[super init];
 
	[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];
 
	//allocate our space manager
	smgr = [[SpaceManagerCocos2d alloc] init];
	smgr.constantDt = 1/55.0; 
 
	return self;
}
 
- (void) dealloc
{
	[smgr release];
	[super dealloc];
}
 
- (BOOL)ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event
{
	return YES;
}
 
- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
}

So nothing too crazy going on here, I’ve setup some basic methods for setup, teardown, and handling touches. At this point I’m wanting to see some visual feedback though so I create a function to get some shapes simulating in chipmunk:

- (CCNode*) createBlockAt:(cpVect)pt
			width:(int)w
			height:(int)h
			mass:(int)mass
{
	cpShape *shape = [smgr addRectAt:pt mass:mass width:w height:h rotation:0];
	cpShapeNode *node = [cpShapeNode nodeWithShape:shape];
	node.color = ccc3(56+rand()%200, 56+rand()%200, 56+rand()%200);
 
	[self addChild:node];
 
	return node;
}

So you can see here I’m just creating a rectangle block with a given mass, attaching it to a cpShapeNode (which will just draw a primitive representation of the shape) and then adding that node to “self” aka the game’s visible layer. I use rand() here just to get some color variation going as I plan to call this function a bunch of times. Now that I have this function I can modify the init function to use it and tell SpaceManager to start simulating:

	[self createBlockAt:cpv(240,200) width:12 height:40 mass:100];
	[smgr start];


I add these two lines right after I allocate smgr in the init, and I run the app. Whoops! the block I created shows up but falls immediately off the screen. I guess I need some sort of containment rectangle around the screen. Add this call right before createBlockAt:

	[smgr addWindowContainmentWithFriction:1.0 elasticity:1.0 inset:cpvzero];

Phew! Upon running this time, the block falls down, bounces a bit, and comes to rest.

The black background is noticeable at this point so I pop one in at the bottom of init using an image I drew up real quick in Paint.NET and also ask smgr to add some static segment shapes to act as my physical terrain.

	CCSprite *background = [CCSprite spriteWithFile:@"smgrback.png"];
	background.position = ccp(240,160);
	[self addChild:background];
 
	[smgr addSegmentAtWorldAnchor:cpv(72,13) toWorldAnchor:cpv(480,13) mass:STATIC_MASS radius:1];
	[smgr addSegmentAtWorldAnchor:cpv(72,13) toWorldAnchor:cpv(72,133) mass:STATIC_MASS radius:1];
	[smgr addSegmentAtWorldAnchor:cpv(72,133) toWorldAnchor:cpv(0,133) mass:STATIC_MASS radius:1];
 
	[self addChild:[smgr createDebugLayer]];

So what’s this createDebugLayer you ask? Well since I did not attach any shapes to any CCNodes I do not get any visual feedback of what’s going on; adding a debug layer will automatically make visible anything in chipmunk that currently is not; this includes most constraints as well. This allows me to line up my segments with the background image perfectly.

Interactables

I realize the init function is starting to look a bit bloated, but for now I’ll wait to separate things out; because I want to get my ninja animals working first! So I create an Objective-C file again and make my header looks like this:

Ninja.h

#import "SpaceManagerCocos2d.h"
 
@class Game;
 
@interface Ninja : cpCCSprite
{
	Game *_game;
	int _damage;
}
 
+(id) ninjaWithGame:(Game*)game;
-(id) initWithGame:(Game*)game;
 
-(void) addDamage:(int)damage;
 
@end

cpCCSprite is a special type of CCSprite that is similar to cpShapeNode in that it will keep track of a shape and do all the necessary syncing with chipmunk. My plan is to make my Ninja’s basic circle shapes, my class definition looks like this:

Ninja.m

#import "Ninja.h"
#import "Game.h"
 
@implementation Ninja
 
+(id) ninjaWithGame:(Game*)game
{
	return [[[self alloc] initWithGame:game] autorelease];
}
 
-(id) initWithGame:(Game*)game
{
	cpShape *shape = [game.spaceManager addCircleAt:cpvzero mass:50 radius:9];
	[super initWithShape:shape file:@"elephant.png"];
 
	_game = game;
 
	//Free the shape when we are released
	self.spaceManager = game.spaceManager;
	self.autoFreeShape = YES;
 
	return self;
}
 
-(void) addDamage:(int)damage
{
	_damage += damage;
 
	if (_damage > 2)
	{
		[_game removeChild:self cleanup:YES];
	}
}
 
@end


There’s a few things going on here that I’ve just thrown at you, let’s discuss the init method. First of all I create the shape we’re going use, a circle of radius 9. Next I initialize with the shape and a file, I’ve chosen an elephant as the animal to use as you can tell by the filename. I then set the autoFreeShape property to true and because of this I must set the spaceManager as well. I also started creating an addDamage method, I basically want to be able to track any damage done and at some threshold the Ninja should be “destroyed”.

Now I need something to slingshot at these guys! I create another class similar to the Ninja’s……

Bomb.h:

#import "SpaceManagerCocos2d.h"
 
@class Game;
 
@interface Bomb : cpCCSprite
{
	Game *_game;
	BOOL _countDown;
}
 
+(id) bombWithGame:(Game*)game;
-(id) initWithGame:(Game*)game;
 
-(void) startCountDown;
-(void) blowup;
 
@end

Bomb.m:

#import "Bomb.h"
#import "Game.h"
 
@implementation Bomb
 
+(id) bombWithGame:(Game*)game
{
	return [[[self alloc] initWithGame:game] autorelease];
}
 
-(id) initWithGame:(Game*)game
{
	cpShape *shape = [game.spaceManager addCircleAt:cpvzero mass:STATIC_MASS radius:7];
	[super initWithShape:shape file:@"bomb.png"];
 
	_game = game;
	_countDown = NO;
 
	//Free the shape when we are released
	self.spaceManager = game.spaceManager;
	self.autoFreeShape = YES;
 
	return self;
}
 
-(void) startCountDown
{
	//Only start it if we haven't yet
	if (!_countDown)
	{
		_countDown = YES;
 
		id f1 = [CCFadeTo actionWithDuration:.25 opacity:200];
		id f2 = [CCFadeIn actionWithDuration:.25];
 
		id d = [CCDelayTime actionWithDuration:3];
		id c = [CCCallFunc actionWithTarget:self selector:@selector(blowup)];
 
		[self runAction:[CCRepeatForever actionWithAction:[CCSequence actions:f1,f2,nil]]];
		[self runAction:[CCSequence actions:d,c,nil]];
	}
}
 
-(void) blowup
{
	[self.spaceManager applyLinearExplosionAt:self.position radius:100 maxForce:4500];
	[_game removeChild:self cleanup:YES];
}

So the init function should look familiar at this point, and since I already know what the functionality of this bomb will be I implement a “startCountDown” function to basically “blink” the bomb and then call another function, “blowup”, after 3 seconds. The “blowup” function asks the SpaceManager to apply an explosion to all shapes within a radius, and also removes itself. Simple!

Collisions

Almost there, we just need way to launch the bombs at the elephant ninjas and handle a few collisions and such. Lets do the collision handling first. If you created your project through the cocos2d template, you should have a file named “GameConfig.h”; find some empty space before the “#endif” and put these defines in:

#define kNinjaCollisionType		1
#define kGroundCollisionType		2
#define kBlockCollisionType		3
#define kBombCollisionType		4

These are just integer values that chipmunk needs in order to sort out the different types of collision shapes. Now we have to go back to all the place’s we’ve created shapes and fill in their collision_type field appropriately. For example, the Bomb’s init function needs this line now:

shape->collision_type = kBombCollisionType;

Make sure Ninja, Blocks, and the segments we used for Ground also get their collision_type set appropriately. Now we must tell the SpaceManager we are interested in specific collisions, Ninja w/Ground, Ninja w/Block, etc. Put these lines in Game’s init function.

	[smgr addCollisionCallbackBetweenType:kNinjaCollisionType
					otherType:kGroundCollisionType
					   target:self
					 selector:@selector(handleNinjaCollision:arbiter:space:)
					  moments:COLLISION_POSTSOLVE,nil];
	[smgr addCollisionCallbackBetweenType:kNinjaCollisionType
					otherType:kBlockCollisionType
					   target:self
					selector:@selector(handleNinjaCollision:arbiter:space:)
					 moments:COLLISION_POSTSOLVE,nil];
	[smgr addCollisionCallbackBetweenType:kNinjaCollisionType
					otherType:kBombCollisionType
					   target:self
					 selector:@selector(handleNinjaCollision:arbiter:space:)
					  moments:COLLISION_POSTSOLVE,nil];
	[smgr addCollisionCallbackBetweenType:kBombCollisionType
					otherType:kGroundCollisionType
					   target:self
					 selector:@selector(handleBombCollision:arbiter:space:)
					  moments:COLLISION_POSTSOLVE,nil];
	[smgr addCollisionCallbackBetweenType:kBombCollisionType
					otherType:kBlockCollisionType
					   target:self
					 selector:@selector(handleBombCollision:arbiter:space:)
					  moments:COLLISION_POSTSOLVE,nil];

These calls will make SpaceManager call a ninja collision handler and a bomb collision handler immediately after a collision occurs between the types we specified. These two handlers need to be defined in Game:

-(BOOL) handleNinjaCollision:(CollisionMoment)moment arbiter:(cpArbiter*)arb space:(cpSpace*)space
{
	CP_ARBITER_GET_SHAPES(arb, ninjaShape, otherShape);
 
	//Get a value for "force" generated by collision
	float f = cpvdistsq(ninjaShape->body->v, otherShape->body->v);
 
	if (f > 600)
		[(Ninja*)ninjaShape->data addDamage:f/600];
	return YES;
}
 
-(BOOL) handleBombCollision:(CollisionMoment)moment arbiter:(cpArbiter*)arb space:(cpSpace*)space
{
	CP_ARBITER_GET_SHAPES(arb, bombShape, otherShape);
 
	[(Bomb*)bombShape->data startCountDown];
	return YES;
}

The first function will take care of adding damage to the Ninja by calculating a fake force value based on the velocities; if the value is greater than a threshold (600 seemed good) we pass it on as damage. The second function will just activate the bomb’s countdown when it hits anything. Collision stuff is done!

The next step is to actually setup some enemies and launch bombs at them! Setting up the enemies in Game’s init function is easy enough:

	Ninja *ninja = [Ninja ninjaWithGame:self];
	ninja.position = ccp(250,23);
	[self addChild:ninja z:5];

Bomb’s a slightly harder, we want to keep track of them so we create 2 more member variables in Game’s header file.

////
	NSMutableArray	*_bombs;
	Bomb			*_curBomb;
////

And back again in the init we initialize the array and setup our bombs.

	_bombs = [[NSMutableArray array] retain];
 
	for (int i = 0; i < 3; i++)
	{
		Bomb *bomb = [Bomb bombWithGame:self];
		bomb.position = ccp(10+i*16, 143);
		[self addChild:bomb z:5];
		[_bombs addObject:bomb];
	}
 
	[self setupNextBomb];

Make sure you put [_bombs release] in Game’s dealloc method as well. We also need to setup the “current” bomb so we add a function to do just that:

- (void) setupNextBomb
{
	if ([_bombs count])
	{
		_curBomb = [_bombs lastObject];
 
		//move it into position
		[_curBomb runAction:[CCMoveTo actionWithDuration:.7 position:ccp(60,166)]];
 
		[_bombs removeLastObject];
	}
	else
		_curBomb = nil;
}

Here we look to see if any bombs are in the queue and move one into position if there is at least one. I suppose some of you are wondering how I’ve decided on what positions to use in both these previous two snippets. Well this next snippet might explain a bit, it also can go in the Game’s init function for now:

	CCSprite *sling1 = [CCSprite spriteWithFile:@"sling1.png"];
	CCSprite *sling2 = [CCSprite spriteWithFile:@"sling2.png"];
 
	sling1.position = ccp(60,157);
	sling2.position = ccpAdd(sling1.position, ccp(5,10));
 
	[self addChild:sling1 z:10];
	[self addChild:sling2 z:1];

It’s the slingshot! I placed it in the middle left of the screen on the ledge; the “current” bomb is placed in the slingshot, and the other bombs are lined up beside it. We don’t really need a shape for the slingshot itself so it just remains two sprites with differing z orders so that the bomb gets launched “through” it.

To make this slingshot work, we need but only to implement the touch functions on the Game layer.

-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event
{
	CGPoint pt = [self convertTouchToNodeSpace:touch];
	float radiusSQ = 25*25;
 
	//Get the vector of the touch
	CGPoint vector = ccpSub(ccp(60,157, pt);
 
	//Are we close enough to the slingshot?
	if (ccpLengthSQ(vector) < radiusSQ)
		return YES;
	else
		return NO;
}

First of all we implement the began function, we only want to detect at this point if the touch is near the slingshot; if it is we return YES to indicate we’d like to accept the touch. Next is the move function:

-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent *)event
{
	CGPoint pt = [self convertTouchToNodeSpace:touch];
	CGPoint bombPt = ccp(60,166);
 
	//Get the vector, angle, length, and normal vector of the touch
	CGPoint vector = ccpSub(pt, bombPt);
	CGPoint normalVector = ccpNormalize(vector);
	float angleRads = ccpToAngle(normalVector);
	int angleDegs = (int)CC_RADIANS_TO_DEGREES(angleRads) % 360;
	float length = ccpLength(vector);
 
	//Correct the Angle; we want a positive one
	while (angleDegs < 0)
		angleDegs += 360;
 
	//Limit the length
	if (length > 25)
		length = 25;
 
	//Limit the angle
	if (angleDegs > 245)
		normalVector = ccpForAngle(CC_DEGREES_TO_RADIANS(245));
	else if (angleDegs < 110)
		normalVector = ccpForAngle(CC_DEGREES_TO_RADIANS(110));
 
	//Set the position
	_curBomb.position = ccpAdd(bombPt, ccpMult(normalVector, length));
}

We calculate the bomb’s position as you move your touch, we limit both angle and length away from the slingshot. And finally the end function:

-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
	CGPoint vector = ccpSub(ccp(60,166), _curBomb.position);
 
	if (_curBomb)
		[smgr morphShapeToActive:_curBomb.shape mass:30];
 
	[_curBomb applyImpulse:cpvmult(vector, 240)];
 
	[self setupNextBomb];
}

We grab the vector between our launch pt and the bomb’s position, we turn the current bomb’s mass from static (unmoving) to an active mass of 30, and then finally we use the vector to apply an impulse that’ll launch the bomb. We also call our function we made earlier, setupNextBomb, to move the next bomb into position. Give it a try!

We now have the working essence of a game, you can launch bombs, there’s obstacles, and there’s enemies that can be destroyed. I also added a bit of touchup such as “poof” clouds when the enemy dies and particles to the explosion that I won’t discuss here because this article is already getting huge.

Serialization

So our huge init function needs to be broken up first, I create 4 discrete functions to handle all the setup.

- (void) setupShapes;		//setup terrain and blocks
- (void) setupEnemies;		//setup the enemies
- (void) setupBackground;		//setup background image and slingshot
- (void) setupBombs;		//setup the bombs

I leave all the SpaceManager and collision setup in the init, but below I now morph all that junk into something looks a lot more readable:

	[self setupBackground];
 
	//Try to load it from file, if not then create from scratch
	if (!([smgr loadSpaceFromUserDocs:"saved_state.xml" delegate:self]))
	{
		[self setupBombs];
		[self setupEnemies];
		[self setupShapes];
	}
 
	[self setupNextBomb];

As you can see , I ask SpaceManager to load up the chipmunk space from a file; if it fails or doesn’t exist then we create it manually. Notice that we pass a delegate to the load function and that delegate is self, meaning we are able to capture certain events now.

-(BOOL) aboutToReadShape:(cpShape*)shape shapeId:(long)id
{
	if (shape->collision_type == kBombCollisionType)
	{
		Bomb *bomb = [Bomb bombWithGame:self shape:shape];
		[self addChild:bomb z:5];
 
		if (cpBodyGetMass(shape->body) == STATIC_MASS)
			[_bombs addObject:bomb];
	}
	else if (shape->collision_type == kNinjaCollisionType)
	{
		Ninja *ninja = [Ninja ninjaWithGame:self shape:shape];
		[self addChild:ninja z:5];
	}
	else if (shape->collision_type == kBlockCollisionType)
	{
		cpShapeNode *node = [cpShapeNode nodeWithShape:shape];
		node.color = ccc3(56+rand()%200, 56+rand()%200, 56+rand()%200);
		[self addChild:node z:5];
	}
 
	//This just means accept the reading of this shape
	return YES;
}

Since we only care about the reading of shapes, we implement this function; identifying the shapes merely by their collision_type. A STATIC_MASS bomb means its in the queue, so we add it to the array. You may notice that both Bomb and Ninja are calling functions we did not write…. yet. Since they are similar I will just give you the Bomb’s changes:

+(id) bombWithGame:(Game*)game shape:(cpShape*)shape
{
	return [[[self alloc] initWithGame:game shape:shape] autorelease];
}
 
-(id) initWithGame:(Game*)game
{
	cpShape *shape = [game.spaceManager addCircleAt:cpvzero mass:STATIC_MASS radius:7];
	return [self initWithGame:game shape:shape];
}
 
-(id) initWithGame:(Game*)game shape:(cpShape*)shape;
{

So the init now takes a shape, but regular old init will create a shape if called, this lets the read code work…. am I forgetting something? Oh right I need a save function.

-(void)save
{
	[smgr saveSpaceToUserDocs:"saved_state.xml" delegate:self];
}

There! I can call that at any time now and save down the state, and the init will reload it if it is there.

Retina Mode

Well this is a toughie, In the app delegate I usually find the line where FPS is enabled and put this line after it:

[director enableRetinaDisplay:YES];

That’s it! SpaceManager and Chipmunk are indifferent to the change because the point scale does not change. Of course make sure you have the “-hd” on all your hd images which should be twice as large as the originals. You will notice that the simulator runs a bit slower (30 FPS) and since we’re using a constant dt in SpaceManager it will cause the simulation to look slow.

Closing Notes

The included example source has a little bit more that added to it than what I discussed in the article, just to make it more complete and playable. Here’s a list of what else is in there:

- Added a few more block functions to make pillared structures and triangles (for roofs)
- Added a restart button
- Added configurable defines for many of the positions and radii.
- Keep track of enemies killed so that a “You Win” appears when all are dead
- “poof” clouds and particles add to ninja and bomb for special effect

Some notes of what else could go in or be changed:

- A way to load different levels (XML files perhaps?)
- Different Bomb and Ninja types
- The slingshot and touch code could be better encapsulated

Check out the example source, here’s a video of it in action!

83 Responses to “A SpaceManager Game”


  • “>” should be “>” but thx

  • Thanks for posting this sample app using SpaceManager, I tried using it a while back on my “Balls in the Urinal” iOS game but couldn’t get it working.

    Question.. I pulled in this project and began adding types of enemies, animating them etc but all in Xcode 4… now, I my build blows up in the link. I blow away the project restart from the original zip and it compiles and links fine, but again, once I modify it, no link and +999 errors. In both cases I’m using the GCC 4.2 compiler. Any ideas?

    Thanks again!

    Doug Hart

  • @vert – yes haha, I can’t seem to get > to display within a code block correctly.

    @Doug – Ummmm I’m not sure at all, that sounds like crazy talk. I haven’t tried XCode 4 though, but will soon and post back here if any problems occur.

  • why this example is so slow on retina? I get 18fps on the iphone4.

  • 54 responses? Where are the rest of the responses?

    Anyway, I would like to know if someone has tried to code “A way to load different levels (XML files perhaps?)” or if somebody could let me know about a tutorial where I can learn how to do that.

    Thanks.

  • Maybe I missed this somewhere, or maybe it is assumed knowledge…

    Took me awhile to realize that I needed to change a line of code in the GrenadeGameAppDelegate.m:
    [[CCDirector sharedDirector] runWithScene:[HelloWorld scene]];
    should be changed to
    [[CCDirector sharedDirector] runWithScene: [Game scene]];

    This is probably a “Duh” comment for most, but if you’re fairly new to cocos2d or iOS development in general it may be helpful.

    If your app just shows a black screen with 0.0 fps… then this will probably fix your problem.

  • Hi all!

    Maybe this question sounds retarded but I can’t attach and image to ,for example, the triangle roof created in the game with [super initWithShape:shape file:@"roof.png"]; or to any of the pillars. The program crash if I do it.
    So far the only way I have to do this is creating a new class like the Ninja and Bomb one for every single shape and inside the -(id) initWithGame:(Game*)game shape:(cpShape*)shape; attach the image to the shape but it’s a pain.

    Is there any way to attach a image straight to any of our shapes?

    Any help appreciated.

  • @off – nothing about this example is optimized…

    @F – I have no idea how to get to the other responses…

    @Confuse – It’s as easy as changing where the cpShapeNode *node = … line to this instead:

    cpCCSprite *node = [cpCCSprite spriteWithShape:shape file:@"roof.png"];
  • I’m creating my Bomb.m and when I type the cpShape *shape = [game.spaceManager addCircle…

    It’s giving me an error “Property ‘spaceManager’ not found on object of type ‘GameScene *’

    Any clue what’s going on? my .h imports “SpaceManagerCocos2d.h” and the .m imports the GameScene.h

  • @JdNorrod – Most likely you haven’t defined spaceManager as a property of the Game class, something I believe I glossed over. If you download the source and look at the header for something like:

    @property (readonly) SpaceManager *spaceManager;

    and in the .m file for something like:

    @synthesize spaceManager = _smgr;

    then you see what you have to do; I’m not sure if I typed everything “correct” just now.

  • I don’t know what I might be doing wrong, but when I try to launch a bomb (after applyImpulse), it doesn’t move and I get this warning in the console: “Cannot remove a body that was not added to the space. (Removed twice maybe?) Failed condition: body->space == space.

    I would appreciate any help.

  • Hello,

    I’m having the same problem as Nacho. Any suggested solution?

    In ccTouchEnded the morphShapeToActive call tries to remove the shape and the “Cannot remove a body that was not added to the space.” error happens.

    Thanks

  • When i build it, it will not show up in my open GL view. Why is that?

  • this little “Edit: Updated source location” deprecates the tutorial.. someone who starts the tutorial wonders that most of the parts differ from the code.. pretty annoying ..but thanks for the updated code !

  • I am getting all kinds of errors when I try to build this. Most of them are complaining about undeclared methods – cpSpaceBodyIterator and cpSpaceShapeIteratorFunc. Did I miss a step?

  • Hey Jim, the newest SpaceManager wants chipmunk 6; most likely you have chipmunk 5, I think it’s the one that still comes with cocos2d. Updating to chipmunk 6 should make everything happy, not to mention it’s quite a bit faster.

  • Thanks! I was already on that path. While you are here… how do I integrate SpaceManager into the cocos2d-chipmunk template? I can manually add it to a project, but I would love for it to just be there when I started a new project.

    Thanks!

  • Okay, I am doing something wrong. I am building the code, and I am to the point where I have added the first rectangle (the one that is supposed to fall off the display). When I build, I get 5 linking errors. I haven’t the foggiest idea what I am doing wrong. Here they are:

    Undefined symbols for architecture i386:
    “_cpBBTreeNew”, referenced from:
    _cpSpaceInit in cpSpace.o
    “_cpBBTreeSetVelocityFunc”, referenced from:
    _cpSpaceInit in cpSpace.o
    “_cpSpatialIndexFree”, referenced from:
    _cpSpaceDestroy in cpSpace.o
    _cpSpaceUseSpatialHash in cpSpace.o
    “_cpSpatialIndexInit”, referenced from:
    _cpSpaceHashInit in cpSpaceHash.o
    “_cpSpatialIndexCollideStatic”, referenced from:
    _cpSpaceHashReindexQuery in cpSpaceHash.o
    ld: symbol(s) not found for architecture i386
    collect2: ld returned 1 exit status

    I am running cocos2d 1.1, SpaceManager 0.1.2, Chipmunk 6.0.3, and I have PhysicsEditor installed to prevent errors with the GCp… something. The hooks for PE.

    Do I have to do any building for Chipmunk and/or any other component? Is the example deprecated to the point that it doesn’t work? Is animal sacrifice necessary? :)

    Thanks again!

  • You would have to edit or create a new template; I haven’t done it in a while but it’s as simple as finding out where that template project lives, opening it like you would a normal project and adding the SpaceManager src in.

    Ugh, I’ve gotten those kinds of errors once or twice before; it could be a few things. First try just doing a clean on the whole project and rebuilding; If you still get those errors, delete the chipmunk folder from your PROJECT (not the harddrive lol) and re-add them back to the project. When you go to re-add them make sure you check “Create groups for any added folders” and NOT “Create folder references for any added folders” because for whatever reason I’ve gotten similar errors when I did the references one instead of the groups one.

    Also if all else fails, I updated the project file here a while ago to work with 0.1.2 : http://mobile-bros.com/source/GrenadeGame/

  • Thanks for getting back with me. I wiped out anything cocos2d or chipmunk or spacemanager or physics editor. I added things back in this order: cocos2d 1.0.1, chipmunk 6.0.2, PE 1.0.5, and then Spacemanager 0.1.2. I had a linking error, but I found the issue… both Spacemanager and PE had the loader files. So lesson for today, do not include the same files more than once :)

  • Okay, as I am diving into the code, I understand most of what I am seeing. My first real head scratcher is the methods for Ninja. I see the +(id) ninjaWithGame twice… with one having a cpShape as a second parameter, and one without. The one without simply calls the one with. Same for the -(id) initWithGame… one shape, and one without, with the one without calling the one with.

    So, as I am not a learned man in these areas, left to my own devices, I would eliminate the two methods that do not have shape as a parameter. I have no reason, other than they look to be duplicative. I assume there is a reason to keep them both, and I would love to know what it is!

    PS: Do you guys have a forum? I saw a link on your page, but it said the forum was not available.

  • Sorry, no forum at the moment; it was used way too rarely with a ton of spam coming. At some point we were going to move it. But anyway I don’t think anyone would have a problem with starting a topic in the cocos forum, in fact I’m starting one right here to answer your question:

    http://www.cocos2d-iphone.org/forum/topic/25709

    …I gotta step out for a moment, but I’ll be back to answer.

  • The link to the source code is broken for me. It says “Directory has no index file.”

  • Hey, I’ve made a background, and I’d like to implement a new scene..

    I’ve understand the code, but for example, if a I create 2 new classes: “Game2.m and Game2.h”, what sould I do with the other classes, for example Bomb, thath has this type of code:

    @class Game;

    @interface Bomb : cpCCSprite
    {
    Game *_game;
    BOOL _countDown;
    }

    +(id) bombWithGame:(Game*)game;

    Will I have to create the same methods for each Game?

  • The short answer is no you don’t need to recreate any other classes. All code is/should be designed to be reusable.

  • what should I do to improve the speed in retina? What can be optimized? Thanks

  • And What should I do with loads of scenes a switch (gameID) case:1 – to case:50 in several places? Because in each scene, the position of the stuff are different. What about the sling position?

    #define SLING_POSITION ccp(60,157)

    it should be mutable.. shouldn’t it?
    Thanks

  • To improve the speed, you should probably beusing spritesheets all around. And yes any kind of position stuff like that should be stored in somewhere else. Just saying: I would avoid having to write up 50 scenes, and find another way like loading up simple plist level files for example.

  • Ah.. Thanks.. I understood now!

    Is there any tutorial here of how to whrite a plist file?
    If it would’t be too much, I’d like to see how would be the plist file for this example above…

    Thanks

  • Ok, I’m doing good so far..

    I generate the xml file and read it in the project..
    But just one question. Where should I store the SLING_POSITION? How could I change it dependind on the game?

    #define SLING_POSITION ccp(400,45)

  • Hey Pedro, do you mind moving these types of questions to this forum thread: http://www.cocos2d-iphone.org/forum/topic/25709

    To answer that last one, you could just have a member variable in the Game class: CGPoint _sling_position;

    Also, here’s a thread on plist’s: http://www.cocos2d-iphone.org/forum/topic/12267

  • Hey, just wondering..

    Imagine I’m doing a game like this one.. When the project is done, I’d like to make it in Android too.
    What should I do?

    Use cocos2d, chipmunk and spacemanager for Android, and then addapt my code for it? Isn’t there an easier way? Cause every update I should addept the code in both?

    Wonder 2: The angry birds itself (has for Android and iOs and) runs exactly the same in both devices.. I’ve been searching about html5, and discovered this site: http://cocos2d-javascript.org/about. If I do my app in html5, would it be the same for iOs and Android?
    Is Angry Birds made using html5?

    Thanks! =)

  • If you want to write code once I suggest looking at cocos2d-x. You won’t be able to use SpaceManager but chipmunk itself should be fine.

    Angry Birds is not using html5 on iOS or Android (as far as I know), but they do have a web version that most certainly is.

Leave a Reply




Social Widgets powered by AB-WebLog.com.