1

I am using Xcode 5.1 and Cocos2d v3.0 for reference. In this practice app I want the user to hold down on the screen. If the user holds down for one second the program should run "someMethod". Every second the user holds down on the screen the program should run "someMethod". So if the user holds down on the screen for a total of five second at each internal of one second "someMethod" should be called. If the user isn't holding down on the screen the time shouldn't run. I want this to work each timer the user holds down. So if the user holds down for one second, removes finger from screen, and then holds down again the timer should reset. Finally if the user holds down for 2.5 seconds "someMethod" should not be fired for a third time.

My problem is that my repeating timer isn't stopping if I lift my finger from the screen

Here is an example of my output

2014-12-03 19:47:45.987 Practice App[14739:f03] fire      
2014-12-03 19:47:46.986 Practice App[14739:f03] fire 
//after this point in time I am not holding down on the screen   
2014-12-03 19:47:47.986 Practice App[14739:f03] fire  
2014-12-03 19:47:48.986 Practice App[14739:f03] fire   
2014-12-03 19:47:49.986 Practice App[14739:f03] fire
@implementation GameScene
{
    dispatch_source_t dispatchSource;
}

- (instancetype)init
{

     if (self = [super init]){
    dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
                                                              dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));

    double interval = 1.0;
    dispatch_time_t startTime = dispatch_time(DISPATCH_TIME_NOW, 0);
    uint64_t intervalTime = (int64_t)(interval * NSEC_PER_SEC);
    dispatch_source_set_timer(dispatchSource, startTime, intervalTime, 0);

    dispatch_source_set_event_handler(dispatchSource, ^{
        [self someMethod];
    });


  ...
  }
  return self;
}

- (void)fixedUpdate:(CCTime)dt
{
    if(touchState == kTouchDown){//The player is touching the screen
        dispatch_resume(dispatchSource);
    }

    if (touchState == kTouchUp) {//The player isn't touching the screen
        dispatch_suspend(dispatchSource);
    }
}

- (void)someMethod{
    NSLog(@"fire");
}
Michael
  • 6,561
  • 5
  • 38
  • 55
Asdrubal
  • 2,421
  • 4
  • 29
  • 37
  • 3
    Do not use GCD to time anything in Cocos2D. Following explains the issue, though this answer is about Sprite Kit it equally applies to Cocos2D as well: http://stackoverflow.com/a/23978854/201863 Besides, if you use actions or the schedule methods in cocos2d it'll be a lot simpler to create timers. Just look at all the code to set the GCD timer up, with a CCNode's schedule methods that's a one-liner. – CodeSmile Dec 04 '14 at 08:10

1 Answers1

0

Use 5 long press gesture recognizers , one will fire at 1 sec, the second will fire at 2 secs, etc..., here goes the example of the first one, do that with the others and adjust the time:

UILongPressGestureRecognizer* recognizerOneSec = 
        [[UILongPressGestureRecognizer alloc] 
                initWithTarget:self
                        action:@selector(handleLongPressFrom:)];
recognizer.minimumPressDuration = 1.0; // seconds
[[[CCDirector sharedDirector] view] 
        addGestureRecognizer:recognizer];

That will fire after 1 seconds this:

-(void)handleLongPressFrom:(UILongPressGestureRecognizer*)recognizer
{
  //Perform here some logic to detect wich gesture will you handle
  //Example: if (recognizer is recognizerOneSec)

    if(recognizer.state == UIGestureRecognizerStateEnded)
    {
        CCLOG(@"Long press gesture recognized.");

        // Get the location of the touch in Cocos coordinates.
        CGPoint touchLocation = [recognizer locationInView:recognizer.view];

        //Do something with the touchLocation
    }
}

Later, do not forget of this, also you can try to remove and recreate gestures each time you need it:

-(void) onExit{
    NSArray *grs = [[[CCDirector sharedDirector] view] gestureRecognizers];

    for (UIGestureRecognizer *gesture in grs){
        if([gesture isKindOfClass:[UILongPressGestureRecognizer class]]){
            [[[CCDirector sharedDirector] view] removeGestureRecognizer:gesture];
        }
    }
}

The other approach that comes to my mind is to create a class, with a suspend variable and have a reference to the object so you can send a suspend message to it, but you will have to handle more things, like possible memory issues.

Juan Boero
  • 6,281
  • 1
  • 44
  • 62