I’m making a top down tile based game (think old Pokemon and Zelda games on GameBoy). I’m having problems with the character moving smoothly. I think the problem is the delay between finishing an action and starting a new one.
Here’s what the code looks like:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CGPoint touchCoor = [self coordinateForTouch:touch];
// If the character was touched, open their dialogue
if (CGPointEqualToPoint(touchCoor, ebplayer.coordinate)) {
[[CCDirector sharedDirector] replaceScene:
[CCTransitionMoveInR transitionWithDuration:1.0 scene:[HelloWorldLayer scene]]];
}
else // otherwise, move the character
{
activeTouch = [self directionForPoint:[touch locationInView:[touch view]]];
[self movePlayer:nil inDirection:activeTouch];
}
return YES;
}
// given in screen dimension points
// is the base movement function for all movements
– (void)movePlayer:(NSString*)pid toPosition:(CGPoint)position{
CGPoint playerCoordinate = [self coordinateForPositionPoint:position];
// if we're not already moving, and we can move, then move
if(!isAnimating && [self coordinateIsOnMap:playerCoordinate] && [self isPassable:playerCoordinate]){
id doneAction = [CCCallFuncN actionWithTarget:self selector:@selector(finishedAnimating)];
id moveAction = [CCMoveTo actionWithDuration:WALK_DURATION position:position];
id animAction = [CCAnimate actionWithAnimation: [ebplayer animateDirection:activeTouch withDuration:WALK_DURATION]];
id walkAndMove = [CCSpawn actionOne:moveAction two:animAction];
id action = [CCSequence actions: walkAndMove, doneAction, nil];
isAnimating = YES;
[player runAction:action];
ebplayer.coordinate = playerCoordinate;
[self setViewpointCenter:position Animated:YES];
}
// if it's not passable, just run the animation
if(!isAnimating){
id doneAction = [CCCallFuncN actionWithTarget:self selector:@selector(finishedAnimating)];
id animAction = [CCAnimate actionWithAnimation: [ebplayer animateDirection:activeTouch withDuration:WALK_DURATION]];
id action = [CCSequence actions: animAction, doneAction, nil];
isAnimating = YES;
[player runAction: action];
}
}
Then when that action is finished, try and start it up again:
- (void)finishedAnimating{
isAnimating = NO;
[self movePlayer:nil inDirection:activeTouch];
}
You will always end up with a 1-frame delay when sequencing multiple CCMove* actions.
What happens is the following:
This one-frame delay is one of the main problems of sequencing move actions, and the reason why I wouldn’t recommend using move actions for gameplay purposes.
The alternative is to move objects manually in a scheduled update method by modifying their position. You can use the CCMove* action code as basis.