//
// JumpGameMode.m
// Cart Collect
//
// Created by Starla Insigna on 8/17/11.
// Copyright 2011 Four Island. All rights reserved.
//
#import "JumpGameMode.h"
#import "SimpleAudioEngine.h"
#import "FallingObject.h"
#import "Cherry.h"
#import "Bottle.h"
#import "OneUp.h"
#import "Rock.h"
#import "GameOverScene.h"
#import "PointMultiplier.h"
#define kMinimumGestureLength 25
@interface LedgeFactory : NSObject {
UIImage* leftSprite;
UIImage* midSprite;
UIImage* rightSprite;
UIImage* singleSprite;
}
- (id)init;
- (UIImage*)createLedgeWithWidth:(int)width height:(int)height;
@end
// FallingObject flag 0 is whether the object is floating in water
@implementation JumpGameMode
- (id)init
{
self = [super init];
if (nil != self)
{
CCSprite* backgroundImage = [CCSprite spriteWithFile:@"SeaBeach.png"];
backgroundImage.position = ccp(240, 160);
[self addChild:backgroundImage z:-1];
water = [CCSprite spriteWithFile:@"water.png"];
water.position = ccp(240, -60);
[self addChild:water];
cart.sprite.position = ccp(120, 22+64); //86
cart.falling = YES;
cart.delegate = self;
self.isTouchEnabled = YES;
waterTick = 0;
wave = NO;
factory = [[LedgeFactory alloc] init];
ledges = [[NSMutableSet alloc] init];
CCTexture2D* texture = [[CCTexture2D alloc] initWithImage:[factory createLedgeWithWidth:6 height:2]];
CCSprite* ledge = [CCSprite spriteWithTexture:texture];
ledge.position = ccp(80, 32);
[self addChild:ledge];
[ledges addObject:ledge];
[texture release];
CCSprite* firstLedge = ledge;
texture = [[CCTexture2D alloc] initWithImage:[factory createLedgeWithWidth:10 height:2]];
ledge = [CCSprite spriteWithTexture:texture];
ledge.position = ccp(80 + firstLedge.boundingBox.size.width/2 + ledge.boundingBox.size.width/2+64, 32);
[self addChild:ledge];
[ledges addObject:ledge];
[texture release];
ledgeScrollSpeed = 0;
ledgeAccelerationRate = 20.0f;
addSpeed = 2.5f;
}
return self;
}
- (void)onEnterTransitionDidFinish
{
[super onEnterTransitionDidFinish];
[self schedule:@selector(accelerateGame) interval:ledgeAccelerationRate];
[self schedule:@selector(randomlyAddObject:) interval:addSpeed];
[self schedule:@selector(incrementScore) interval:1.0f];
[self scheduleDelayedAction:^{
wave = YES;
} delay:60.0f];
}
- (void)tick:(ccTime)dt
{
NSMutableSet* discardedSet = [NSMutableSet set];
int rightmost = 0;
int rightwidth = 0;
for (CCSprite* sprite in ledges)
{
sprite.position = ccp(sprite.position.x - ledgeScrollSpeed, sprite.position.y);
if ((sprite.position.x + sprite.boundingBox.size.width/2) < 0)
{
[discardedSet addObject:sprite];
[self removeChild:sprite cleanup:YES];
}
if (sprite.position.x > rightmost)
{
rightmost = sprite.position.x;
rightwidth = sprite.boundingBox.size.width/2;
}
}
NSMutableSet* discardedObjects = [NSMutableSet set];
for (FallingObject* object in objects)
{
if ((object.sprite.position.y < 86) && (![object flag:0]))
{
for (CCSprite* ledge in ledges)
{
CGSize first = [object.sprite boundingBox].size;
CGSize second = [ledge boundingBox].size;
if (object.sprite.position.x > (ledge.position.x - second.width/2 - first.width/2))
{
if (object.sprite.position.x < (ledge.position.x + second.width/2 + first.width/2))
{
if (object.sprite.position.y > (ledge.position.y - second.height/2 - first.height/2))
{
if (object.sprite.position.y < (ledge.position.y + second.height/2 + first.height/2))
{
[discardedObjects addObject:object];
}
}
}
}
}
}
if ((waterTick >= 180) || ((waterTick > 0) && ([object flag:0])))
{
object.sprite.position = ccp(object.sprite.position.x, MAX(object.sprite.position.y, water.position.y+80+11));
} else {
object.sprite.position = ccp(object.sprite.position.x-ledgeScrollSpeed, object.sprite.position.y);
}
if ((waterTick > 0) && (object.sprite.position.y <= (water.position.y+80+11)))
{
[object setFlag:0 withValue:YES];
}
}
[ledges minusSet:discardedSet];
[objects minusSet:discardedObjects];
if (rightmost <= 480)
{
int ledgeWidth = arc4random() % 9 + 1;
int ledgeDistance = arc4random() % (ledgeScrollSpeed*ledgeScrollSpeed+1)*3/2;
CCTexture2D* texture = [[CCTexture2D alloc] initWithImage:[factory createLedgeWithWidth:ledgeWidth height:2]];
CCSprite* ledge = [CCSprite spriteWithTexture:texture];
ledge.position = ccp(rightmost + rightwidth + ledge.boundingBox.size.width/2+64+ledgeDistance, 32);
[self addChild:ledge];
[ledges addObject:ledge];
[texture release];
}
if ([self cartIsObstructed:cart])
{
cart.sprite.position = ccp(cart.sprite.position.x-ledgeScrollSpeed, cart.sprite.position.y);
}
[super tick:dt];
if ((cart.sprite.position.y < 86) && (cart.boundedByScreen))
{
cart.boundedByScreen = NO;
}
if (cart.sprite.position.y == (0-cart.sprite.boundingBox.size.height/2))
{
[self setLives:self.lives-1];
cart.boundedByScreen = YES;
[[SimpleAudioEngine sharedEngine] playEffect:[[NSBundle mainBundle] pathForResource:@"Damage1" ofType:@"wav"]];
if (cart.sprite.position.x < cart.sprite.boundingBox.size.width/2)
{
cart.sprite.position = ccp(cart.sprite.boundingBox.size.width, 320 + cart.sprite.boundingBox.size.height/2);
} else {
cart.sprite.position = ccp(cart.sprite.position.x, 320 + cart.sprite.boundingBox.size.height/2);
}
}
if (lives <= 0)
{
[self unscheduleAllSelectors];
[[CCDirector sharedDirector] replaceScene:[CCTransitionSlideInT transitionWithDuration:1.5f scene:[GameOverScene sceneWithScore:score gameMode:@"Jump"]]];
}
if (wave)
{
waterTick++;
water.position = ccp(240, 140 * sin(waterTick / (36 * M_PI)) - 60);
if (waterTick == 180)
{
wave = NO;
[self scheduleDelayedAction:^{
wave = YES;
} delay:10.0f];
} else if (waterTick == 360)
{
wave = NO;
waterTick = 0;
[self scheduleDelayedAction:^{
wave = YES;
} delay:60.0f];
}
}
if (jump)
{
jumpTick++;
cart.sprite.position = ccp(cart.sprite.position.x, MAX(100 * sin(jumpTick / (2 * M_PI)) + 86, water.position.y+80+11));
if (jumpTick == 20)
{
jump = NO;
jumpTick = 0;
cart.falling = YES;
}
}
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ((!isPaused) && (!isGesturing))
{
UITouch* touch = [touches anyObject];
gestureStartPoint = [touch locationInView:nil];
isGesturing = YES;
}
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (isGesturing)
{
UITouch* touch = [touches anyObject];
CGPoint gestureCurrentPosition = [touch locationInView:nil];
CGFloat angle = atan2f(gestureCurrentPosition.y - gestureStartPoint.y, gestureCurrentPosition.x - gestureStartPoint.x);
CGFloat distance = sqrt(powf((gestureCurrentPosition.x - gestureStartPoint.x),2) + powf((gestureCurrentPosition.y - gestureStartPoint.y),2));
if ((distance >= kMinimumGestureLength) && (angle >= expectedAngle - M_PI_4) && (angle <= expectedAngle + M_PI_4) && ((cart.sprite.position.y >= 80) && (cart.sprite.position.y <= 90)))
{
jump = YES;
cart.falling = NO;
}
}
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isGesturing = NO;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
[super accelerometer:accelerometer didAccelerate:acceleration];
expectedAngle = acceleration.y*M_PI_2;
}
- (int)cartShouldFall:(Cart *)m_cart
{
int bottom = 0-m_cart.sprite.boundingBox.size.height/2;
for (CCSprite* sprite in ledges)
{
CGSize first = [m_cart.sprite boundingBox].size;
CGSize second = [sprite boundingBox].size;
if (m_cart.sprite.position.x > (sprite.position.x - second.width/2 - first.width/2))
{
if (m_cart.sprite.position.x < (sprite.position.x + second.width/2 + first.width/2))
{
bottom = sprite.position.y + second.height/2 + first.height/2;
break;
}
}
}
if (waterTick > 0)
{
bottom = MAX(water.position.y+80+11, bottom);
}
return bottom;
}
- (BOOL)cartIsObstructed:(Cart *)m_cart
{
for (CCSprite* sprite in ledges)
{
CGSize first = [m_cart.sprite boundingBox].size;
CGSize second = [sprite boundingBox].size;
if (m_cart.sprite.position.x > (sprite.position.x - second.width/2 - first.width/2))
{
if (m_cart.sprite.position.x < (sprite.position.x + second.width/2 + first.width/2))
{
if (m_cart.sprite.position.y > (sprite.position.y - second.height/2 - first.height/2))
{
if (m_cart.sprite.position.y < (sprite.position.y + second.height/2 + first.height/2))
{
return YES;
}
}
}
}
}
return NO;
}
- (void)accelerateGame
{
[self unschedule:@selector(accelerateGame)];
[self unschedule:@selector(randomlyAddObject:)];
ledgeScrollSpeed += 2;
ledgeAccelerationRate *= 2;
addSpeed *= 0.8f;
[self schedule:@selector(randomlyAddObject:) interval:addSpeed];
[self schedule:@selector(accelerateGame) interval:ledgeAccelerationRate];
}
- (void)randomlyAddObject:(ccTime)dt
{
FallingObject* object;
int randomval = arc4random()%100;
int pmChance = (5-pointMultiplier)*5 + 30;
if (randomval < 30)
{
object = [[OneUp alloc] init];
} else if (randomval < pmChance)
{
object = [[PointMultiplier alloc] init];
} else {
object = [[Rock alloc] init];
}
int objectX;
CGSize first = [cart.sprite boundingBox].size;
CGSize second = [object.sprite boundingBox].size;
for (;;)
{
objectX = arc4random()%448+16;
if (waterTick == 0)
{
break;
}
if (cart.sprite.position.x > (objectX - second.width/2 - first.width/2))
{
if (cart.sprite.position.x < (objectX + second.width/2 + first.width/2))
{
continue;
}
}
break;
}
object.sprite.position = ccp(objectX, 360);
object.sprite.scale = 1;
[self addChild:object.sprite];
[objects addObject:object];
[object release];
if (score >= 240)
{
if (arc4random() % 100 > 80)
{
object = [[Rock alloc] init];
for (;;)
{
objectX = arc4random()%448+16;
if (waterTick == 0)
{
break;
}
if (cart.sprite.position.x > (objectX - second.width/2 - first.width/2))
{
if (cart.sprite.position.x < (objectX + second.width/2 + first.width/2))
{
continue;
}
}
break;
}
object.sprite.position = ccp(objectX, 360);
object.sprite.scale = 1;
[self addChild:object.sprite];
[objects addObject:object];
[object release];
}
}
if (score >= 480)
{
if (arc4random() % 100 > 80)
{
object = [[Rock alloc] init];
for (;;)
{
objectX = arc4random()%448+16;
if (waterTick == 0)
{
break;
}
if (cart.sprite.position.x > (objectX - second.width/2 - first.width/2))
{
if (cart.sprite.position.x < (objectX + second.width/2 + first.width/2))
{
continue;
}
}
break;
}
object.sprite.position = ccp(objectX, 360);
object.sprite.scale = 1;
[self addChild:object.sprite];
[objects addObject:object];
[object release];
}
}
}
- (void)incrementScore
{
[self setScore:self.score+pointMultiplier];
}
- (void)setLives:(int)m_lives
{
int oldLives = lives;
[super setLives:m_lives];
if (oldLives > lives)
{
[self setPointMultiplier:1];
}
}
@end
@implementation LedgeFactory
- (id)init
{
self = [super init];
CGImageRef framestuff = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ledge" ofType:@"png"]] CGImage];
CGImageRef leftRef = CGImageCreateWithImageInRect(framestuff, CGRectMake(0, 0, 32, 32));
CGImageRef midRef = CGImageCreateWithImageInRect(framestuff, CGRectMake(32, 0, 32, 32));
CGImageRef rightRef = CGImageCreateWithImageInRect(framestuff, CGRectMake(64, 0, 32, 32));
CGImageRef singleRef = CGImageCreateWithImageInRect(framestuff, CGRectMake(96, 0, 32, 32));
leftSprite = [[UIImage alloc] initWithCGImage:leftRef];
midSprite = [[UIImage alloc] initWithCGImage:midRef];
rightSprite = [[UIImage alloc] initWithCGImage:rightRef];
singleSprite = [[UIImage alloc] initWithCGImage:singleRef];
CGImageRelease(leftRef);
CGImageRelease(midRef);
CGImageRelease(rightRef);
CGImageRelease(singleRef);
return self;
}
- (UIImage*)createLedgeWithWidth:(int)width height:(int)height
{
NSAssert(width > 0, @"Ledge width must be greater than 0");
NSAssert(height > 0, @"Ledge height must be greater than 0");
UIGraphicsBeginImageContext(CGSizeMake(width*32, height*32));
for (int y=0; y<height; y++)
{
if (width == 1)
{
[singleSprite drawInRect:CGRectMake(0, y*32, 32, 32)];
} else {
[leftSprite drawInRect:CGRectMake(0, y*32, 32, 32)];
for (int x=1; x<(width-1); x++)
{
[midSprite drawInRect:CGRectMake(x*32, y*32, 32, 32)];
}
[rightSprite drawInRect:CGRectMake((width-1)*32, y*32, 32, 32)];
}
}
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
@end