Tomasz Szulc
Tomasz Szulc

Reputation: 4235

How to repeatedly perform an action when a button is continuously pressed in obj-c

I've got four simple methods, four buttons and one object.

- (IBAction)left:(id)sender{
    object.center = CGPointMake(object.center.x - 5, object.center.y);
}

- (IBAction)right:(id)sender{
    object.center = CGPointMake(object.center.x + 5, object.center.y);
}
- (IBAction)down:(id)sender{
    object.center = CGPointMake(object.center.x, object.center.y + 5);
}
- (IBAction)up:(id)sender{
    object.center = CGPointMake(object.center.x, object.center.y - 5);
}

When I press a button, the method is executed once. When the button is pressed continuously it's the same. What do I have to do so that when I press the button continuously my object keep moving to the left?

Upvotes: 0

Views: 2469

Answers (3)

user244343
user244343

Reputation:

As @Maudicus said, you probably need to do something with NSTimers to get a continuous button press triggering. The example I'm going to use is moving an object on screen (since you want to do that anyway). I've used graded moving because I have no idea whether you are writing a grid-based game and so need exactly 5 pixels of movement. Just cut out all of the stepSize code and set it to 5 if that's what you do.

  1. Write a timer callback function which checks whether a BOOL is set and if so keeps triggering itself:

    - (void)moveObjectLeft:(NSTimer *)timer
    {
        // check the total move offset and/or the X location of the object here
        // if the object can't be moved further left then invalidate the timer
        // you don't need to check whether the button is still being pressed
        //[timer invalidate];
        //return;
    
        // the object moves gradually faster as you hold the button down for longer
        NSNumber *moveOffset = (NSNumber *)[timer userInfo];
        NSUInteger stepSize = 1;
        if(moveOffset >= 40)
            stepSize = 10;
        else if(moveOffset >= 15)
            stepSize = 5;
        else if(moveOffset >= 5)
            stepSize = 2;
    
        // move the object
        object.center = CGPointMake(object.center.x - stepSize, object.center.y);
    
        // store the new total move offset for this press
        moveOffset += stepSize;
        [timer setUserInfo:moveOffset];
    }
    
  2. Create a timer property in the current classes .h:

    @property (nonatomic, retain) NSTimer *moveTimer;
    
  3. Synthesize it in your .m:

    @synthesize moveTimer;
    
  4. Create your timer object when the button is pressed. Either do this in touchesBegan:withEvent: and check it's a Touch Down event, or connect the Touch Down event in Interface Builder to an IBAction method.

    NSNumber *moveOffset = [NSNumber numberWithUnsignedInt:0];
    self.moveTimer =
        [NSTimer
         scheduledTimerWithTimeInterval:0.2
         target:self
         selector:@selector(moveObject:)
         userInfo:moveOffset
         repeats:YES];
    
  5. When the button is released (using one of the above methods again, touchesEnded:withEvent: for a Touch Up Inside or probably even a Touch Up Outside, or another IBAction on both of those events), invalidate the timer externally:

    [self.moveTimer invalidate];
    self.moveTimer = nil;
    

Upvotes: 1

Jesse Black
Jesse Black

Reputation: 7976

I think you need to schedule a timer and repeat a method that checks the button states.

// assume timer is set up to test button states, triggering controlLoop every x seconds

-(void)controlsLoop
{
    if (leftButton.state == UIControlStateSelected || leftButton.state == UIControlStateHighlighted)  {

    }
}

I have never done this before so have fun playing around with it. I usually achieve controls like you want in Cocos2d,

It might be better to implement these methods

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

to set which direction you want to move the object, and still have a timer triggering the actual movement.

Upvotes: 0

Almo
Almo

Reputation: 15861

When a button gives its mousedown event, start moving. When the button gives its mouseup event, stop moving.

Be careful; this can act funny if multiple buttons can be pressed at the same time.

Upvotes: 0

Related Questions