Reputation: 367
I'm trying to make a cocos2D game in which every time the player touches the screen, the background scrolls to the left thus simulating moving forwards.
The "background" consists of 2 very long rectangular panels called pane1 and pane2 linked together in a chain. When the screen is touched, I use CCActionMoveTo to move both panes to the left, and when one pane is completely off the screen, I move it back around to the other side to create an infinite loop.
The problem is the background scrolling animation takes .2 seconds, and if the player just mashes the screen a lot, it messes up everything. And, sometimes these two panes experience different amounts of lag so that they desync.
How do I set a delay on a function so that it can only be called once per designated time period? In other words, I want to add a "cooldown" to the function that handles player touch.
This function is called every time the scene is touched:
- (void)playerMove {
CCActionMoveTo * actionMove1 = [CCActionEaseOut actionWithAction:
[CCActionMoveTo actionWithDuration:.2
position:ccp(pane1.position.x - 150, 0)]
rate: 1.5];
CCActionMoveTo * actionMove2 = [CCActionEaseOut actionWithAction:
[CCActionMoveTo actionWithDuration:.2
position:ccp(pane2.position.x - 150, 0)]
rate: 1.5];
CCActionCallFunc * actionCallGenerateTerrain = [CCActionCallFunc actionWithTarget: self selector:@selector(generateTerrain)];
counter++;
if(pane1InUse){
[pane1 runAction: [CCActionSequence actionWithArray:@[actionMove1, actionCallGenerateTerrain]]];
[pane2 runAction: actionMove2];
}
else
{
[pane1 runAction: actionMove1];
[pane2 runAction: [CCActionSequence actionWithArray:@[actionMove2, actionCallGenerateTerrain]]];
}
}
-(void) generateTerrain {
if (counter%8 == 0){
pane1InUse ^= YES;
CCLOG(@"%@", pane1InUse ? @"YES" : @"NO");
if (pane1InUse){
CCLOG(@"Generating Terrain 2 ...");
pane2.position = ccp(pane1.position.x+pane1.boundingBox.size.width, 0);
}
else{
CCLOG(@"Generating Terrain 1 ...");
pane1.position = ccp(pane2.position.x+pane2.boundingBox.size.width, 0);
}
}
}
Also you may have noticed I'm using this weird block of code because ideally I would like actionMove1 and actionMove2 to be executed simultaneously, and once they are both done, then execute actionCallGenerateTerrain, but I don't know how to implement that:
if(pane1InUse){
[pane1 runAction: [CCActionSequence actionWithArray:@[actionMove1, actionCallGenerateTerrain]]];
[pane2 runAction: actionMove2];
}
else
{
[pane1 runAction: actionMove1];
[pane2 runAction: [CCActionSequence actionWithArray:@[actionMove2, actionCallGenerateTerrain]]];
}
}
Upvotes: 0
Views: 217
Reputation: 9079
You probably want to put pane1 and pane2 in a ccNode , call it combinedPanes (this will make pane1 and pane2 always move in sync). Then perform a single action on combinedPane. Also add a boolean state property, call it moveEnabled;
id movePane = [CCActionMoveTo ... ]; // whatever you have for pane1 or pane2
id moveComplete = [CCActionBlock actionWithBlock:^{
[self generateTerrain];
self.moveEnabled = YES;
}];
self.moveEnabled = NO;
[movePane runAction:[CCActionSequence actions:movePane,moveComplete,nil]];
and use moveEnabled to allow/deny the touch processing that detected a touch and triggered this move code. During the move, this will drop touches and effectively block your hysterical user tapping like nuts.
-(void) playerMove {
if (self.moveEnabled){
//
// the rest of your logic
// ...
}
}
and in init (or if you detect this condition already, place it there).
self.moveEnabled = YES;
Upvotes: 1
Reputation: 1316
One simple way to prevent a function being called twice within a time period is to wrap it in an if statement like:
if ([[NSDate date] timeIntervalSinceDate:lastUpdated] > minDelay)
{
// call function here
lastUpdated = [NSDate date];
}
where lastUpdated
is initialized using [NSDate date]
and minDelay is the required minimum delay in seconds.
Upvotes: 0