title: Sprite Kit delay on runAction completion?
body: <p>I'm building a game with Sprite Kit that implements A* Pathfinding. I'm using a grid system (blocks) that the character uses to calculate the path, it works great. My problem is the animation.</p>
  
  <p>I'm using a NSMutableArray to hold the steps and removes a step each time the move has been completed (runAction completion). It works but the animation freezes for a microsecond between completion and the new move making it look "choppy", its not a smooth move...</p>
  
  <p>I've tried a lot of things and the only thing that works is to change the duration to about 1.5 seconds to move 32px (its going to be a sloooooow game ;) ). When I want the duration I need (0.7) the problem is there.</p>
  
  <p>I really hope someone can help me.</p>
  
  <p>Here is some code:</p>
  
  <pre><code>-(void)animateChar {
  
      self.currentStepAction = nil;
  
      if (self.pendingMove != nil) {
          tileMap *moveTarget = pendingMove;
          self.pendingMove = nil;
          self.shortestPath = nil;
          [self moveToward:moveTarget];
          return;
      }
  
      if (self.shortestPath == nil) {
          return;
      }
  
  
      // WE HAVE REACHED OUR BLOCK! CHECK IF ITS CLICKED OR STROLLING
      if ([self.shortestPath count] == 0) {
  
          self.shortestPath = nil;
          self.moving = FALSE;
          self.strolling = FALSE;
  
          if (self.minionBlock) {
              CGPoint diff = ccpSub(self.minionBlock.position, self.parentBlock.position);
              if (abs(diff.x) &gt; abs(diff.y)) {
                  if (diff.x &gt; 0) { [self runAnimation:_faceRight speed:0.3]; } else { [self runAnimation:_faceLeft speed:0.3]; }
              } else {
                  if (diff.y &gt; 0) { [self runAnimation:_faceUp speed:0.3]; } else { [self runAnimation:_faceDown speed:0.3]; }
              }
  
              // SET TIMER FOR REMOVING THE BLOCK. EVERY 0.5 SECONDS IT REMOVES X ENDURANCE.
              self.blockTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(pickBlock) userInfo:nil repeats:YES];
  
          } else {
  
              [self setMinionBusy:FALSE];
              [self runAnimation:_waiting speed:0.3];
              [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(selectRandBlockAndMove) userInfo:nil repeats:NO];
          }
  
          return;
      }
  
      ShortestPathStep *s = [self.shortestPath objectAtIndex:0];
  
      // CHECK HOLE ON NEXT DOWN
      tileMap *checkHole = [s.theBlock getNeighbor:1];
  
      if ([checkHole isBlockType] == 2) { // THERE IS A HOLE, WE CANT REACH!
  
          if ([_scene getRecentBlock] == self.minionBlock) { [_scene controlHud:1]; }
  
          [self removeBlockBar];
          [self.minionBlock setOccupied:FALSE];
          self.minionBlock = nil;
          self.currentStepAction = nil;
          self.pendingMove = nil;
          self.shortestPath = nil;
          [self runAnimation:_waiting speed:0.3];
          [self addBubble:1];
  
          if (!self.stuck) {
              [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(selectRandBlockAndMove) userInfo:nil repeats:NO];
          }
  
          return;
      }
  
      CGPoint futurePosition = s.theBlock.position;
      CGPoint currentPosition = self.parentBlock.position;
      CGPoint diff = ccpSub(futurePosition, currentPosition);
  
      if (abs(diff.x) &gt; abs(diff.y)) {
          if (diff.x &gt; 0) { [self runAnimation:_faceRight speed:0.2]; } else { [self runAnimation:_faceLeft speed:0.2]; }
       } else {
          if (diff.y &gt; 0) { [self runAnimation:_faceUp speed:0.2]; } else { [self runAnimation:_faceUp speed:0.2]; }
      }
  
      self.parentBlock = s.theBlock;
  
      currentStepAction = [SKAction moveTo:s.theBlock.position duration:1.2];
  
      [self runAction:currentStepAction completion:^{
          [self animateChar];
      }];
  
      [self.shortestPath removeObjectAtIndex:0];
  }
  </code></pre>