Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #import "Lemming.h"
00011
00012 @interface Lemming()
00013
00014 -(void)initAnimations;
00015 -(void)resetState;
00016 -(void)changeStateDelegate:(id)_newState;
00017 -(void)useHelmet:(BOOL)_useHelmet;
00018 -(void)useUmbrella;
00019 -(void)checkForCollisions:(CCArray*)_listOfGameObjects;
00020 -(void)checkLemmingWithinScreenBounds;
00021 -(void)updateDebugLabel;
00022
00023 @end
00024
00025 @implementation Lemming
00026
00027 @synthesize health;
00028 @synthesize state;
00029
00030 @synthesize helmetUses;
00031 @synthesize umbrellaUses;
00032
00033
00034 @synthesize idleAnim;
00035 @synthesize idleHelmetAnim;
00036 @synthesize walkingAnim;
00037 @synthesize walkingHelmetAnim;
00038 @synthesize openUmbrellaAnim;
00039 @synthesize floatUmbrellaAnim;
00040 @synthesize deathAnim;
00041
00042
00043 @synthesize ID;
00044 @synthesize debugLabel;
00045
00046 #pragma mark -
00047 #pragma mark Memory Allocation
00048
00052 -(void)dealloc
00053 {
00054 [idleAnim release];
00055 [idleHelmetAnim release];
00056 [walkingAnim release];
00057 [walkingHelmetAnim release];
00058 [openUmbrellaAnim release];
00059 [floatUmbrellaAnim release];
00060 [deathAnim release];
00061
00062 debugLabel = nil;
00063
00064 [super dealloc];
00065 }
00066
00067 #pragma mark -
00068 #pragma mark Initialisation
00069
00074 -(id)init
00075 {
00076 self = [super init];
00077
00078 if (self != nil)
00079 {
00080 self.gameObjectType = kLemmingType;
00081 respawns = kLemmingRespawns;
00082 movementDirection = kDirectionRight;
00083 [self initAnimations];
00084 [self resetState];
00085 [self changeState:kStateSpawning];
00086 }
00087 return self;
00088 }
00089
00093 -(void)initAnimations
00094 {
00095 [self setIdleAnim:[self loadAnimationFromPlistWthName:@"idleAnim" andClassName:@"Lemming"]];
00096 [self setIdleHelmetAnim:[self loadAnimationFromPlistWthName:@"idleHelmetAnim" andClassName:@"Lemming"]];
00097 [self setWalkingAnim:[self loadAnimationFromPlistWthName:@"walkingAnim" andClassName:@"Lemming"]];
00098 [self setWalkingHelmetAnim:[self loadAnimationFromPlistWthName:@"walkingHelmetAnim" andClassName:@"Lemming"]];
00099 [self setOpenUmbrellaAnim:[self loadAnimationFromPlistWthName:@"openUmbrellaAnim" andClassName:@"Lemming"]];
00100 [self setFloatUmbrellaAnim:[self loadAnimationFromPlistWthName:@"floatUmbrellaAnim" andClassName:@"Lemming"]];
00101 [self setDeathAnim:[self loadAnimationFromPlistWthName:@"deathAnim" andClassName:@"Lemming"]];
00102 }
00103
00107 -(void)resetState
00108 {
00109 health = 100;
00110 spawnTime = [[GameManager sharedGameManager] getGameTimeInSecs];
00111 actionsTaken = 0;
00112 isUsingHelmet = NO;
00113 isUsingUmbrella = NO;
00114 umbrellaEquipped = NO;
00115 umbrellaTimer = 0;
00116 objectLastCollidedWith = kObjectTypeNone;
00117 helmetUses = [[[GameManager sharedGameManager] currentLevel] helmetUses];
00118 umbrellaUses = [[[GameManager sharedGameManager] currentLevel] umbrellaUses];
00119 if(movementDirection != kDirectionRight) [self changeDirection];
00120 }
00121
00122 #pragma mark -
00123 #pragma mark State Changing
00124
00129 -(void)changeState: (CharacterStates)_newState
00130 {
00131
00132 if(umbrellaEquipped)
00133 {
00134 if(umbrellaTimer >= 70) [self useUmbrella];
00135 return;
00136 }
00137
00138
00139 [self stopAllActions];
00140 id action = nil;
00141 self.state = _newState;
00142
00143 fallCounter = 0;
00144
00145 switch(_newState)
00146 {
00147 case kStateSpawning:
00148 [self setPosition:ccp([GameManager sharedGameManager].currentLevel.spawnPoint.x, [GameManager sharedGameManager].currentLevel.spawnPoint.y)];
00149 if (isUsingHelmet) [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_helmet_1.png"]];
00150 else [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_1.png"]];
00151 [self resetState];
00152 respawns--;
00153 [self changeState:kStateFalling];
00154 break;
00155
00156 case kStateFalling:
00157 if (isUsingHelmet) [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_helmet_1.png"]];
00158 else [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_1.png"]];
00159 action = [CCSpawn actions: [CCMoveBy actionWithDuration:0.1f position:ccp(0.0f, kLemmingFallAmount*-1)], action, nil];
00160 break;
00161
00162 case kStateIdle:
00163 if (isUsingHelmet) [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_helmet_1.png"]];
00164 else [self setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"Lemming_idle_1.png"]];
00165 break;
00166
00167 case kStateWalking:
00168 if(isUsingHelmet) action = [CCAnimate actionWithAnimation:walkingHelmetAnim restoreOriginalFrame:NO];
00169 else action = [CCAnimate actionWithAnimation:walkingAnim restoreOriginalFrame:YES];
00170 id walkingAction = [CCMoveBy actionWithDuration:1.04f position:ccp((movementDirection == kDirectionLeft) ? kLemmingMovementAmount * -1 : kLemmingMovementAmount, 0.0f)];
00171 action = [CCSpawn actions: walkingAction, action, nil];
00172 break;
00173
00174 case kStateFloating:
00175 action = [CCAnimate actionWithAnimation:openUmbrellaAnim restoreOriginalFrame:NO];
00176 break;
00177
00178 case kStateDead:
00179 action = [CCAnimate actionWithAnimation:deathAnim restoreOriginalFrame:NO];
00180 break;
00181
00182 case kStateWin:
00183 break;
00184
00185 default:
00186 CCLOG(@"Lemming.changeState: unknown state '%@'", [Utils getStateAsString:_newState]);
00187 break;
00188 }
00189
00190
00191 if(action != nil)
00192 {
00193 if(_newState != kStateDead && _newState != kStateFloating) action = [CCRepeatForever actionWithAction:action];
00194 [self runAction:action];
00195 }
00196 }
00197
00203 -(void)changeState: (CharacterStates)_newState afterDelay:(float)_delay
00204 {
00205 [self performSelector:@selector(changeStateDelegate:) withObject:[NSNumber numberWithInt:_newState] afterDelay:_delay];
00206 }
00207
00208 -(void)changeStateDelegate:(id)_newState
00209 {
00210 [self changeState:(CharacterStates)[_newState intValue]];
00211 }
00212
00213 #pragma mark -
00214
00219 -(void)takePath:(Action)_action
00220 {
00221 if(_action == -1) { CCLOG(@"Lemming.takePath: Unknown action chosen"); return; }
00222
00223 switch (_action)
00224 {
00225 case kActionLeft:
00226 if(movementDirection != kDirectionLeft) [self changeDirection];
00227 break;
00228
00229 case kActionRight:
00230 if(movementDirection != kDirectionRight) [self changeDirection];
00231 break;
00232
00233 case kActionLeftHelmet:
00234 if(movementDirection != kDirectionLeft) [self changeDirection];
00235 if(!isUsingHelmet) [self useHelmet:YES];
00236 break;
00237
00238 case kActionRightHelmet:
00239 if(movementDirection != kDirectionRight) [self changeDirection];
00240 if(!isUsingHelmet) [self useHelmet:YES];
00241 break;
00242
00243 case kActionEquipUmbrella:
00244 umbrellaEquipped = YES;
00245 break;
00246
00247 case kActionDownUmbrella:
00248 isUsingUmbrella = YES;
00249 [self performSelector:@selector(useUmbrella) withObject:nil afterDelay:2.0f];
00250 break;
00251
00252 case kActionDown:
00253 [self changeState:kStateFalling afterDelay:2.0f];
00254 break;
00255
00256 default:
00257 break;
00258 }
00259
00260 if(isUsingHelmet && _action != kActionLeftHelmet && _action != kActionRightHelmet) [self useHelmet:NO];
00261
00262
00263 actionsTaken++;
00264 }
00265
00269 -(void)changeDirection
00270 {
00271 if(movementDirection == kDirectionRight)
00272 {
00273 self.flipX = YES;
00274 movementDirection = kDirectionLeft;
00275 [self setPosition:ccp(self.position.x-1, self.position.y)];
00276 }
00277 else
00278 {
00279 self.flipX = NO;
00280 movementDirection = kDirectionRight;
00281 [self setPosition:ccp(self.position.x+1, self.position.y)];
00282 }
00283
00284 [self changeState:kStateWalking];
00285 }
00286
00291 -(void)onEndConditionReached
00292 {
00293
00294 if(self.state == kStateDead)
00295 {
00296 if(respawns > 0) [self changeState:kStateSpawning];
00297 else [[LemmingManager sharedLemmingManager] removeLemming:self];
00298 }
00299
00300 else [[LemmingManager sharedLemmingManager] removeLemming:self];
00301 }
00302
00303 #pragma mark -
00304 #pragma mark Tools
00305
00309 -(void)useHelmet:(BOOL)_useHelmet
00310 {
00311 if(isUsingHelmet != _useHelmet)
00312 {
00313 isUsingHelmet = _useHelmet;
00314 helmetUses--;
00315 [self changeState:kStateWalking];
00316 }
00317 }
00318
00322 -(void)useUmbrella
00323 {
00324 if(isUsingUmbrella || umbrellaEquipped)
00325 {
00326
00327 isUsingUmbrella = NO;
00328 umbrellaEquipped = NO;
00329 umbrellaUses--;
00330 umbrellaTimer = 0;
00331 [self changeState:kStateFloating];
00332 }
00333 }
00334
00335
00336 #pragma mark -
00337 #pragma mark Collisions
00338
00343 -(void)checkForCollisions:(CCArray*)_listOfGameObjects
00344 {
00345 CCArray* collisions = [CCArray arrayWithCapacity:0];
00346 CGRect selfBBox = [self adjustedBoundingBox];
00347 BOOL colliding = NO;
00348
00349 for (GameObject *gameObject in _listOfGameObjects)
00350 {
00351
00352
00353 if(gameObject == self || gameObject.gameObjectType == kLemmingType) continue;
00354
00355 CGRect objectBBox = [gameObject adjustedBoundingBox];
00356 if(CGRectIntersectsRect(selfBBox, objectBBox))
00357 {
00358 [collisions addObject:gameObject];
00359 if(gameObject.gameObjectType == kObjectTerrain || gameObject.gameObjectType == kObjectTrapdoor) colliding = YES;
00360 }
00361 }
00362
00363
00364 if(!colliding && state != kStateSpawning && state != kStateFalling && state != kStateFloating && state != kStateDead) [self changeState:kStateFalling];
00365
00366
00367 if([collisions count] > 0)
00368 {
00369 GameObject* object = nil;
00370
00371
00372 if([collisions count] > 1)
00373 {
00374 GameObject* object1 = [collisions objectAtIndex:0];
00375 GameObject* object2 = [collisions objectAtIndex:1];
00376
00377 if(object1.gameObjectType == kObjectTerrain || object2.gameObjectType == kObjectTerrain)
00378 {
00379 if(object1.gameObjectType == kObjectTerrain) object = object2;
00380 else object = object1;
00381 }
00382 }
00383 else object = [collisions objectAtIndex:0];
00384
00385
00386 if(![object isCollideable]) return;
00387
00388 if(object.gameObjectType == objectLastCollidedWith)
00389 {
00390 if(object.gameObjectType == kObjectTerrain && (self.state == kStateFalling || self.state == kStateFloating));
00391 else return;
00392 }
00393 else objectLastCollidedWith = object.gameObjectType;
00394
00395 [self onObjectCollision:object];
00396 }
00397 }
00398
00402 -(void)checkLemmingWithinScreenBounds
00403 {
00404 CGPoint position = [self position];
00405
00406
00407 if (position.x <= 10)
00408 {
00409 [self setPosition:ccp(self.position.x+0.5, self.position.y)];
00410 [self changeDirection];
00411 }
00412 else if(position.x >= 470)
00413 {
00414 [self setPosition:ccp(self.position.x-0.5, self.position.y)];
00415 [self changeDirection];
00416 }
00417
00418 if (position.y <= 20) [self changeState:kStateDead];
00419 }
00420
00426 -(void)onObjectCollision:(GameObject*)_object
00427 {
00428 switch([_object gameObjectType])
00429 {
00430 case kObstaclePit:
00431 case kObstacleWater:
00432 [self changeState:kStateDead];
00433 break;
00434
00435 case kObstacleStamper:
00436 if(!isUsingHelmet) [self changeState:kStateDead];
00437 break;
00438
00439 case kObjectExit:
00440 [self changeState:kStateWin afterDelay:1.0f];
00441 break;
00442
00443 case kObjectTerrain:
00444 if(self.state != kStateWalking && self.state != kStateDead && self.state != kStateWin && ![(Terrain*)_object isWall])
00445 {
00446 if(fallCounter >= ((float)kLemmingFallTime*(float)kFrameRate) && self.state != kStateFloating) [self changeState:kStateDead];
00447 else [self changeState:kStateWalking];
00448 }
00449 else if([(Terrain*)_object isWall]) [self changeDirection];
00450 break;
00451
00452 case kObjectTerrainEnd:
00453 case kObjectTrapdoor:
00454 case kObstacleCage:
00455
00456 break;
00457
00458 default:
00459 CCLOG(@"Lemming.onObjectCollision: %@", [Utils getObjectAsString:_object.gameObjectType]);
00460 break;
00461 }
00462 }
00463
00464 #pragma mark -
00465 #pragma mark Update
00466
00472 -(void)updateStateWithDeltaTime:(ccTime)_deltaTime andListOfGameObjects:(CCArray*)_listOfGameObjects
00473 {
00474
00475 if(self.health <= 0 && self.state != kStateDead) { [self changeState:kStateDead]; return; }
00476
00477
00478 if (state != kStateDead) [self checkLemmingWithinScreenBounds];
00479
00480
00481 [self checkForCollisions:_listOfGameObjects];
00482
00483
00484 if(self.state == kStateFalling) fallCounter++;
00485 if(umbrellaEquipped) umbrellaTimer++;
00486
00487
00488 [self updateDebugLabel];
00489
00490 [super updateStateWithDeltaTime:_deltaTime andListOfGameObjects:_listOfGameObjects];
00491
00492
00493
00494
00495 if([self numberOfRunningActions] == 0)
00496 {
00497 if(self.state == kStateFloating)
00498 {
00499
00500 id floatAction = [CCAnimate actionWithAnimation:floatUmbrellaAnim restoreOriginalFrame:NO];
00501 id floatingAction = [CCMoveBy actionWithDuration:0.75f position:ccp(0.0f, kLemmingMovementAmount*-1)];
00502 floatAction = [CCSpawn actions: floatingAction, floatAction, nil];
00503 floatAction = [CCRepeatForever actionWithAction:floatAction];
00504 [self runAction:floatAction];
00505 }
00506
00507 if(self.state == kStateWin || self.state == kStateDead) [self onEndConditionReached];
00508 }
00509 }
00510
00514 -(void)updateDebugLabel
00515 {
00516 CGPoint newPosition = [self position];
00517
00518 [debugLabel setString:@""];
00519
00520 float yOffset = 20.0f;
00521 newPosition = ccp(newPosition.x, newPosition.y+yOffset);
00522 [debugLabel setPosition:newPosition];
00523 }
00524
00525 #pragma mark -
00526 #pragma mark Getters/Setters
00527
00533 -(CGRect)adjustedBoundingBox
00534 {
00535 CGRect bBox = [self boundingBox];
00536 float xCropAmount = bBox.size.width * 0.25;
00537 float yCropAmount = bBox.size.height * 0.095f;
00538
00539 bBox = CGRectMake(bBox.origin.x, bBox.origin.y, bBox.size.width-xCropAmount, bBox.size.height-yCropAmount);
00540
00541 return bBox;
00542 }
00543
00547 -(int)respawns
00548 {
00549 return respawns;
00550 }
00551
00552 @end