I'm finishing the chipmunk part of my Labyrinth maze style game, and I'm trying to optimize it to get 30 FPS from all 4 difficulty levels.
The different difficulty levels have different sizes of mazes in them, meaning the higher the difficulty level the more cpSegmentShapeNew and cpSpaceAddStaticShape I use, hence more collision tests are being called and the game runs slower.
In each maze there is one (active) ball, 4 big walls for the outer borders, and lots of segments making the "inside" of the maze.
I count the total number of static shapes (for every one of them I do: cpSegmentShapeNew and then cpSpaceAddStaticShape) and I have about:
100 for maze size "S"
125 for maze size "M"
165 for maze size "L"
200 for maze size "XL"
My problem is mainly with the "XL" sized maze, having around 200 maze segments, running at 17.5 to 22.5 FPS.
I tried optimizing using cpSpaceResizeActiveHash and cpSpaceResizeStaticHash, maybe my numbers are wrong, or there might be some other problem I'm not aware of.
How do I fix this problem? I know using this exact code works on the smaller sized mazes, giving a steady 30 FPS for the "S" and "M" sizes now, but the "L" size is dropping to 25 FPS and the "XL" is even lower, as stated above, and is the most important topic I have left to fix.
Maybe I'm doing something wrong with the way I am setting this up, or maybe it does have something to do with values I use with my cpSpaceResizeActiveHash and cpSpaceResizeStaticHash?
Here's my code: basically I have an array I create that represents the maze:
Code: Select all
array = [[NSArray alloc] initWithObjects:
@"XXXXXXXXXXXXXXXXXXXXX",
@"X X X X X X",
@"X X XX X X X X X XX X",
@"X X X X X X X X",
@"X X X XX XXXXXXXXX XX",
@"X X X XX",
@"XXXXXXXXXX XXXXXXXXXX",
@"XX X X X",
@"XX XXXXXXXXX XX X X X",
@"X X X X X X X X",
@"X XX X X X X X XX X X",
@"X X X X X X",
@"XXXXXXXXXXXXXXXXXXXXX",nil];
And my code (only the relevant values for the "XL" maze) for the GameLayer.m is:
Code: Select all
-(void)setupChipmunk{
#define kBallElasticity 0.60
#define kBallFriction 0.04
#define kObstacleElasticity 0.80
#define kObstacleFriction 0.35
#define kObstacleRadius 1
// Start chipmunk
cpInitChipmunk();
// Create a space object
space = cpSpaceNew();
// Define a gravity vector
space->gravity = cpv(0,0);
[self schedule: @selector(tick:) interval: 1.0f/50.0f];
int count;
int rowCount = [array count];
int columnCount = [[array objectAtIndex:0] length];
int startXpos = (480 - columnCount*tileSize)/2;
int startYpos = (320 - rowCount*tileSize)/2;
cpBody* ballBody;
ballBody = cpBodyNew(85.0, cpMomentForCircle(85.0, 0.0, 9, cpvzero));
space->iterations = 2;
space->elasticIterations = 3;
cpSpaceResizeActiveHash(space, 9, 4);
cpSpaceResizeStaticHash(space, 11, 600);
// position ball:
ballBody->p = cpv(startXpos + 1.5*tileSize, startYpos + 1.5*tileSize);
// add the ball body to the space
cpSpaceAddBody(space, ballBody);
// create the ball's shape using the ball body
cpShape* ballShape = cpCircleShapeNew(ballBody, 9, cpvzero);
ballShape->e = kBallElasticity;
ballShape->u = kBallFriction;
ballShape->data = ballSprite;
ballShape->collision_type = 1; // 1=ball, 0=walls
// add the regular (non-static) shape to the space
cpSpaceAddShape(space, ballShape);
// start wallBody
wallBody = cpBodyNew(INFINITY, INFINITY);
wallBody->p = cpv(0,0);
// set the maze's outer borders:
cpShape* outerWallShape;
int x = startXpos;
int y = startYpos;
// top border
outerWallShape = cpSegmentShapeNew(wallBody, cpv(x,y+(rowCount-2)*size), cpv(x+(columnCount-2)*size,y+(rowCount-2)*size), kObstacleRadius);
outerWallShape->e = kObstacleElasticity;
outerWallShape->u = kObstacleFriction;
outerWallShape->collision_type = 0;
cpSpaceAddStaticShape(space, outerWallShape);
counter++;
// bottom border
outerWallShape = cpSegmentShapeNew(wallBody, cpv(x,y), cpv(x+(columnCount-2)*size,y), kObstacleRadius);
outerWallShape->e = kObstacleElasticity;
outerWallShape->u = kObstacleFriction;
outerWallShape->collision_type = 0;
cpSpaceAddStaticShape(space, outerWallShape);
counter++;
// left border
outerWallShape = cpSegmentShapeNew(wallBody, cpv(x,y), cpv(x,y+(rowCount-2)*size), kObstacleRadius);
outerWallShape->e = kObstacleElasticity;
outerWallShape->u = kObstacleFriction;
outerWallShape->collision_type = 0;
cpSpaceAddStaticShape(space, outerWallShape);
counter++;
// right border
outerWallShape = cpSegmentShapeNew(wallBody, cpv(x+(columnCount-2)*size,y), cpv(x+(columnCount-2)*size,y+(rowCount-2)*size), kObstacleRadius);
outerWallShape->e = kObstacleElasticity;
outerWallShape->u = kObstacleFriction;
outerWallShape->collision_type = 0;
cpSpaceAddStaticShape(space, outerWallShape);
counter++;
}
for (int row = 1; row < numOfRows-1; row++)
{
NSString * tmpRow = [array objectAtIndex:row];
NSString * tmpBelowTheRow = [array objectAtIndex:row-1];
NSString * tmpAboveTheRow = [array objectAtIndex:row+1];
for (int column = 1; column < numOfColumns-1; column++)
{
// if the current square is 'X' (=88)
if([tmpRow characterAtIndex:column] == 88)
{
// set a visual tile for the correct position
[self setTileForX:startXpos+column*tileSize forY:startYpos+row*tileSize forSize:tileSize];
// if there's no wall above set collision border at the top of the square
if([tmpAboveTheRow characterAtIndex:column] != 88)
[self setCollisionForDirection:@"UP" forX:startXpos+column*tileSize forY:startYpos+row*tileSize forSize:tileSize];
// if there's no wall below set collision border at the bottom of the square
if([tmpBelowTheRow characterAtIndex:column] != 88)
[self setCollisionForDirection:@"DOWN" forX:startXpos+column*tileSize forY:startYpos+row*tileSize forSize:tileSize];
// if there's no wall to the left set collision border to the left of the square
if((column>0) && [tmpRow characterAtIndex:column-1] != 88)
[self setCollisionForDirection:@"LEFT" forX:startXpos+column*tileSize forY:startYpos+row*tileSize forSize:tileSize];
// if there's no wall to the right set collision border to the right of the square
if((column<numOfColumns-1) && [tmpRow characterAtIndex:column+1] != 88)
[self setCollisionForDirection:@"RIGHT" forX:startXpos+column*tileSize forY:startYpos+row*tileSize forSize:tileSize];
}
}
}
[array release];
[spriteName release];
[spriteShadowName release];
// add collision pair functions:
// for exit flag:
cpSpaceAddCollisionPairFunc(space, 1, 2, &collFunc, nil);
}
-(void)setCollisionForDirection:(NSString *)direction forX:(int)x forY:(int)y forSize:(int)size
{
cpShape *wallShape;
if(direction==@"UP")
wallShape = cpSegmentShapeNew(wallBody, cpv(x,y+tileSize), cpv(x+tileSize,y+tileSize), kObstacleRadius);
else
if(direction==@"DOWN")
wallShape = cpSegmentShapeNew(wallBody, cpv(x,y), cpv(x+tileSize,y), kObstacleRadius);
else
if(direction==@"LEFT")
wallShape = cpSegmentShapeNew(wallBody, cpv(x,y), cpv(x,y+tileSize), kObstacleRadius);
else
if(direction==@"RIGHT")
wallShape = cpSegmentShapeNew(wallBody, cpv(x+tileSize,y), cpv(x+tileSize,y+tileSize), kObstacleRadius);
wallShape->e = kObstacleElasticity;
wallShape->u = kObstacleFriction;
wallShape->collision_type = 0;
cpSpaceAddStaticShape(space, wallShape);
counter++;
}
-(void)dealloc{
cpBodyFree(wallBody);
cpSpaceFreeChildren(space);
cpSpaceFree(space);
[objectsToRemove release];
[super dealloc];
}
OmerV