-(void)changeState:(CharacterStates)newState {
if (characterState == kStateDead)
return; // No need to change state further once I am dead
[self stopAllActions];
id action = nil;
characterState = newState;
switch (newState) {
case kStateSpawning:
[self runAction:[CCFadeOut actionWithDuration:0.0f]]; // Fades out the sprite if it was visible before
[self setDisplayFrame: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"teleport.png"]];
action = [CCSpawn actions:
[CCRotateBy actionWithDuration:1.5f angle:360],
[CCFadeIn actionWithDuration:1.5f], nil];
break;
case kStateIdle:
CCLOG(@"EnemyRobot->Changing State to Idle");
[self setDisplayFrame: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"an1_anim1.png"]];
break;
case kStateWalking:
CCLOG(@"EnemyRobot->Changing State to Walking");
if (isVikingWithinBoundingBox)
break; // AI will change to Attacking on next frame
float xPositionOffSet = 150.0f;
if (isVikingWithinSight) {
if ([vikingCharacter position].x < [self position].x) xPositionOffSet = xPositionOffSet * -1;
// Invert to -150
} else {
if (CCRANDOM_0_1() > 0.5f) xPositionOffSet = xPositionOffSet * -1;
if (xPositionOffSet > 0.0f) {
[self setFlipX:YES];
} else {
[self setFlipX:NO];
}
}
action = [CCSpawn actions:
[CCAnimate actionWithAnimation:robotWalkingAnim restoreOriginalFrame:NO],
[CCMoveTo actionWithDuration:2.4f position:ccp([self position].x + xPositionOffSet,[self position].y)], nil];
break;
case kStateAttacking:
CCLOG(@"EnemyRobot->Changing State to Attacking");
action = [CCSequence actions:
[CCAnimate actionWithAnimation:raisePhaserAnim restoreOriginalFrame:NO],
[CCDelayTime actionWithDuration:1.0f],
[CCAnimate actionWithAnimation:shootPhaserAnim restoreOriginalFrame:NO],
[CCCallFunc actionWithTarget:self selector:@selector(shootPhaser)],
[CCAnimate actionWithAnimation:lowerPhaserAnim restoreOriginalFrame:NO],
[CCDelayTime actionWithDuration:2.0f], nil];
break;
case kStateTakingDamage:
CCLOG(@"EnemyRobot->Changing State to TakingDamage");
if ([vikingCharacter getWeaponDamage] > kVikingFistDamage){
// If the viking has the mallet, then
action = [CCAnimate actionWithAnimation:headHitAnim restoreOriginalFrame:YES];
} else {
// Viking does not have weapon, body blow
action = [CCAnimate actionWithAnimation:torsoHitAnim restoreOriginalFrame:YES];
}
break;
case kStateDead:
CCLOG(@"EnemyRobot -> Going to Dead State");
action = [CCSequence actions: [CCAnimate actionWithAnimation:robotDeathAnim restoreOriginalFrame:NO],
[CCDelayTime actionWithDuration:2.0f],
[CCFadeOut actionWithDuration:2.0f],
nil];
break;
default: CCLOG(@"Enemy Robot -> Unknown CharState %d",characterState);
break;
}
if (action != nil)
[self runAction:action];
}
死亡:
(AI)gameUpdate 会在“适当的时候“来调用changeState,所以gameUpdate的责任是思考----” 如果是什么什么情况,就怎么样“。。。 如此这般。
然后决定了要”怎么样“,由改变状态 changeState来处理。 (just like your boss & you)
每次状态的改变应该带来行为的改变,例如本来在巡逻”walking“的敌人,在发现玩家后会改为”攻击“状态。所以stopAllAction在开始便要执行。
---- 下面是AI部分
-(void)updateStateWithDeltaTime:(ccTime)deltaTime andListOfGameObjects:(CCArray*)listOfGameObjects {
[self checkAndClampSpritePosition];
if ((characterState != kStateDead) && (characterHealth <= 0)) {
[self changeState:kStateDead];
return;
}
vikingCharacter = (GameCharacter*)[[self parent] getChildByTag:kVikingSpriteTagValue];
CGRect vikingBoundingBox = [vikingCharacter adjustedBoundingBox];
CGRect robotBoundingBox = [self adjustedBoundingBox];
CGRect robotSightBoundingBox = [self eyesightBoundingBox];
isVikingWithinBoundingBox = CGRectIntersectsRect(vikingBoundingBox, robotBoundingBox) ? YES : NO;
isVikingWithinSight = CGRectIntersectsRect(vikingBoundingBox, robotSightBoundingBox)? YES : NO;
if ((isVikingWithinBoundingBox) && ([vikingCharacter characterState] == kStateAttacking)) {
// Viking is attacking this robot
if ((characterState != kStateTakingDamage) && (characterState != kStateDead)) {
[self setCharacterHealth: [self characterHealth] – [vikingCharacter getWeaponDamage]];
if (characterHealth > 0) {
[self changeState:kStateTakingDamage];
} else {
[self changeState:kStateDead];
}
return; // Nothing to update further, stop and show damage
}
}
if ([self numberOfRunningActions] == 0) { // -- 1
if (characterState == kStateDead) {
// Robot is dead, remove
[self setVisible:NO];
[self removeFromParentAndCleanup:YES];
} else if ([vikingCharacter characterState] == kStateDead) {
// Viking is dead, walk around the scene
[self changeState:kStateWalking];
} else if (isVikingWithinSight) {
[self changeState:kStateAttacking];
} else {
// Viking alive and out of sight, resume walking
[self changeState:kStateWalking];
}
}
}
1-- 关键的一句
例如创建时状态是spawning,此时 updateStateWithDeltaTime 判断为:执行一个1.5s 的动画action。
如果没有1,enemy的状态会在下一个运算循环中被改为其它状态。
numberOfRunningActions 让enemy在做完前一阶段的动作后,再回到AI判断,下一阶段应该是什么。