views:

1237

answers:

3

I am creating a quiz game and I can't figure out the best way to implement UIButtons that disappear one by one at 3 second intervals. I can get the first UIButton to disappear after 3 seconds, but the subsequent UIButtons take considerably longer.

I believe the problem is that my code becomes more inefficient with each UIButton I make disappear. The following method is what I call with a repeating NSInterval to make each subsequent UIButton disappear:

-(void)hideButton { int buttonNum;

while(buttonNum != -1)
{
 buttonNum = rand() % 5;

 if(buttonNum != [quiz correctNumber])
 {
  if(buttonNum == 0 && [buttonOne isEnabled] == YES)
  {
   [UIView beginAnimations:@"buttonFades" context:nil];
   [UIView setAnimationDuration:0.5];
   [buttonOne setEnabled:NO];
   [buttonOne setAlpha:0.0];
   [UIView commitAnimations];
  }
  else if(buttonNum == 1 && [buttonTwo isEnabled] == YES)
  {
   [UIView beginAnimations:@"buttonFades" context:nil];
   [UIView setAnimationDuration:0.5];
   [buttonTwo setEnabled:NO];
   [buttonTwo setAlpha:0.0];
   [UIView commitAnimations];
  }
  else if(buttonNum == 2 && [buttonThree isEnabled] == YES)
  {
   [UIView beginAnimations:@"buttonFades" context:nil];
   [UIView setAnimationDuration:0.5];
   [buttonThree setEnabled:NO];
   [buttonThree setAlpha:0.0];
   [UIView commitAnimations];
  }
  else if(buttonNum == 3 && [buttonFour isEnabled] == YES)
  {
   [UIView beginAnimations:@"buttonFades" context:nil];
   [UIView setAnimationDuration:0.5];
   [buttonFour setEnabled:NO];
   [buttonFour setAlpha:0.0];
   [UIView commitAnimations];
  }
  else if(buttonNum == 4 && [buttonFive isEnabled] == YES)
  {
   [UIView beginAnimations:@"buttonFades" context:nil];
   [UIView setAnimationDuration:0.5];
   [buttonFive setEnabled:NO];
   [buttonFive setAlpha:0.0];
   [UIView commitAnimations];
  }

  buttonNum = -1;
 }
}

}

+3  A: 

When you have only, say, 2 buttons left, since you still generate a random number between 0 and 4, you only have a 20% chance of actually making one more button disappear -- 20% of the time you'll do nothing because the random number matches the correct one, and 60% of the time under those conditions you'll do nothing because it matches an already-disappeared button.

I suggest you keep an array initially populated with references the 4 buttons that may actually disappear (don't bother putting the correct-number one there as you'll never disappear it anyway). In your function, generate a random number that's between 0 and N-1 when you have N buttons left in that array, so you can disappear the appropriate button with effective and concise code -- then (if the button that disappeared was not the last one in the array) swap it with the last one and decrement N by one. Of course when N is 1 there's no need for the random number either.

Alex Martelli
This worked great. Thanks
+1  A: 

Good answer from Alex Martelli. Another possibility would be to replace the separate objects buttonOne, buttonTwo, etc. with a single array of buttons, button[5] and replace your big loop with this:

do {
   buttonNum = rand() % 5;
} while (buttonNum == [quiz correctNumber] || ![buttons[buttonNum] isEnabled]);

[buttons[buttonNum] setEnabled:NO]; // Doesn't need to be in animation block
[UIView beginAnimations:@"buttonFades" context:nil];
[UIView setAnimationDuration:0.5];
[buttons[buttonNum] setAlpha:0.0];
[UIView commitAnimations];

*** Dan, below: Something to randomize the order of the button hiding and make sure the correct answer was not hidden would still be needed, but otherwise that's a great solution too.

Amagrammer
+1  A: 

Another way of making the buttons disappear at set intervals is to use the

- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay

method. To use this, you would define a function to make a button disappear when it is called:

-(void)hideButton:(UIButton *)button{
button.enabled = NO;
[UIView beginAnimations:@"buttonFades" context:nil];
[UIView setAnimationDuration:0.5];
[button setAlpha:0.0];
[UIView commitAnimations];
}

Then you would spit out those delayed selectors in a loop like this:

for(int i=0; i<numButtons; i++){
    [self performSelector:@selector(mySelector:) withObject:buttons[i] afterDelay:3*i+3]
}
Dan Lorenc