I'm building a platformer in cocos2d, my first game project. I'm working on movement and collision detection. I'm using a tilemap with a "meta" layer of invisible blocks that are designated collidable.
Everything seems to work pretty well except for one minor detail: when the character jumps from above into a platform, he does not fall but clips through it. If he jumps from below, it recognizes it and resets his Y velocity accordingly. I know that it's because of how I'm detecting the collisions, and just doing a simple comparison of the origin.y's, but I'm unsure of how to refactor this code better:
- (void) update: (ccTime) dt {
CGPoint scaledVelocity = ccpMult(leftJoystick.velocity, 35.0f);
CGPoint newPosition = ccp(player.position.x + scaledVelocity.x * dt, player.position.y);
CGPoint oldPosition = [player position];
float velocityX = player.Velocity.x + scaledVelocity.x * dt;
float velocityY = player.Velocity.y;
BOOL isCollision = NO;
BOOL isCollisionBelow = NO;
BOOL isCollisionRight = NO;
BOOL isCollisionLeft = NO;
NSMutableArray* collisionSprites = [[NSMutableArray alloc] init];
if (oldPosition.x > newPosition.x) {
player.flipX = YES;
}
else if (oldPosition.x < newPosition.x) {
player.flipX = NO;
}
for (CCSprite* sprite in gameplayLayer.collidableTiles) {
if (CGRectIntersectsRect(player.boundingBox, sprite.boundingBox)) {
isCollision = YES;
[collisionSprites addObject:sprite];
}
}
// Figure out which direction collision is in
if (isCollision) {
for (CCSprite* collisionSprite in collisionSprites) {
if (collisionSprite.boundingBox.origin.y < player.boundingBox.origin.y) {
isCollisionBelow = YES;
}
if ((collisionSprite.boundingBox.origin.x > player.boundingBox.origin.x) && (collisionSprite.boundingBox.origin.y >= player.boundingBox.origin.y)) {
isCollisionRight = YES;
}
if ((collisionSprite.boundingBox.origin.x < player.boundingBox.origin.x) && (collisionSprite.boundingBox.origin.y >= player.boundingBox.origin.y)) {
isCollisionLeft = YES;
}
}
}
if (isCollisionLeft) {
velocityX = 0.5f;
}
else if (isCollisionRight) {
velocityX = -0.5f;
}
if (isCollision && !isCollisionBelow && player.characterState != kStateFalling) {
velocityY = 0;
velocityY -= 0.8f;
[player setCharacterState:kStateFalling];
}
else if (!isCollisionBelow) {
velocityY -= 0.7f;
}
else if (isCollisionBelow) {
velocityY = 0;
[player setCharacterState:kStateIdle];
}
if (rightButton.active) {
if (player.characterState != kStateJumping) {
velocityY += 15.0f;
[player setCharacterState:kStateJumping];
}
}
// Ground friction
if (player.Velocity.x > 0) {
if (player.Velocity.x < 0.5f) {
velocityX = 0;
}
else {
velocityX -= 0.5f;
}
}
if (player.Velocity.x < 0) {
velocityX += 0.5f;
}
[player setVelocity:ccp(velocityX, velocityY)];
[player setPosition: ccp(player.position.x + player.Velocity.x, player.position.y + player.Velocity.y)];
[gameplayLayer setViewpointCenter:newPosition];
[player setOldPosition: player.position];
}
How can I refactor this code to work properly from all angles and reduce the complexity (I feel that there's too many booleans, and they all get a bit confusing).
isCollisionAbove
, making the necessary changes to the logic. \$\endgroup\$