1
votes

Just to clarify: this is not a question about sequences or groups of SKActions.

I have 7-20 sprites representing monsters on a 2D game board. I would like them to act one after another. The action can be a move, or move and attack.

The issue that I'm running in is that the first few monsters seem to act normally, - one monster moves, attacks, then the next one, etc. But after a few of them (4-5) the sequence breaks and multiple monsters start to act at the same time.

Is this an issue with the recursive move/AI methods I have below or if something within Sprite Kit is interfering with the sequence?

I see that the call stack in xCode seems to grow, and I see multiple calls to processMonsterAI, but it's not a 1 call per monster situation.

In particular I'm interested if I should use NSTimers or Delayed dispatch queue blocks instead of relying on Sprite Kit's completion blocks?

Every turn, my AI has to move monsters on the board:

-(void)processMonsterAI
{
    CharacterModelNode* monster = [allMonstersCopy lastObject];
    [allMonstersCopy removeLastObject];

     AIBase* ai = monster.character.AI;
     ai.delegate = self;
     ai doAIAction];

}

AI frequently makes decisions to move around the board, which are animated as move from one cell to the next, step by step until the monster is out of moves or destination is reached:

//do recursive movement animation

-(void)recursiveMoveWithCharacter:(CharacterModelNode*)characterModel path:(NSMutableArray*)path
{
    //check if we ran out of moves 
    if(path.count == 0)
    {
        //notify delegate
        [self moveCompleteForCharacter:characterModel];

    }else
    {
        NSNumber* tileIndex =  path[0];
        CGPoint destination = [MapOfTiles positionForTileAtIndex:tileIndex.intValue];
        [path removeObjectAtIndex:0];

        [self runAction:[SKAction moveTo:destination duration:1]
             completion:^{

            characterModel.character.currentMoves = characterModel.character.currentMoves-1;

            [self recursiveMoveWithCharacter:characterModel path:path];
        }];

    }
}

Once the animation completes, the AI is notified that the monster is in a correct position, and attack sequence can be performed:

//once animation is complete, call
-(void)moveComplete
{

    if(self.bestTarget)
    {
        [self.actor attack:self.bestTarget];    
    }
    //notify whoever is the delegate that we are done here and the next AI can do it's magic.

    [self finishAction];
}


//AI is done, notify delegate to process next monster
-(void)finishAction
{
    NSLog(@"Finished :%@",self.actor.character.name);
    [self.actor debugFlashRed];
    if([self.delegate respondsToSelector:@selector(didFinishAIAction:)])
    {
        [self.delegate didFinishAIAction:self];
    }
}

Proceed to move/attack with the next monster

//either repeat the process, or terminate if all monsters acted
-(void)didFinishAIAction:(AIBase*)AI
{
 if(allMonstersCopy.count==0)
 {
     //finished with monster turn
     [self preventUserInteraction:NO];
     [[GameDataManager sharedInstance] processEndTurn];

 }else
 {
     [self processMonsterAI];
 }
}

UPDATE:

Here's the call stack, It hits the assertion that finishAction gets called by some AI more than once: enter image description here

1

1 Answers

1
votes

Does doAIAction possibly go through multiple paths that may call finishAction more then once? That does seem to be a possibility. There isn't really any branching in the code you have shown that would lead to multiple processMonsterAI calls.