
One Game, Many Frameworks: Cocos2D
good framework, good
Next on the list was supposed to come LibGDX, but the bug with Sparrow bothered me too much and I wanted to see the game actually running with a clean bill of health from Apple Instruments. (Note: The Bug is gone, finito!) Plus, I wanted to run comparisons between Cocos2D and Sparrow.
There isn't much one needs to do in order to change from the Sparrow version. Here are the main changes:
Changes from Sparrow to Cocos2D
1- I had to use SpriteBatchNodes as containers for the textures so that the number of opengl texture bindings are reduced during rendering. So I decided to add a Container property inside each screen, and that container is a SpriteBatchNode object. That way I can associate one texture atlas per screen if I need.
2- I created an ImageCache object as a helper object to grab Textures and ready-to-use Sprites. But mostly so I could keep referencing that object in my logic, something I wouldn't need to do in Cocos2D, since the texture cache in Cocos2D is a singleton and can be accessed anywhere in the code.
3- The death animation had to be done with animation objects instead of a MovieClip. I had to use a CCSequence so that I could have the animation and a callback when the animation had finished playing.
4- It's harder to create an empty texture with Cocos2D than it is with Sparrow. Again the reason is also related to the way the frameworks handle the reduction in texture binding. When you work with a SpriteBatchNode you have to add only textures listed in the atlas bound to that batch node, you can't draw on it or add "foreign" textures, even if empty ones. So the solution in Cocos2D is to create empty textures inside the atlas and use those instead of creating an empty texture.
5- The same thing goes for drawing squares. In Sparrow you can use a Quad to do that, and I used it to create the backgrounds, but with Cocos you would have to create a special layer so you can use the drawing api to draw on that layer. It cannot be the SpriteBatchNode layer you use with the textures. In the end, I resolved the issue by making the Screen object inherit from CCLayerColor, so I could paint the entire screen with a fill color.
6- In order to animate the time bar, I used a texture and changed the clipping (masking) of that texture, since I could not draw a rectangle on that SpriteBatchNode.
7- I used TexturePacker to export the sprite sheet formatted to Cocos2D instead of Sparrow.
8- And of course SPImages became CCSprites, SPTextures became CCSpriteFrames, and SPMovieClip became a combination of CCAnimation, CCSequence, CCCallFunc.
With the AS version done and tested, it took two afternoons to change the game to Objective-C and Sparrow. Then with that done and tested, in one brief session I had the game running in Cocos2D. It was that easy!
In the next pages I will list the main classes done in Cocos2D and their Sparrow version too.

Cocos2D: The Main Classes
with sparrow and cocos2d
Sparrow: Frogger Entry Point
#import "FroggerSparrow.h"
#import "FrogGame.h"
@implementation FroggerSparrow
- (id)initWithWidth:(float)width height:(float)height
{
if ((self = [super initWithWidth:width height:height]))
{
_game = [[[FrogGame alloc] init] retain];
[self addChild:_game];
}
return self;
}
-(void) dealloc {
[_game release];
[super dealloc];
}
@end
//...
//AND THE FROGGAME CLASS
#import "FrogGame.h"
#import "Screen.h"
@implementation FrogGame
-(id) init {
self = [super init];
if (self != nil) {
[self addEventListener:@selector(onAddedToStage:) atObject:self forType:SP_EVENT_TYPE_ADDED_TO_STAGE];
}
return self;
}
-(void) onAddedToStage:(SPEvent *) event {
[self removeEventListenersAtObject:self forType:SP_EVENT_TYPE_ADDED_TO_STAGE];
_gameData = [[[GameData alloc] initWithGame:self] retain];
_imageCache = [[[SPTextureAtlas alloc] initWithContentsOfFile:@"frogger.xml"] retain];
_sounds = [[[Sounds alloc] init] retain];
[self setScreen:@"MenuScreen"];
//[self setScreen:@"GameScreen"];
[self addEventListener:@selector(onEnterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
}
-(void) onEnterFrame:(SPEnterFrameEvent *) event {
float dt = event.passedTime;
if (_gameData.gameMode == GAME_STATE_PAUSE) return;
[self updateGame:dt];
}
-(void) updateGame:(float)dt {
[_screen update:dt];
}
-(void) dealloc {
[_gameData release];
[_imageCache release];
[_sounds release];
[self removeEventListenersAtObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
[super dealloc];
}
@end
Cocos2D: Frogger Entry Point
//I combined Entry Point and FrogGame classes
#import "FroggerCocos2d.h"
#import "SimpleAudioEngine.h"
#import "GameData.h"
#import "Sounds.h"
#import "ImageCache.h"
// HelloWorldLayer implementation
@implementation FroggerCocos2d
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
FroggerCocos2d *layer = [FroggerCocos2d node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// 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])) {
CGSize size = [[CCDirector sharedDirector] winSize];
_screenWidth = size.width;
_screenHeight = size.height;
_gameData = [[[GameData alloc] initWithGame:self] retain];
_imageCache = [[[ImageCache alloc] initWithGame:self] retain];
_sounds = [[[Sounds alloc] initWithGame:self] retain];
[self scheduleUpdate];
[self setScreen:@"MenuScreen" withColor:ccc4(80, 80 ,80, 255)];
//[self setScreen:@"GameScreen" withColor:ccc4(0, 0 , 0, 255)];
}
return self;
}
-(void) update:(ccTime) dt {
if (_gameData.gameMode == GAME_STATE_PAUSE) return;
if (_screen) {
[_screen update:dt];
}
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
[_gameData release];
[_imageCache release];
[_sounds release];
[super dealloc];
}
@end
Sparrow: Game Super Class
#import "Game.h"
#import "Screen.h"
#import "MenuScreen.h"
@implementation Game
@synthesize gameData = _gameData;
@synthesize sounds = _sounds;
@synthesize imageCache = _imageCache;
-(id) init {
self = [super init];
if (self != nil) {
_screen = nil;
_screens = [[NSMutableDictionary dictionary] retain];
}
return self;
}
-(Screen *) getScreen {
return _screen;
}
//Class class = NSClassFromString(@"NSArray");
-(void) setScreen:(NSString *)screenName {
NSLog(@"SCREEN CLASS: %@", screenName);
if ([_screens objectForKey:screenName] == nil) {
Class screenClass = NSClassFromString(screenName);
Screen *myScreen = [[[screenClass alloc] initWithGame:self] retain];
[_screens setValue:myScreen forKey:screenName];
[myScreen release];
}
//if we are currently displaying some screen, get rid of it
if (_screen) {
[self removeChild:_screen];
[_screen destroy];
}
_screen = [_screens objectForKey:screenName];
[_screen createScreen];
[self addChild:_screen];
}
-(int) getScreenWidth {
return self.stage.width;
}
-(int) getScreenHeight {
return self.stage.height;
}
-(void) updateGame:(float)dt{}
-(void) dealloc {
[_screens release];
[super dealloc];
}
@end
Cocos2D: Game Super Class
#import "Game.h"
#import "Screen.h"
#import "GameData.h"
#import "Sounds.h"
#import "ImageCache.h"
@implementation Game
@synthesize gameData = _gameData;
@synthesize sounds = _sounds;
@synthesize imageCache = _imageCache;
@synthesize screenHeight = _screenHeight, screenWidth = _screenWidth;
-(id) init {
self = [super init];
if (self != nil) {
//_screen = nil;
_screens = [[NSMutableDictionary dictionary] retain];
}
return self;
}
-(Screen *) getScreen {
return _screen;
}
-(void) setScreen:(NSString *) screenName withColor:(ccColor4B) color {
//NSLog(@"SCREEN CLASS: %@", screenName);
if ([_screens objectForKey:screenName] == nil) {
Class screenClass = NSClassFromString(screenName);
Screen *myScreen = [[[screenClass alloc] initWithGame:self withColor:color] retain];
[_screens setValue:myScreen forKey:screenName];
[myScreen release];
}
[self setScreen:screenName];
}
-(void) setScreen:(NSString *) screenName {
if ([_screens objectForKey:screenName] == nil) return;
//if we are currently displaying some screen, get rid of it
if (_screen) {
[self removeChild:_screen cleanup:NO];
[_screen destroy];
}
_screen = [_screens objectForKey:screenName];
[_screen createScreen];
[self addChild:_screen];
}
-(void) updateGame:(float)dt{}
-(void) dealloc {
[_screens release];
[super dealloc];
}
@end
Sparrow: Screen Super Class
#import "Screen.h"
@implementation Screen
-(id) initWithGame:(Game *)game {
self = [super init];
if (self != nil) {
_game = game;
}
return self;
}
-(void) createScreen {
_dynamicElements = [[NSMutableArray array] retain];
}
-(void) destroy {
[_dynamicElements removeAllObjects];
[_dynamicElements release];
_dynamicElements = nil;
}
-(void ) update:(float)dt {}
-(void) onTouch:(SPTouchEvent *) event{}
-(void) dealloc {
if (_dynamicElements) {
[_dynamicElements removeAllObjects];
[_dynamicElements release];
}
[super dealloc];
}
@end
Cocos2D: Screen Super Class
#import "Screen.h"
#import "Game.h"
@implementation Screen
@synthesize stage = _container;
-(id) initWithGame:(Game *) game withColor:(ccColor4B) color {
self = [super initWithColor:color];
if (self != nil) {
_game = game;
_container = nil;
_dynamicElements = [[NSMutableArray array] retain];
}
return self;
}
-(void) addSprite:(CCSprite *) sprite {
if (_container != nil) {
[_container addChild:sprite];
}
}
-(void) createScreen {}
-(void) update:(float) dt {}
-(void) destroy {}
-(CGPoint) touchFromLocation:(UITouch *)touch {
CGPoint location = [touch locationInView: [touch view]];
return [[CCDirector sharedDirector] convertToGL:location];
}
-(void) dealloc {
[_dynamicElements removeAllObjects];
[_dynamicElements release];
[super dealloc];
}
@end
Sparrow: MenuScreen
#import "MenuScreen.h"
@implementation MenuScreen
//override
-(void) createScreen {
if (self.numChildren == 0) {
//add bg
SPQuad *bg = [SPQuad quadWithWidth:_game.stage.width height:_game.stage.height];
bg.color = 0x666666;
[self addChild:bg];
//add logo
SPImage * logo = [[SPImage imageWithTexture:[_game.imageCache textureByName:@"logo"]] retain];
logo.pivotX = logo.width * 0.5;
logo.pivotY = logo.height * 0.5;
logo.x = _game.stage.width * 0.5;
logo.y = _game.stage.height * 0.3;
[self addChild:logo];
SPImage *label1 = [[SPImage imageWithTexture:[_game.imageCache textureByName:@"label_how_to"]] retain];
label1.pivotX = label1.width * 0.5;
label1.pivotY = label1.height * 0.5;
label1.x = _game.stage.width * 0.5;
label1.y = _game.stage.height * 0.5;
[self addChild:label1];
SPImage *label2 = [[SPImage imageWithTexture:[_game.imageCache textureByName:@"label_instructions"]] retain];
label2.pivotX = label2.width * 0.5;
label2.pivotY = label2.height * 0.5;
label2.x = _game.stage.width * 0.5;
label2.y = _game.stage.height * 0.72;
[self addChild:label2];
SPImage *label3 = [[SPImage imageWithTexture:[_game.imageCache textureByName:@"label_tap"]] retain];
label3.pivotX = label3.width * 0.5;
label3.pivotY = label3.height * 0.5;
label3.x = _game.stage.width * 0.5;
label3.y = _game.stage.height * 0.98;
[self addChild:label3];
SPImage *controls = [[SPImage imageWithTexture:[_game.imageCache textureByName:@"control"]] retain];
controls.pivotX = controls.width * 0.5;
controls.pivotY = controls.height * 0.5;
controls.x = _game.stage.width * 0.5;
controls.y = _game.stage.height * 0.6;
[self addChild:controls];
//release all objects once we're done with them
[logo release];
[label1 release];
[label2 release];
[label3 release];
[controls release];
}
//add touch event listener
[self addEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
}
-(void) onTouch:(SPTouchEvent *) event {
SPTouch *touch = [[[event touchesWithTarget:self andPhase:SPTouchPhaseEnded] anyObject] retain];
if (touch) {
[_game setScreen:@"GameScreen"];
}
[touch release];
}
-(void) destroy {
[self removeEventListener:@selector(onTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
}
@end
Cocos2D: MenuScreen
#import "MenuScreen.h"
@implementation MenuScreen
-(void) createScreen {
if (!_container) {
_container = [[_game.imageCache getContainer:@"frogger.png"] retain];
[self addChild:_container];
//add elements
//add logo
CCSprite * logo = [_game.imageCache getSkin:@"logo.png"];
logo.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.7);
[_container addChild:logo];
CCSprite *label1 = [[_game.imageCache getSkin:@"label_how_to.png"] retain];
label1.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.53);
[_container addChild:label1];
CCSprite *label2 = [[_game.imageCache getSkin:@"label_instructions.png"] retain];
label2.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.2);
[_container addChild:label2];
CCSprite *label3 = [[_game.imageCache getSkin:@"label_tap.png"] retain];
label3.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.02);
[_container addChild:label3];
CCSprite *controls = [[_game.imageCache getSkin:@"control.png"] retain];
controls.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.4);
[_container addChild:controls];
//release all objects once we're done with them
[logo release];
[label1 release];
[label2 release];
[label3 release];
[controls release];
self.isTouchEnabled = YES;
}
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[_game setScreen:@"GameScreen" withColor:ccc4(0,0,0,255)];
}
-(void) dealloc {
[_container release];
[super dealloc];
}
@end
Sparrow: GameScreen
#import "GameScreen.h"
#import "TierSprite.h"
@implementation GameScreen
-(id) initWithGame:(Game *)game {
self = [super initWithGame:game];
if (self != nil) {
_tiers = [[NSMutableArray arrayWithCapacity:13] retain];
}
return self;
}
-(void) createScreen {
if (self.numChildren == 0) {
[super createScreen];
//add bg
SPImage * bg = [SPImage imageWithTexture:[_game.imageCache textureByName:@"bg"]];
[self addChild:bg];
//add tiers (cars, trees, crocodiles, turtles...)
for (int i = 0; i < 12; i++) {
[_tiers addObject:[[Tier alloc] initWithGame:_game level:i]];
}
[_tiers addObject:[[FinalTier alloc] initWithGame:_game level:12]];
//add grass
SPImage * grass = [SPImage imageWithTexture:[_game.imageCache textureByName:@"grass"]];
grass.pivotX = grass.width * 0.5;
grass.pivotY = grass.height * 0.5;
grass.x = _game.stage.width * 0.5;
grass.y = _game.stage.height * 0.12;
[self addChild:grass];
//add player
_player = [[[Player alloc] initWithGame:_game x:_game.stage.width * 0.5 y:_game.stage.height * 0.89] retain];
[_dynamicElements addObject:_player];
//add bonus frog
_bonusFrog = [[[BonusFrog alloc] initWithGame:_game x:-100 y:-100 player:_player] retain];
_bonusFrog.log = (TierSprite *)[(Tier*)[_tiers objectAtIndex:8] getElement:0];
[_dynamicElements addObject:_bonusFrog];
//add game timer
_timer = [[[LevelTimer alloc] initWithGame:_game x:_game.stage.width * 0.5 y:_game.stage.height * 0.95] retain];
//add score, level, lives
_score = [[[NumberSprite alloc] initWithGame:_game x:_game.stage.width * 0.2 y:_game.stage.height * 0.04 name:@"number_score_"] retain];
_level = [[[NumberSprite alloc] initWithGame:_game x:_game.stage.width * 0.06 y:_game.stage.height * 0.04 name:@"number_level_"] retain];
_lives = [[[Lives alloc] initWithGame:_game x:_game.stage.width * 0.68 y:_game.stage.height * 0.02] retain];
//add controls
_controls = [[[Controls alloc] initWithGame:_game x:_game.stage.width * 0.85 y:_game.stage.height * 0.89] retain];
//add game labels (game over, new level, game timer)
_gameOverMsg = [[[GameSprite alloc] initWithGame:_game x:_game.stage.width * 0.5 y:_game.stage.height * 0.53] retain];
[_gameOverMsg setSkin:[SPImage imageWithTexture:[_game.imageCache textureByName:@"game_over_box"]]];
[_gameOverMsg hide];
_newLevelMsg = [[[GameSprite alloc] initWithGame:_game x:_game.stage.width * 0.5 y:_game.stage.height * 0.53] retain];
[_newLevelMsg setSkin:[SPImage imageWithTexture:[_game.imageCache textureByName:@"new_level_box"]]];
[_newLevelMsg hide];
[self addChild:_gameOverMsg.skin];
[self addChild:_newLevelMsg.skin];
_levelTimeMsg = [[[TimeMsg alloc] initWithGame:_game x:_game.stage.width * 0.5 y:_game.stage.height * 0.53] retain];
[_levelTimeMsg hide];
} else {
NSLog(@"NEW GAME!!!");
[_timer reset];
[_player reset];
[_bonusFrog reset];
[_score reset];
[_level reset];
[_game.gameData reset];
[_lives show];
for (int i = 0; i < [_tiers count]; i++) {
[(Tier *)[_tiers objectAtIndex:i] reset];
}
}
[_score showValue:0];
[_level showValue:1];
//add main input events
[_game.stage addEventListener:@selector(onControlTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
[self performSelector:@selector(startGame) withObject:self afterDelay:0.5f];
}
-(void) startGame {
_game.gameData.gameMode = GAME_STATE_PLAY;
[_timer startTimer];
}
-(void) update:(float)dt {
int i;
int len = [_dynamicElements count];
for (i = 0; i < len; i++) {
[(MovingSprite *)[_dynamicElements objectAtIndex:i] update:dt];
[(MovingSprite *)[_dynamicElements objectAtIndex:i] place];
}
len = [_tiers count];
for (i = 0; i < len; i++) {
[(Tier *) [_tiers objectAtIndex:i] update:dt];
}
if (_player.skin.visible) {
//check collision of frog and tier sprites
if ([(Tier*)[_tiers objectAtIndex:_player.tierIndex] checkCollision:_player]) {
//if tiers with vehicles, and colliding with vehicle
if (_player.tierIndex < 6) {
[_game.sounds play:SOUND_HIT];
//if not colliding with anything in the water tiers, drown frog
} else {
[_game.sounds play:SOUND_SPLASH];
}
//kill player
[_player kill];
_game.gameData.lives--;
[_lives updateLives];
}
//check collision of frog and bonus frog
//if bonus frog is visible and not on frog
if (_bonusFrog.skin.visible) {
if (CGRectIntersectsRect([_bonusFrog bounds], [_player bounds]) ) {
//[[_bonusFrog bounds] intersectsRectangle:[_player bounds]]
_player.hasBonus = YES;
}
}
} else {
if (_player.hasBonus) {
[_bonusFrog hide];
_player.hasBonus = NO;
}
}
}
-(void) destroy {
[_controls.skin removeEventListener:@selector(onControlTouch:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
}
-(void) updateScore {
[_score showValue:_game.gameData.score];
}
-(void) updateLevel{
[_level showValue:_game.gameData.level];
}
-(void) gameOver{
[_gameOverMsg show];
_game.gameData.gameMode = GAME_STATE_PAUSE;
[_game.stage addEventListener:@selector(onRestartGame:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
}
-(void) targetReached{
//show time for this target
[_levelTimeMsg.timeLabel showValue:_timer.seconds];
[_levelTimeMsg show];
[_levelTimeMsg.timeLabel show];
[self performSelector:@selector(hideLevelTime) withObject:self afterDelay:3.0f];
_timer.seconds = 0;
[_timer startTimer];
}
-(void) hideLevelTime {
[_levelTimeMsg hide];
[_levelTimeMsg.timeLabel hide];
}
-(void) newLevel{
_game.gameData.gameMode = GAME_STATE_PAUSE;
//increase the speeds in the tiers
_game.gameData.tierSpeed1 += 0.1;
_game.gameData.tierSpeed2 += 0.2;
[_game.gameData addLevel];
int len = [_tiers count];
for (int i = 0; i < len; i++) {
[(Tier *)[_tiers objectAtIndex:i] refresh];
}
[_timer reset];
_game.gameData.gameMode = GAME_STATE_PLAY;
}
-(void) onControlTouch:(SPTouchEvent *) event{
if (_game.gameData.gameMode != GAME_STATE_PLAY || !_player.skin.visible) return;
SPTouch *touch = [[event touchesWithTarget:_controls.skin andPhase:SPTouchPhaseBegan] anyObject];
if (touch) {
SPPoint * pos = [[touch locationInSpace:_controls.skin] retain];
CGPoint point = CGPointMake(pos.x, pos.y);
switch ([_controls getDirection:point]) {
case MOVE_TOP:
[_player moveFrogUp];
break;
case MOVE_DOWN:
[_player moveFrogDown];
break;
case MOVE_LEFT:
[_player moveFrogLeft];
break;
case MOVE_RIGHT:
[_player moveFrogRight];
break;
}
[pos release];
}
}
-(void) onRestartGame:(SPTouchEvent *) event{
SPTouch *touch = [[event touchesWithTarget:_game.stage andPhase:SPTouchPhaseEnded] anyObject];
if (touch) {
[_game.stage removeEventListener:@selector(onRestartGame:) atObject:self forType:SP_EVENT_TYPE_TOUCH];
[_gameOverMsg hide];
[_game setScreen:@"MenuScreen"];
}
}
-(void) dealloc {
[_player release];
[_bonusFrog release];
[_timer release];
[_score release];
[_level release];
[_lives release];
[_controls release];
[_newLevelMsg release];
[_gameOverMsg release];
[_levelTimeMsg release];
[_tiers removeAllObjects];
[_tiers release];
[super dealloc];
}
@end
Cocos2D: GameScreen
#import "GameScreen.h"
#import "TierSprite.h"
#import "GameSprite.h"
#import "Player.h"
#import "BonusFrog.h"
#import "Controls.h"
#import "Tier.h"
#import "FinalTier.h"
#import "TimeMsg.h"
#import "LevelTimer.h"
#import "NumberSprite.h"
#import "Lives.h"
@implementation GameScreen
-(id) initWithGame:(Game *)game withColor:(ccColor4B)color {
self = [super initWithGame:game withColor:color];
if (self != nil) {
_tiers = [[NSMutableArray arrayWithCapacity:13] retain];
}
return self;
}
-(void) createScreen {
if (!_container) {
_container = [[_game.imageCache getContainer:@"frogger.png"] retain];
[self addChild:_container];
//add bg
CCSprite * bg = [_game.imageCache getSkin:@"bg.png"];
bg.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight * 0.5);
[_container addChild:bg];
//add tiers (cars, trees, crocodiles, turtles...)
for (int i = 0; i < 12; i++) {
[_tiers addObject:[[Tier alloc] initWithGame:_game level:i]];
}
[_tiers addObject:[[FinalTier alloc] initWithGame:_game level:12]];
//add grass
CCSprite * grass = [_game.imageCache getSkin:@"grass.png"];
grass.position = CGPointMake(_game.screenWidth * 0.5, _game.screenHeight - _game.screenHeight * 0.12);
[_container addChild:grass];
//add player
_player = [[[Player alloc] initWithGame:_game x:_game.screenWidth * 0.5 y:_game.screenHeight - _game.screenHeight * 0.89] retain];
[_dynamicElements addObject:_player];
//add bonus frog
_bonusFrog = [[[BonusFrog alloc] initWithGame:_game x:-100 y:-100 player:_player] retain];
_bonusFrog.log = (TierSprite *)[(Tier*)[_tiers objectAtIndex:8] getElement:0];
[_dynamicElements addObject:_bonusFrog];
//add game timer
_timer = [[[LevelTimer alloc] initWithGame:_game x:_game.screenWidth * 0.1 y:_game.screenHeight - _game.screenHeight * 0.95] retain];
//add score, level, lives
_score = [[[NumberSprite alloc] initWithGame:_game x:_game.screenWidth * 0.2 y:_game.screenHeight - _game.screenHeight * 0.04 name:@"number_score_"] retain];
_level = [[[NumberSprite alloc] initWithGame:_game x:_game.screenWidth * 0.06 y:_game.screenHeight - _game.screenHeight * 0.04 name:@"number_level_"] retain];
_lives = [[[Lives alloc] initWithGame:_game x:_game.screenWidth * 0.7 y:_game.screenHeight - _game.screenHeight * 0.02] retain];
//add controls
_controls = [[[Controls alloc] initWithGame:_game x:_game.screenWidth * 0.83 y:_game.screenHeight - _game.screenHeight * 0.88] retain];
//add game labels (game over, new level, game timer)
_gameOverMsg = [[[GameSprite alloc] initWithGame:_game x:_game.screenWidth * 0.5 y:_game.screenHeight - _game.screenHeight * 0.53] retain];
[_gameOverMsg setSkin:[_game.imageCache getSkin:@"game_over_box.png"]];
[_gameOverMsg hide];
_newLevelMsg = [[[GameSprite alloc] initWithGame:_game x:_game.screenWidth * 0.5 y:_game.screenHeight - _game.screenHeight * 0.53] retain];
[_newLevelMsg setSkin:[_game.imageCache getSkin:@"new_level_box.png"]];
[_newLevelMsg hide];
[_container addChild:_gameOverMsg.skin];
[_container addChild:_newLevelMsg.skin];
_levelTimeMsg = [[[TimeMsg alloc] initWithGame:_game x:_game.screenWidth * 0.5 y:_game.screenHeight * 0.53] retain];
[_levelTimeMsg hide];
self.isTouchEnabled = YES;
} else {
[_timer reset];
[_player reset];
[_bonusFrog reset];
[_score reset];
[_level reset];
[_game.gameData reset];
[_lives show];
for (int i = 0; i < [_tiers count]; i++) {
[(Tier *)[_tiers objectAtIndex:i] reset];
}
}
[_score showValue:0];
[_level showValue:1];
[self performSelector:@selector(startGame) withObject:self afterDelay:0.5f];
}
-(void) startGame {
_game.gameData.gameMode = GAME_STATE_PLAY;
[_timer startTimer];
}
-(void) update:(float)dt {
int i;
int len = [_dynamicElements count];
for (i = 0; i < len; i++) {
[(MovingSprite *)[_dynamicElements objectAtIndex:i] update:dt];
[(MovingSprite *)[_dynamicElements objectAtIndex:i] place];
}
len = [_tiers count];
for (i = 0; i < len; i++) {
[(Tier *) [_tiers objectAtIndex:i] update:dt];
}
if (_player.skin.visible && !_player.dead) {
//check collision of frog and tier sprites
if ([(Tier*)[_tiers objectAtIndex:_player.tierIndex] checkCollision:_player]) {
//if tiers with vehicles, and colliding with vehicle
if (_player.tierIndex < 6) {
[_game.sounds play:SOUND_HIT];
//if not colliding with anything in the water tiers, drown frog
} else {
[_game.sounds play:SOUND_SPLASH];
}
//kill player
[_player kill];
_game.gameData.lives--;
[_lives updateLives];
}
//check collision of frog and bonus frog
//if bonus frog is visible and not on frog
if (_bonusFrog.skin.visible) {
if (CGRectIntersectsRect([_bonusFrog bounds], [_player bounds]) ) {
//[[_bonusFrog bounds] intersectsRectangle:[_player bounds]]
_player.hasBonus = YES;
}
}
} else {
if (_player.hasBonus) {
[_bonusFrog hide];
_player.hasBonus = NO;
}
}
}
-(void) destroy {}
-(void) updateScore {
[_score showValue:_game.gameData.score];
}
-(void) updateLevel{
[_level showValue:_game.gameData.level];
}
-(void) gameOver{
[_gameOverMsg show];
_game.gameData.gameMode = GAME_STATE_PAUSE;
}
-(void) targetReached{
//show time for this target
[_levelTimeMsg.timeLabel showValue:_timer.seconds];
[_levelTimeMsg show];
[_levelTimeMsg.timeLabel show];
[self performSelector:@selector(hideLevelTime) withObject:self afterDelay:3.0f];
_timer.seconds = 0;
[_timer startTimer];
}
-(void) hideLevelTime {
[_levelTimeMsg hide];
[_levelTimeMsg.timeLabel hide];
}
-(void) newLevel{
_game.gameData.gameMode = GAME_STATE_PAUSE;
//increase the speeds in the tiers
_game.gameData.tierSpeed1 += 0.1;
_game.gameData.tierSpeed2 += 0.2;
[_game.gameData addLevel];
int len = [_tiers count];
for (int i = 0; i < len; i++) {
[(Tier *)[_tiers objectAtIndex:i] refresh];
}
[_timer reset];
_game.gameData.gameMode = GAME_STATE_PLAY;
}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (!_gameOverMsg.skin.visible) {
if (_game.gameData.gameMode != GAME_STATE_PLAY || _player.dead) return;
if (_player.moving) return;
UITouch * touch = [[touches anyObject] retain];
CGPoint tap;
CGRect control = [_controls bounds];
tap = [self touchFromLocation:touch];
if (CGRectContainsPoint(control, tap)) {
switch ([_controls getDirection:tap]) {
case MOVE_TOP:
[_player moveFrogUp];
break;
case MOVE_DOWN:
[_player moveFrogDown];
break;
case MOVE_LEFT:
[_player moveFrogLeft];
break;
case MOVE_RIGHT:
[_player moveFrogRight];
break;
}
}
[touch release];
} else {
[_gameOverMsg hide];
[_game setScreen:@"MenuScreen"];
}
}
-(void) dealloc {
[_player release];
[_bonusFrog release];
[_timer release];
[_score release];
[_level release];
[_lives release];
[_controls release];
[_newLevelMsg release];
[_gameOverMsg release];
[_levelTimeMsg release];
[_tiers removeAllObjects];
[_tiers release];
[super dealloc];
}
@end

Cocos2D: The Main Classes II
with sparrow and cocos
Cocos2D: ImageCache
#import "ImageCache.h"
@implementation ImageCache
-(id) initWithGame:(Game *) game {
self = [super init];
if (self != nil) {
_game = game;
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
@"frogger.plist"];
}
return self;
}
-(CCSpriteBatchNode *) getContainer:(NSString *) name {
return [CCSpriteBatchNode batchNodeWithFile:name];
}
-(CCSprite *) getSkin:(NSString *) name {
return [CCSprite spriteWithSpriteFrameName:name];
}
-(CCSpriteFrame *) getTexture:(NSString *) name {
return [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:name];
}
@end
Sparrow: Sounds
#import "Sounds.h"
@implementation Sounds
-(id) init {
self = [super init];
if (self != nil) {
_sounds = [[NSMutableArray arrayWithCapacity:6] retain];
//add sounds
[_sounds addObject:[SPSound soundWithContentsOfFile:@"hit.aiff"] ];
[_sounds addObject:[SPSound soundWithContentsOfFile:@"jump.aiff"]];
[_sounds addObject:[SPSound soundWithContentsOfFile:@"pickup.aiff"]];
[_sounds addObject:[SPSound soundWithContentsOfFile:@"splash2.aiff"] ];
[_sounds addObject:[SPSound soundWithContentsOfFile:@"target.aiff"] ];
[_sounds addObject:[SPSound soundWithContentsOfFile:@"outofbounds.aiff"]];
}
return self;
}
-(void) play:(int)type {
if (type > ([_sounds count] - 1)) return;
SPSound * sound = (SPSound *)[_sounds objectAtIndex:type];
[sound play];
}
-(void) dealloc {
[_sounds removeAllObjects];
[_sounds release];
[super dealloc];
}
@end
Cocos2D: Sounds
#import "Sounds.h"
@implementation Sounds
-(id) initWithGame:(Game *) game {
self = [super init];
if (self != nil) {
_game = game;
[[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:@"hit.aiff"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"jump.aiff"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"target.aiff"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"splash2.aiff"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"pickup.aiff"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"outofbounds.aiff"];
}
return self;
}
-(void) play:(int)type {
switch (type) {
case SOUND_JUMP:
[[SimpleAudioEngine sharedEngine] playEffect:@"jump.aiff"];
break;
case SOUND_HIT:
[[SimpleAudioEngine sharedEngine] playEffect:@"hit.aiff"];
break;
case SOUND_PICKUP:
[[SimpleAudioEngine sharedEngine] playEffect:@"pickup.aiff"];
break;
case SOUND_OUTOFBOUNDS:
[[SimpleAudioEngine sharedEngine] playEffect:@"outofbounds.aiff"];
break;
case SOUND_SPLASH:
[[SimpleAudioEngine sharedEngine] playEffect:@"splash2.aiff"];
break;
case SOUND_TARGET:
[[SimpleAudioEngine sharedEngine] playEffect:@"target.aiff"];
break;
}
}
@end
Sparrow: GameSprite
#import "GameSprite.h"
#import "Game.h"
@implementation GameSprite
@synthesize active = _active, x = _x, y = _y, skin = _skin, body = _body;
-(id) initWithGame:(Game *) game x:(float)posx y:(float)posy {
self = [super init];
if (self != nil) {
_game = game;
_x = posx;
_y = posy;
}
return self;
}
-(void) setSkin:(SPImage *) image {
_skin = image;
_skin.pivotX = _skin.width * 0.5;
_skin.pivotY = _skin.height * 0.5;
_skin.x = _x;
_skin.y = _y;
}
-(float) right {
return _x + _skin.width * 0.5;
}
-(float) left {
return _x - _skin.width * 0.5;
}
-(float) top {
return _y - _skin.height * 0.5;
}
-(float) bottom {
return _y + _skin.height * 0.5;
}
-(CGRect) bounds {
return CGRectMake([self left], [self top], _skin.width, _skin.height);
}
-(void) reset {}
-(void) update:(float) dt {}
-(void) show {
if (_skin) _skin.visible = YES;
}
-(void) hide {
if (_skin) _skin.visible = NO;
}
@end
Cocos2D: GameSprite
#import "GameSprite.h"
@implementation GameSprite
@synthesize active = _active, x = _x, y = _y, skin = _skin, body = _body, width = _width, height = _height;
-(id) initWithGame:(Game *) game x:(float)posx y:(float)posy {
self = [super init];
if (self != nil) {
_game = game;
_x = posx;
_y = posy;
}
return self;
}
-(void) setSkin:(CCSprite *) image {
_skin = image;
_skin.position = CGPointMake(_x, _y);
_width = _skin.textureRect.size.width;
_height = _skin.textureRect.size.height;
}
-(float) right {
return _x + _width * 0.5;
}
-(float) left {
return _x - _width * 0.5;
}
-(float) top {
return _y - _height * 0.5;
}
-(float) bottom {
return _y + _height * 0.5;
}
-(CGRect) bounds {
return CGRectMake([self left], [self top], _width, _height);
}
-(void) reset {}
-(void) update:(float) dt {}
-(void) show {
if (_skin) _skin.visible = YES;
}
-(void) hide {
if (_skin) _skin.visible = NO;
}
-(void) dealloc {
[super dealloc];
}
@end
Sparrow: MovingSprite
#import "MovingSprite.h"
#import "Game.h"
@implementation MovingSprite
@synthesize vx = _vx, vy = _vy, nextX = _nextX, nextY = _nextY, speed = _speed;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_nextX = _x;
_nextY = _y;
}
return self;
}
-(float) next_right {
return _nextX + _skin.width * 0.5;
}
-(float) next_left {
return _nextX - _skin.width * 0.5;
}
-(float) next_top {
return _nextY - _skin.height * 0.5;
}
-(float) next_bottom {
return _nextY + _skin.height * 0.5;
}
-(SPRectangle *) next_bounds {
return [SPRectangle rectangleWithX:[self next_left] y:[self next_top] width:_skin.width height:_skin.height];
}
-(void) update:(float)dt {
_nextX += _speed * dt;
}
-(void) place {
_x = _nextX;
_y = _nextY;
_skin.x = _x;
_skin.y = _y;
}
@end
Cocos2D: MovingSprite
#import "MovingSprite.h"
#import "Game.h"
@implementation MovingSprite
@synthesize vx = _vx, vy = _vy, nextX = _nextX, nextY = _nextY, speed = _speed;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_nextX = _x;
_nextY = _y;
}
return self;
}
-(float) next_right {
return _nextX + _width * 0.5;
}
-(float) next_left {
return _nextX - _width * 0.5;
}
-(float) next_top {
return _nextY + _height * 0.5;
}
-(float) next_bottom {
return _nextY - _height * 0.5;
}
-(CGRect) next_bounds {
return CGRectMake([self next_left], [self next_top], _width, _height);
}
-(void) update:(float)dt {
_nextX += _speed * dt;
}
-(void) place {
_x = _nextX;
_y = _nextY;
_skin.position = CGPointMake(_x, _y);
}
@end
Sparrow: NumberSprite
#import "NumberSprite.h"
#import "Game.h"
@implementation NumberSprite
@synthesize value = _value;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy name:(NSString *) root {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_textures = [[NSMutableArray array] retain];
_numbers = [[NSMutableArray array] retain];
int i;
NSString * fileName;
for (i = 0; i < 10; i++) {
fileName = [NSString stringWithFormat:@"%@%i", root, i];
[_textures addObject:[_game.imageCache textureByName:fileName]];
}
//SPTexture * empty = [SPTexture emptyTexture];
float w = ((SPTexture *) [_textures objectAtIndex:0]).width;
float h = ((SPTexture *) [_textures objectAtIndex:0]).height;
SPTexture * empty = [[[SPTexture alloc] initWithWidth:w height:h draw:nil] retain];
SPImage * img;
for (i = 0; i < 10; i++) {
img = [SPImage imageWithTexture:empty];
img.pivotX = w * 0.5;
img.pivotY = h * 0.5;
img.x = _x + i * (w + 2);
img.y = _y;
[_numbers addObject:img];
[[_game getScreen] addChild:img];
}
[empty release];
}
return self;
}
-(void) showValue:(int) value {
NSString *string = [NSString stringWithFormat:@"%i", value];
int len = [string length];
if (len > 10) return;
int texture_index;
char texture_char;
for (int i = 0; i < len; i++) {
texture_char = [string characterAtIndex:i];
texture_index = atoi(&texture_char);
((SPImage *)[_numbers objectAtIndex:i]).texture = [_textures objectAtIndex:texture_index];
}
}
-(void) reset {
float w = ((SPTexture *) [_textures objectAtIndex:0]).width;
float h = ((SPTexture *) [_textures objectAtIndex:0]).height;
SPTexture * empty = [[[SPTexture alloc] initWithWidth:w height:h draw:nil] retain];
for (int i = 0; i < [_numbers count]; i++) {
((SPImage *) [_numbers objectAtIndex:i]).texture = empty;
}
[empty release];
}
-(void) show {
for (int i = 0; i < [_numbers count]; i++) {
((SPImage *) [_numbers objectAtIndex:i]).visible = YES;
}
}
-(void) hide {
for (int i = 0; i < [_numbers count]; i++) {
((SPImage *) [_numbers objectAtIndex:i]).visible = NO;
}
}
-(void) dealloc {
[_textures removeAllObjects];
[_numbers removeAllObjects];
[_textures release];
[_numbers release];
[super dealloc];
}
@end
Cocos2D: NumberSprite
#import "NumberSprite.h"
#import "Game.h"
@implementation NumberSprite
@synthesize value = _value;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy name:(NSString *) root {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_textures = [[NSMutableArray array] retain];
_numbers = [[NSMutableArray array] retain];
int i;
NSString * fileName;
for (i = 0; i < 10; i++) {
fileName = [NSString stringWithFormat:@"%@%i.png", root, i];
[_textures addObject:[_game.imageCache getTexture:fileName]];
}
float w = ((CCSpriteFrame *) [_textures objectAtIndex:0]).rect.size.width;
_empty = [[NSString stringWithFormat:@"%@.png", root] retain];
CCSprite * img;
for (i = 0; i < 10; i++) {
img = [[_game.imageCache getSkin:_empty] retain];
img.position = CGPointMake(_x + i * (w + 2), _y);
[_numbers addObject:img];
[[_game getScreen] addSprite:img];
[img release];
}
}
return self;
}
-(void) showValue:(int) value {
NSString *string = [NSString stringWithFormat:@"%i", value];
int len = [string length];
if (len > 10) return;
int texture_index;
char texture_char;
for (int i = 0; i < len; i++) {
texture_char = [string characterAtIndex:i];
texture_index = atoi(&texture_char);
[(CCSprite *)[_numbers objectAtIndex:i] setDisplayFrame:(CCSpriteFrame*)[_textures objectAtIndex:texture_index]];
}
}
-(void) reset {
CCSpriteFrame * emptyFrame = [[_game.imageCache getTexture:_empty] retain];
for (int i = 0; i < [_numbers count]; i++) {
[(CCSprite *)[_numbers objectAtIndex:i] setDisplayFrame:emptyFrame];
}
[emptyFrame release];
}
-(void) show {
for (int i = 0; i < [_numbers count]; i++) {
((CCSprite *) [_numbers objectAtIndex:i]).visible = YES;
}
}
-(void) hide {
for (int i = 0; i < [_numbers count]; i++) {
((CCSprite *) [_numbers objectAtIndex:i]).visible = NO;
}
}
-(void) dealloc {
[_empty release];
[_textures removeAllObjects];
[_numbers removeAllObjects];
[_textures release];
[_numbers release];
[super dealloc];
}
@end

Cocos2D: The Main Classes III
with sparrow and cocos
Sparrow: Player
#import "Player.h"
#import "Game.h"
#import "Tier.h"
#import "MovingSprite.h"
#import "GameData.h"
#import "Sounds.h"
#import "GameScreen.h"
@implementation Player
@synthesize hasBonus = _hasBonus, dead = _dead, tierIndex = _tierIndex,
tierSpeed = _tierSpeed, moving = _moving;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_dead = NO;
_hasBonus = NO;
_tierIndex = 0;
_tierIndex = 0;
_moving = NO;
_sideStep = 22;
_moveCnt = 0.0f;
_moveInterval = 6;
_startPoint = CGPointMake(_x, _y);
_frogStand = [[_game.imageCache textureByName:@"frog_stand"] retain];
_frogJump = [[_game.imageCache textureByName:@"frog_jump"] retain];
_frogSide = [[_game.imageCache textureByName:@"frog_side"] retain];
_frogSideJump = [[_game.imageCache textureByName:@"frog_side_jump"] retain];
_restFrame = _frogStand;
//create death animation (movie clip)
NSArray * deathFrames = [[_game.imageCache texturesStartingWith:@"death_"] retain];
_deathAnimation = [SPMovieClip movieWithFrames:deathFrames fps:4.0f];
[_deathAnimation setDuration:1.0f atIndex:[deathFrames count] - 1];
_deathAnimation.visible = NO;
_deathAnimation.loop = NO;
_deathAnimation.pivotX = _deathAnimation.width * 0.5;
_deathAnimation.pivotY = _deathAnimation.height * 0.5;
[_deathAnimation addEventListener:@selector(onDeathComplete:) atObject:self forType:SP_EVENT_TYPE_MOVIE_COMPLETED];
[_deathAnimation setCurrentFrame:0];
[_deathAnimation pause];
[_game.stage.juggler addObject:_deathAnimation];
[deathFrames release];
[self setSkin:[SPImage imageWithTexture:_frogStand]];
[[_game getScreen] addChild:_skin];
[[_game getScreen] addChild:_deathAnimation];
_deathAnimation.x = _skin.x;
_deathAnimation.y = _skin.y;
}
return self;
}
-(void) reset {
_x = _skin.x = _nextX = _startPoint.x;
_y = _skin.y = _nextY = _startPoint.y;
_hasBonus = NO;
_dead = NO;
_skin.texture = _frogStand;
_restFrame = _frogStand;
_skin.scaleX = _skin.scaleY = 1;
_tierIndex = 0;
[self show];
}
-(void) moveFrogLeft {
if (!_moving) {
_moving = YES;
_nextX -= _sideStep;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:LEFT];
}
}
-(void) moveFrogRight {
if (!_moving) {
_moving = YES;
_nextX += _sideStep;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:RIGHT];
}
}
-(void) moveFrogUp {
if (!_moving) {
_moving = YES;
_tierIndex++;
if (_tierIndex >= 13) _tierIndex = 12;
_nextY = [Tier TIER_Y:_tierIndex] + _skin.height*0.5;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:UP];
}
}
-(void) moveFrogDown {
if (!_moving) {
_moving = YES;
_tierIndex--;
if (_tierIndex < 0) _tierIndex = 0;
_nextY = [Tier TIER_Y:_tierIndex] + _skin.height*0.5;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:DOWN];
}
}
-(void) kill {
_tierSpeed = 0;
_game.gameData.gameMode = GAME_STATE_ANIMATE;
_skin.visible = NO;
_deathAnimation.x = _skin.x;
_deathAnimation.y = _skin.y;
_deathAnimation.visible = YES;
_dead = YES;
[_deathAnimation setCurrentFrame:0];
[_deathAnimation play];
}
-(void) showMoveFrame:(int) dir {
switch (dir) {
case LEFT:
_skin.scaleX = -1;
_skin.texture = _frogSideJump;
_restFrame = _frogSide;
break;
case RIGHT:
_skin.scaleX = 1;
_skin.texture = _frogSideJump;
_restFrame = _frogSide;
break;
case UP:
_skin.scaleY = 1;
_skin.texture = _frogJump;
_restFrame = _frogStand;
break;
case DOWN:
_skin.scaleY = -1;
_skin.texture = _frogJump;
_restFrame = _frogStand;
break;
}
}
-(void) onDeathComplete:(SPEvent *) event {
_deathAnimation.visible = NO;
if (_game.gameData.lives >= 0) {
[self performSelector:@selector(startNewLife) withObject:self afterDelay:0.5f];
} else {
[(GameScreen *) [_game getScreen] gameOver];
}
}
-(void) update:(float)dt {
if (_dead) {
return;
}
if (_moving) {
if (_moveCnt > _moveInterval) {
_skin.texture = _restFrame;
_moving = NO;
_moveCnt = 0.0f;
}
_moveCnt += 20 * dt;
}
//add tier speed if player is on top of a moving object
_nextX += _tierSpeed * dt;
}
-(void) place {
//limit movement if player is not on water Tiers so frog does not leave the screen
if (_tierIndex < 7) {
if (_nextX < _skin.width * 0.5) _nextX = _skin.width * 0.5;
if (_nextX > _game.stage.width - _skin.width * 0.5) _nextX = _game.stage.width - _skin.width * 0.5;
} else {
//make player go back to start if frog leaves screen on water Tiers
if (_nextX < -_skin.width*0.5 || _nextX > _game.stage.width + _skin.width*0.5) {
[_game.sounds play:SOUND_OUTOFBOUNDS];
[self reset];
}
}
[super place];
}
-(void) startNewLife {
[self reset];
_game.gameData.gameMode = GAME_STATE_PLAY;
}
-(void) dealloc {
[_frogStand release];
[_frogSide release];
[_frogJump release];
[_frogSideJump release];
[super dealloc];
}
@end
Cocos2D: Player
#import "Player.h"
#import "Game.h"
#import "Tier.h"
#import "Sounds.h"
#import "GameScreen.h"
@implementation Player
@synthesize hasBonus = _hasBonus, dead = _dead, tierIndex = _tierIndex,
tierSpeed = _tierSpeed, moving = _moving;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_dead = NO;
_hasBonus = NO;
_tierIndex = 0;
_tierIndex = 0;
_moving = NO;
_moveCnt = 0.0f;
_moveInterval = 6;
_sideStep = 22;
_startPoint = CGPointMake(_x, _y);
_frogStand = [[_game.imageCache getTexture:@"frog_stand.png"] retain];
_frogJump = [[_game.imageCache getTexture:@"frog_jump.png"] retain];
_frogSide = [[_game.imageCache getTexture:@"frog_side.png"] retain];
_frogSideJump = [[_game.imageCache getTexture:@"frog_side_jump.png"] retain];
_restFrame = _frogStand;
//create death animation
NSMutableArray * deathFrames = [[NSMutableArray array] retain];
for (int i = 1; i <= 4 ; i++) {
[deathFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:@"death_%i.png", i]]];
}
//prolong last frame
[deathFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"death_4.png"]];
[deathFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"death_4.png"]];
[deathFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"death_4.png"]];
[deathFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"death_4.png"]];
[[CCAnimationCache sharedAnimationCache] addAnimation:[CCAnimation animationWithFrames:deathFrames delay:0.2f] name:@"death"];
CCCallFunc* onDeath = [CCCallFunc actionWithTarget:self selector:@selector(onDeathComplete)];
CCAnimate *die = [CCAnimate actionWithAnimation:[[CCAnimationCache sharedAnimationCache] animationByName:@"death"] restoreOriginalFrame:NO];
_deathAnimation = [[CCSequence actions:die, onDeath, nil] retain];
[self setSkin:[_game.imageCache getSkin:@"frog_stand.png"]];
[(Screen *)[_game getScreen] addSprite:_skin];
[deathFrames release];
}
return self;
}
-(void) reset {
_x = _nextX = _startPoint.x;
_y = _nextY = _startPoint.y;
_skin.position = CGPointMake(_x, _y);
_hasBonus = NO;
_dead = NO;
[_skin setDisplayFrame: _frogStand];
_restFrame = _frogStand;
_skin.scaleX = _skin.scaleY = 1;
_tierIndex = 0;
[self show];
}
-(void) moveFrogLeft {
if (!_moving) {
_moving = YES;
_nextX -= _sideStep;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:LEFT];
}
}
-(void) moveFrogRight {
if (!_moving) {
_moving = YES;
_nextX += _sideStep;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:RIGHT];
}
}
-(void) moveFrogUp {
if (!_moving) {
_moving = YES;
_tierIndex++;
if (_tierIndex >= 13) _tierIndex = 12;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
_nextY = _game.screenHeight - [Tier TIER_Y:_tierIndex] - _height*0.5;
[self showMoveFrame:UP];
}
}
-(void) moveFrogDown {
if (!_moving) {
_moving = YES;
_tierIndex--;
if (_tierIndex < 0) _tierIndex = 0;
_nextY = _game.screenHeight - [Tier TIER_Y:_tierIndex] - _height*0.5;
[_game.gameData addScore:POINTS_JUMP];
[_game.sounds play:SOUND_JUMP];
[self showMoveFrame:DOWN];
}
}
-(void) kill {
_tierSpeed = 0;
_game.gameData.gameMode = GAME_STATE_ANIMATE;
_skin.scaleX = _skin.scaleY = 1;
[_skin stopAllActions];
[_skin runAction:_deathAnimation];
_dead = YES;
}
-(void) showMoveFrame:(int) dir {
switch (dir) {
case LEFT:
_skin.scaleX = -1;
[_skin setDisplayFrame:_frogSideJump];
_restFrame = _frogSide;
break;
case RIGHT:
_skin.scaleX = 1;
[_skin setDisplayFrame:_frogSideJump];
_restFrame = _frogSide;
break;
case UP:
_skin.scaleY = 1;
[_skin setDisplayFrame:_frogJump];
_restFrame = _frogStand;
break;
case DOWN:
_skin.scaleY = -1;
[_skin setDisplayFrame:_frogJump];
_restFrame = _frogStand;
break;
}
}
-(void) onFrogRest {
//[_skin setDisplayFrame:_restFrame];
_moving = NO;
}
-(void) onDeathComplete {
[_skin stopAllActions];
_skin.visible = NO;
if (_game.gameData.lives >= 0) {
[self performSelector:@selector(startNewLife) withObject:self afterDelay:0.5f];
} else {
[(GameScreen *) [_game getScreen] gameOver];
}
}
-(void) update:(float)dt {
if (_dead) {
return;
}
if (_moving) {
if (_moveCnt > _moveInterval) {
_moving = NO;
[_skin setDisplayFrame:_restFrame];
_moveCnt = 0.0f;
}
_moveCnt += 20*dt;
}
//add tier speed if player is on top of a moving object
_nextX += _tierSpeed * dt;
}
-(void) place {
//limit movement if player is not on water Tiers so frog does not leave the screen
if (_tierIndex < 7) {
if (_nextX < _width * 0.5) _nextX = _width * 0.5;
if (_nextX > _game.screenWidth - _width * 0.5) _nextX = _game.screenWidth - _width * 0.5;
} else {
//make player go back to start if frog leaves screen on water Tiers
if (_nextX < -_width*0.5 || _nextX > _game.screenWidth + _width*0.5) {
[_game.sounds play:SOUND_OUTOFBOUNDS];
[self reset];
}
}
[super place];
}
-(void) startNewLife {
[self reset];
_game.gameData.gameMode = GAME_STATE_PLAY;
}
-(void) dealloc {
[_frogStand release];
[_frogSide release];
[_frogJump release];
[_frogSideJump release];
[super dealloc];
}
@end
Sparrow: Tier
#import "Tier.h"
#import "Game.h"
#import "Player.h"
#import "TierSprite.h"
#import "Vehicle.h"
#import "TreeLog.h"
#import "Turtle.h"
#import "Crocodile.h"
static int TIER_Y[] = {418,388,357,328,300,272,244,216,182,149,117,84,52};
static int TIER_ELEMENT_Y[] = {0,396,367,339,310,281,0,228,194,161,129,95,65};
static int TIER_TYPES[] = {0,0,0,0,0,0,0,1,1,1,1,1,2};
static int TIER_SPEEDS[] = {0,-20,25,-20,40,-25,0,-30,20,40,-25,20,0};
@implementation Tier
@synthesize type = _type, speed = _speed;
+ (int) TIER_Y:(int) index {
return TIER_Y[index];
}
+ (int) TIER_ELEMENT_Y:(int) index {
return TIER_ELEMENT_Y[index];
}
+ (int) TIER_TYPES:(int) index {
return TIER_TYPES[index];
}
+ (int) TIER_SPEEDS:(int) index {
return TIER_SPEEDS[index];
}
-(id) initWithGame:(Game *) game level:(int) index {
self = [super initWithGame:game x:0 y:TIER_Y[index]];
if (self != nil) {
_index = index;
_type = TIER_TYPES[_index];
_speed = TIER_SPEEDS[_index];
_elements = [[NSMutableArray array] retain];
_skin = nil;
[self createElements];
}
return self;
}
-(void) refresh {
if (_index % 2 != 0) {
_speed = TIER_SPEEDS[_index] * _game.gameData.tierSpeed1;
} else {
_speed = TIER_SPEEDS[_index] * _game.gameData.tierSpeed2;
}
}
-(BOOL) checkCollision:(Player *) player {
TierSprite * sprite;
TierSprite * collidingWith;
CGRect player_rec = [player bounds];
BOOL collision = NO;
player.tierSpeed = 0;
for (int i = 0; i < [_elements count]; i++ ) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
if (CGRectIsNull([sprite bounds])) continue;
//check intersects
if (CGRectIntersection(player_rec, [sprite bounds]).size.width > player.skin.width*0.3) {
collision = YES;
collidingWith = sprite;
break;
}
}
//if on a tier with vehicles...
if (_type == TIER_TYPE_GROUND) {
//if collision, kill player
if (collision) return YES;
//if on a tier with logs and turtles...
} else if (_type == TIER_TYPE_WATER) {
//if no collision drown player
if (!collision) return YES;
//else, if collision, transfer tier speed to frog
player.tierSpeed = _speed;
}
return NO;
}
-(void) createElements {
NSArray * element_x = [[self getElementsX] retain];
int len = [element_x count];
NSArray * element_type;
int i;
TierSprite * sprite;
switch (_index) {
case 1:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:CAR_1]
];
}
break;
case 2:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:CAR_3]
];
}
break;
case 3:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:CAR_4]
];
}
break;
case 4:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:CAR_2]
];
}
break;
case 5:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:CAR_5]
];
}
break;
case 7:
element_type = [[NSArray arrayWithObjects:
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
nil] retain];
for (i = 0; i < len; i++) {
[_elements addObject:
[[Turtle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] animate:[ [element_type objectAtIndex:i] boolValue] ]];
}
[element_type release];
break;
case 8:
for (i = 0; i < len; i++) {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:TREELOG_SMALL]
];
}
break;
case 9:
for (i = 0; i < len; i++) {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:TREELOG_LARGE]
];
}
break;
case 10:
element_type = [[NSArray arrayWithObjects:
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
nil] retain];
for (i = 0; i < len; i++) {
[_elements addObject:
[[Turtle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] animate:[ [element_type objectAtIndex:i] boolValue]]];
}
[element_type release];
break;
case 11:
for (i = 0; i < len; i++) {
if (i == 1) {
[_elements addObject:
[[Crocodile alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index]]
];
} else {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:TIER_ELEMENT_Y[_index] type:TREELOG_MEDIUM]
];
}
}
break;
}
[element_x release];
_speed = TIER_SPEEDS[_index];
TierSprite *nextSprite;
int element_len = [_elements count];
//calculate distance between sprites (for smoother screen wrapping)
for (i = 0; i < element_len; i++) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
//if moving to the left
if (TIER_SPEEDS[_index] < 0) {
//if not the first element, distance is between this element and previous element
if (i != 0) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i-1)];
sprite.distance = sprite.x - nextSprite.x;
//else, distance is between this one and the last element
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:(element_len - 1)];
sprite.distance = sprite.x + (_game.stage.width - nextSprite.x) + sprite.skin.width;
}
//if moving to the right
} else if (TIER_SPEEDS[_index] > 0) {
//if not the last element, distance is between next element and this element
if (i != element_len - 1) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i + 1)];
sprite.distance = nextSprite.x - sprite.x;
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:0];
sprite.distance = (_game.stage.width - sprite.x) + nextSprite.x + sprite.skin.width;
}
}
}
}
-(void) update:(float)dt {
int len = [_elements count];
int i;
TierSprite * sprite;
TierSprite * nextSprite;
switch (_index) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 7:
case 8:
case 9:
case 10:
case 11:
//move sprites and wrap them on screen
for (i = 0; i < len; i++) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
sprite.speed = _speed;
[sprite update:dt];
if (_speed < 0) {
if ([sprite next_right] <= 0) {
if (i != 0) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i-1)];
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:(len-1)];
}
sprite.nextX = nextSprite.nextX + sprite.distance;
}
} else {
if ([sprite next_left] >= _game.stage.width) {
if (i != len - 1) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i+1)];
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:0];
}
sprite.nextX = nextSprite.nextX - sprite.distance;
}
}
[sprite place];
}
break;
}
}
-(void) reset {
NSArray * element_x = [[self getElementsX] retain];
TierSprite * sprite;
for (int i = 0; i < [_elements count]; i++) {
sprite = (TierSprite *)[_elements objectAtIndex:i];
sprite.x = sprite.nextX = sprite.skin.x = [[element_x objectAtIndex:i] floatValue];
}
[element_x release];
}
-(TierSprite *) getElement:(int) index {
if ([_elements count] <= index) return nil;
return [_elements objectAtIndex:index];
}
-(NSArray *) getElementsX {
switch (_index) {
//VEHICLES!!!!
case 1:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.1],
[NSNumber numberWithFloat:_game.stage.width*0.4],
[NSNumber numberWithFloat:_game.stage.width*0.6],
[NSNumber numberWithFloat:_game.stage.width*0.9],
nil];
case 2:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.2],
[NSNumber numberWithFloat:_game.stage.width*0.45],
[NSNumber numberWithFloat:_game.stage.width*0.7],
nil];
case 3:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.3],
[NSNumber numberWithFloat:_game.stage.width*0.6],
[NSNumber numberWithFloat:_game.stage.width*0.9],
nil];
case 4:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.5],
[NSNumber numberWithFloat:_game.stage.width*0.35],
nil];
case 5:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.2],
[NSNumber numberWithFloat:_game.stage.width*0.5],
[NSNumber numberWithFloat:_game.stage.width*0.8],
nil];
//LOGS AND TURTLES!!!!
case 7:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.1],
[NSNumber numberWithFloat:_game.stage.width*0.18],
[NSNumber numberWithFloat:_game.stage.width*0.26],
[NSNumber numberWithFloat:_game.stage.width*0.45],
[NSNumber numberWithFloat:_game.stage.width*0.53],
[NSNumber numberWithFloat:_game.stage.width*0.61],
[NSNumber numberWithFloat:_game.stage.width*0.8],
[NSNumber numberWithFloat:_game.stage.width*0.88],
[NSNumber numberWithFloat:_game.stage.width*0.96],
nil];
case 8:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.2],
[NSNumber numberWithFloat:_game.stage.width*0.5],
[NSNumber numberWithFloat:_game.stage.width*0.8],
nil];
case 9:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.2],
[NSNumber numberWithFloat:_game.stage.width*0.8],
nil];
case 10:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.05],
[NSNumber numberWithFloat:_game.stage.width*0.13],
[NSNumber numberWithFloat:_game.stage.width*0.35],
[NSNumber numberWithFloat:_game.stage.width*0.43],
[NSNumber numberWithFloat:_game.stage.width*0.62],
[NSNumber numberWithFloat:_game.stage.width*0.7],
[NSNumber numberWithFloat:_game.stage.width*0.9],
[NSNumber numberWithFloat:_game.stage.width*0.98],
nil];
case 11:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.stage.width*0.15],
[NSNumber numberWithFloat:_game.stage.width*0.5],
[NSNumber numberWithFloat:_game.stage.width*0.85],
nil];
}
return nil;
}
-(void) dealloc {
[_elements removeAllObjects];
[_elements release];
[super dealloc];
}
@end
Cocos2D: Tier
#import "Tier.h"
#import "Game.h"
#import "Player.h"
#import "TierSprite.h"
#import "Vehicle.h"
#import "TreeLog.h"
#import "Turtle.h"
#import "Crocodile.h"
static int TIER_Y[] = {418,388,357,328,300,272,244,216,182,149,117,84,52};
static int TIER_ELEMENT_Y[] = {0,396,367,339,310,281,0,228,194,161,129,95,65};
static int TIER_TYPES[] = {0,0,0,0,0,0,0,1,1,1,1,1,2};
static int TIER_SPEEDS[] = {0,-20,25,-20,40,-25,0,-30,20,40,-25,20,0};
@implementation Tier
@synthesize type = _type, speed = _speed;
+ (int) TIER_Y:(int) index {
return TIER_Y[index];
}
+ (int) TIER_ELEMENT_Y:(int) index {
return TIER_ELEMENT_Y[index];
}
+ (int) TIER_TYPES:(int) index {
return TIER_TYPES[index];
}
+ (int) TIER_SPEEDS:(int) index {
return TIER_SPEEDS[index];
}
-(id) initWithGame:(Game *) game level:(int) index {
self = [super initWithGame:game x:0 y:TIER_Y[index]];
if (self != nil) {
_index = index;
_type = TIER_TYPES[_index];
_speed = TIER_SPEEDS[_index];
_elements = [[NSMutableArray array] retain];
_skin = nil;
[self createElements];
}
return self;
}
-(void) refresh {
if (_index % 2 != 0) {
_speed = TIER_SPEEDS[_index] * _game.gameData.tierSpeed1;
} else {
_speed = TIER_SPEEDS[_index] * _game.gameData.tierSpeed2;
}
}
-(BOOL) checkCollision:(Player *) player {
TierSprite * sprite;
TierSprite * collidingWith;
CGRect player_rec = [player bounds];
BOOL collision = NO;
player.tierSpeed = 0;
for (int i = 0; i < [_elements count]; i++ ) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
if (CGRectIsNull([sprite bounds])) continue;
//check intersects
if (CGRectIntersection(player_rec, [sprite bounds]).size.width > player.width*0.3) {
collision = YES;
collidingWith = sprite;
break;
}
}
//if on a tier with vehicles...
if (_type == TIER_TYPE_GROUND) {
//if collision, kill player
if (collision) return YES;
//if on a tier with logs and turtles...
} else if (_type == TIER_TYPE_WATER) {
//if no collision drown player
if (!collision) return YES;
//else, if collision, transfer tier speed to frog
player.tierSpeed = _speed;
}
return NO;
}
-(void) createElements {
NSArray * element_x = [[self getElementsX] retain];
int len = [element_x count];
NSArray * element_type;
int i;
TierSprite * sprite;
switch (_index) {
case 1:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:CAR_1]
];
}
break;
case 2:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:CAR_3]
];
}
break;
case 3:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:CAR_4]
];
}
break;
case 4:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:CAR_2]
];
}
break;
case 5:
for (i = 0; i < len; i++) {
[_elements addObject:
[[Vehicle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:CAR_5]
];
}
break;
case 7:
element_type = [[NSArray arrayWithObjects:
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
nil] retain];
for (i = 0; i < len; i++) {
[_elements addObject:
[[Turtle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] animate:[ [element_type objectAtIndex:i] boolValue] ]];
}
[element_type release];
break;
case 8:
for (i = 0; i < len; i++) {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:TREELOG_SMALL]
];
}
break;
case 9:
for (i = 0; i < len; i++) {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:TREELOG_LARGE]
];
}
break;
case 10:
element_type = [[NSArray arrayWithObjects:
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:YES],
[NSNumber numberWithBool:NO],
[NSNumber numberWithBool:NO],
nil] retain];
for (i = 0; i < len; i++) {
[_elements addObject:
[[Turtle alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] animate:[ [element_type objectAtIndex:i] boolValue]]];
}
[element_type release];
break;
case 11:
for (i = 0; i < len; i++) {
if (i == 1) {
[_elements addObject:
[[Crocodile alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index]]
];
} else {
[_elements addObject:
[[TreeLog alloc] initWithGame:_game x:[[element_x objectAtIndex:i] floatValue] y:_game.screenHeight - TIER_ELEMENT_Y[_index] type:TREELOG_MEDIUM]
];
}
}
break;
}
[element_x release];
_speed = TIER_SPEEDS[_index];
TierSprite *nextSprite;
int element_len = [_elements count];
//calculate distance between sprites (for smoother screen wrapping)
for (i = 0; i < element_len; i++) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
//if moving to the left
if (TIER_SPEEDS[_index] < 0) {
//if not the first element, distance is between this element and previous element
if (i != 0) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i-1)];
sprite.distance = sprite.x - nextSprite.x;
//else, distance is between this one and the last element
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:(element_len - 1)];
sprite.distance = sprite.x + (_game.screenWidth - nextSprite.x) + sprite.width;
}
//if moving to the right
} else if (TIER_SPEEDS[_index] > 0) {
//if not the last element, distance is between next element and this element
if (i != element_len - 1) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i + 1)];
sprite.distance = nextSprite.x - sprite.x;
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:0];
sprite.distance = (_game.screenWidth - sprite.x) + nextSprite.x + sprite.width;
}
}
}
}
-(void) update:(float)dt {
int len = [_elements count];
int i;
TierSprite * sprite;
TierSprite * nextSprite;
switch (_index) {
case 1:
case 2:
case 3:
case 4:
case 5:
case 7:
case 8:
case 9:
case 10:
case 11:
//move sprites and wrap them on screen
for (i = 0; i < len; i++) {
sprite = (TierSprite *) [_elements objectAtIndex:i];
sprite.speed = _speed;
[sprite update:dt];
if (_speed < 0) {
if ([sprite next_right] <= 0) {
if (i != 0) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i-1)];
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:(len-1)];
}
sprite.nextX = nextSprite.nextX + sprite.distance;
}
} else {
if ([sprite next_left] >= _game.screenWidth) {
if (i != len - 1) {
nextSprite = (TierSprite *) [_elements objectAtIndex:(i+1)];
} else {
nextSprite = (TierSprite *) [_elements objectAtIndex:0];
}
sprite.nextX = nextSprite.nextX - sprite.distance;
}
}
[sprite place];
}
break;
}
}
-(void) reset {
NSArray * element_x = [[self getElementsX] retain];
TierSprite * sprite;
CGPoint pos;
for (int i = 0; i < [_elements count]; i++) {
sprite = (TierSprite *)[_elements objectAtIndex:i];
pos = sprite.skin.position;
sprite.x = sprite.nextX = [[element_x objectAtIndex:i] floatValue];
pos.x = sprite.x;
sprite.skin.position = pos;
}
[element_x release];
}
-(TierSprite *) getElement:(int) index {
if ([_elements count] <= index) return nil;
return [_elements objectAtIndex:index];
}
-(NSArray *) getElementsX {
switch (_index) {
//VEHICLES!!!!
case 1:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.1],
[NSNumber numberWithFloat:_game.screenWidth*0.4],
[NSNumber numberWithFloat:_game.screenWidth*0.6],
[NSNumber numberWithFloat:_game.screenWidth*0.9],
nil];
case 2:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.2],
[NSNumber numberWithFloat:_game.screenWidth*0.45],
[NSNumber numberWithFloat:_game.screenWidth*0.7],
nil];
case 3:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.3],
[NSNumber numberWithFloat:_game.screenWidth*0.6],
[NSNumber numberWithFloat:_game.screenWidth*0.9],
nil];
case 4:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.5],
[NSNumber numberWithFloat:_game.screenWidth*0.35],
nil];
case 5:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.2],
[NSNumber numberWithFloat:_game.screenWidth*0.5],
[NSNumber numberWithFloat:_game.screenWidth*0.8],
nil];
//LOGS AND TURTLES!!!!
case 7:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.1],
[NSNumber numberWithFloat:_game.screenWidth*0.18],
[NSNumber numberWithFloat:_game.screenWidth*0.26],
[NSNumber numberWithFloat:_game.screenWidth*0.45],
[NSNumber numberWithFloat:_game.screenWidth*0.53],
[NSNumber numberWithFloat:_game.screenWidth*0.61],
[NSNumber numberWithFloat:_game.screenWidth*0.8],
[NSNumber numberWithFloat:_game.screenWidth*0.88],
[NSNumber numberWithFloat:_game.screenWidth*0.96],
nil];
case 8:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.2],
[NSNumber numberWithFloat:_game.screenWidth*0.5],
[NSNumber numberWithFloat:_game.screenWidth*0.8],
nil];
case 9:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.2],
[NSNumber numberWithFloat:_game.screenWidth*0.8],
nil];
case 10:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.05],
[NSNumber numberWithFloat:_game.screenWidth*0.13],
[NSNumber numberWithFloat:_game.screenWidth*0.35],
[NSNumber numberWithFloat:_game.screenWidth*0.43],
[NSNumber numberWithFloat:_game.screenWidth*0.62],
[NSNumber numberWithFloat:_game.screenWidth*0.7],
[NSNumber numberWithFloat:_game.screenWidth*0.9],
[NSNumber numberWithFloat:_game.screenWidth*0.98],
nil];
case 11:
return [NSArray arrayWithObjects:
[NSNumber numberWithFloat:_game.screenWidth*0.15],
[NSNumber numberWithFloat:_game.screenWidth*0.5],
[NSNumber numberWithFloat:_game.screenWidth*0.85],
nil];
}
return nil;
}
-(void) dealloc {
[_elements removeAllObjects];
[_elements release];
[super dealloc];
}
@end
Sparrow: LevelTimer
#import "LevelTimer.h"
#import "Game.h"
#import "GameScreen.h"
@implementation LevelTimer
@synthesize seconds = _seconds;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_timeWidth = 180;
_seconds = 0;
_timeLabel = [SPImage imageWithTexture:[_game.imageCache textureByName:@"label_time"]];
_timeLabel.x = _x - _game.stage.width * 0.45;
_timeLabel.y = _y;
_timeBar = [SPQuad quadWithWidth:_timeWidth height:10.0f color:0x00FF00];
_timeBar.x = _x - _game.stage.width * 0.3;
_timeBar.y = _y + _timeBar.height * 0.2;
[[_game getScreen] addChild:_timeLabel];
[[_game getScreen] addChild:_timeBar];
_timeDecrement = _timeWidth * 0.002;
}
return self;
}
-(void) tickTock {
if (_game.gameData.gameMode == GAME_STATE_PLAY) {
_seconds++;
//reduce time bar width
if (_timeBar.width - _timeDecrement <= 0) {
[(GameScreen *) [_game getScreen] gameOver];
_timeBar.visible = NO;
[_timer invalidate];
} else {
_timeBar.width -= _timeDecrement;
}
}
}
-(void) pauseTimer {
[_timer invalidate];
}
-(void) startTimer {
if (![_timer isValid]) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tickTock) userInfo:nil repeats:YES];
}
}
-(void) reset {
_seconds = 0;
_timeBar.width = _timeWidth;
_timeBar.visible = YES;
}
-(void) dealloc {
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
[super dealloc];
}
@end
Cocos2D: LevelTimer
#import "LevelTimer.h"
#import "Game.h"
#import "GameScreen.h"
#import "GameData.h"
@implementation LevelTimer
@synthesize seconds = _seconds;
-(id) initWithGame:(Game *)game x:(float)posx y:(float)posy {
self = [super initWithGame:game x:posx y:posy];
if (self != nil) {
_timeWidth = 180;
_seconds = 0;
_timeLabel = [_game.imageCache getSkin:@"label_time.png"];
_timeLabel.position = CGPointMake(_x, _y);
_timeBar = [_game.imageCache getSkin:@"time_bar.png"];
[_timeBar setAnchorPoint:ccp(0,0)];
_timeBar.position = CGPointMake(_x + _game.screenWidth * 0.08, _y - _timeBar.textureRect.size.height * 0.5);
[[_game getScreen] addSprite:_timeLabel];
[[_game getScreen] addSprite:_timeBar];
_textureRectangleFull = _textureRectangle = _timeBar.textureRect;
_timeDecrement = _timeBar.textureRect.size.width * 0.004;
}
return self;
}
-(void) tickTock {
//return;
if (_game.gameData.gameMode == GAME_STATE_PLAY) {
_seconds++;
//reduce time bar width
if (_textureRectangle.size.width - _timeDecrement <= 0) {
[(GameScreen *) [_game getScreen] gameOver];
_timeBar.visible = NO;
[_timer invalidate];
} else {
_textureRectangle.size.width -= _timeDecrement;
[_timeBar setTextureRect:_textureRectangle];
}
}
}
-(void) pauseTimer {
[_timer invalidate];
}
-(void) startTimer {
if (![_timer isValid]) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tickTock) userInfo:nil repeats:YES];
}
}
-(void) reset {
_seconds = 0;
_textureRectangle = _textureRectangleFull;
[_timeBar setTextureRect:_textureRectangle];
_timeBar.visible = YES;
}
-(void) dealloc {
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
[super dealloc];
}
@end

