views:

486

answers:

4

I'm learning Cocoa/Objective-C/iPhone SDK, and as a simple project to apply what I've learned, I wanted to create a simple version of the Simon game of old. Four colored buttons, you're shown a sequence (Red, Green, Blue, Red, etc.) and you have to repeat the sequence back.

I believe I have most of it figured out, save one piece: showing the sequence to the user. Specifically, how to implement the delay between highlighting the button & setting it back to normal after 200ms.

If I sleep in the main run loop, the update doesn't happen properly (even if I explicitly call setNeedsDisplay). If I spawn off a new thread, things get complicated quickly as my class method needs to refer back to UI elements (instant variables).

Any advice?

A: 

Read the docs for the Core Animation framework.

NSResponder
A: 

"simon" is a very simple MIDI sequencer. therefore I would highly suggest looking into the CoreAudio Framework, in particular the real-time-clock functionality.

kent
+3  A: 

You can use the +setAnimationStartDate: method on UIView to set up some animations to do this. To ensure that no one presses your buttons during the animation, call -[UIApplication beginIgnoringInteractionEvents] at the start of your animations and -[UIApplication endIgnoringInteractionEvents] at the end.

A written-in-the-text-field example of what I’m talking about:

[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
button1.highlighted = YES;

[UIView beginAnimations:@"" context:nil];
[UIView setAnimationStartDate: CFAbsoluteTimeGetCurrent() + 0.2];
[UIView setAnimationsEnabled:NO];
button1.highlighted = NO;
[UIView commitAnimations];

[UIView beginAnimations:@"" context:nil];
[UIView setAnimationStartDate: CFAbsoluteTimeGetCurrent() + 0.25];
[UIView setAnimationsEnabled:NO];
button2.highlighted = YES;
[UIView commitAnimations];

// etc.

[[UIApplication sharedApplication] performSelector:@selector(endIgnoringInteractionEvents) withObject:nil afterDelay:yourTotalDelay];
Ben Stiglitz
Thanks Ben! My plan had been to disable the buttons while showing the sequence, but beginIgnoringInteractionEvents looks like a much better way to do so.I considered using NSTimers, but the challenge is the delay. I.e. show the red button highlighted, wait 200ms, change to normal, wait 50ms, show blue highlighed, wait 200ms, change to normal, wait 50s, etc.If I sleep the thread, the UI updates don't propagate (even with calling setNeedsDisplay).
Bill
Instead of a repeating timer you’ll then just want to schedule a non-repeating timer each time. You’ll find -performSelector:withObject:afterDelay: very useful for this.
Ben Stiglitz
Actually, I just realized that you can use the +setAnimationStartDate: method on UIView to set up some animations that do this all at once, and then use a single timer at the end to re-enable interaction. Much simpler.
Ben Stiglitz
I changed the answer to reflect my revised thinking.
Ben Stiglitz
I've been futzing with this for a bit (and reading up on the docs), but it doesn't seem to work. I have this: redButton.highlighted = YES; [UIView beginAnimations:@"" context:nil]; [UIView setAnimationStartDate:[NSDate dateWithTimeIntervalSinceNow:1]]; [UIView setAnimationsEnabled:NO]; redButton.highlighted = NO; [UIView commitAnimations]; [UIView beginAnimations:@"" context:nil]; [UIView setAnimationStartDate: [NSDate dateWithTimeIntervalSinceNow:2]]; [UIView setAnimationsEnabled:NO]; blueButton.highlighted = YES; [UIView commitAnimations];
Bill
Well, that's gross. I'll open a new question w/ the revised code block.
Bill