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.
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...
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.
I really hope someone can help me.
Here is some 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) > abs(diff.y)) {
if (diff.x > 0) { [self runAnimation:_faceRight speed:0.3]; } else { [self runAnimation:_faceLeft speed:0.3]; }
} else {
if (diff.y > 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) > abs(diff.y)) {
if (diff.x > 0) { [self runAnimation:_faceRight speed:0.2]; } else { [self runAnimation:_faceLeft speed:0.2]; }
} else {
if (diff.y > 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];
}
You can try performing the completion as an animation sequence:
[self runAction:[SKAction sequence:@[currentStepAction,
[SKAction runBlock:^{ [self animateChar]; }]
]]];
Also this will not call animateChar
when the SKAction is aborted while animating.