Double blow detection in iPhone - iphone

I have seen many tutorials over internet to detect blow in iPhone but my app's requirement is that I need to detect single blow and double blow both so that if user blow single time it can perform action a and if the user blow two times together then to perform action b.
Any way to do this?
Thanks all,

Surely if you know how to detect a single blow, you could just have a timer with a threshold & see if another blow happens within that time? Something like -
-(void)userDidBlow {
if (hasBlownOnce) {
hasBlownOnce = NO;
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(singleBlowTimedOut) object:nil];
// do double-blow stuff
} else {
hasBlownOnce = YES;
[self performSelector:#selector(singleBlowTimedOut) withObject:nil afterDelay:kDoubleBlowTime];
}
}
-(void)singleBlowTimedOut {
hasBlownOnce = NO;
// do single-blow stuff
}
I haven't tested it, but it looks ok :)

Related

referencing a method in an if statement

How can I check if a method is or isn't running, in an if statement? For example-
if ([(UIButton *)sender isEqual:blueButton] && **showBlueText method is running** )
{
Keep playing.
}
else if ([(UIButton *)sender isEqual:blueButton] && **showBlueText method is NOT running** )
{
Game over.
}
-(void)showBlueText
{
blueText.hidden = NO;
[self performSelector:#selector(hideText) withObject:nil afterDelay:textDelay];
[self performSelector:#selector(showGreenText) withObject:nil afterDelay:hideDelay];
}
Just to clarify, 'showBlueText' is a part of its own loop that runs independently of this if statement. I'm just trying to check if showBlueText is currently running.
You want to record state here. Make a new instance variable in this class.
// new iVar
BOOL textIsShowing;
// method
-(void)showBlueText {
textIsShowing = YES;
blueText.hidden = NO;
[self performSelector:#selector(hideText) withObject:nil afterDelay:textDelay];
}
// method
- (void)hideText {
textIsShowing = NO;
blueText.hidden = YES;
}
// button press
- (void)buttonPressed {
if (textIsShowing) {
NSLog(#"Keep playing");
} else {
NSLog(#"Game over");
}
}
Between the time you call this method, and the animation stops, don't think of it as "running". It schedules code to be executed later. Instead you want to be notified after it has finally run.
And in this case it's easiest to keep track of the state yourself. Use a new variable to track the state of things, and change it's value when that state changes.
But can't you just check if (blueText.hidden)? Yeah, you could. But it's bad practice to store state about your program in some obscure property of a random unimportant object.
Examine your state to figure out what you show. Don't examine what's showing to figure out your state.
I suggest replace Keep playing or Game over or Doing stuff with NSLog() statements. I always use it to keep a track of the changes in program if I am getting unexpected result.
So your statement may look like:
NSLog(#"Keep playing");
I hope this helps.
Just check if the text is hidden. No need to store parallel state in your controller - all that does is create the possibility that they'll be out of sync.

Detecting when MapView tiles are displayed

Since - (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView is not called when the tiles are loaded from cache, is there a way to know when all the tiles have been loaded (either from cache or from the mapping servers) and displayed?
Is there any delegation that intimates that tiles have been loaded ?
Here is some source code I wrote: https://github.com/jonathanlking/mapViewTest
Why don't you think about the problem like this;
When the map view will change, mapView:regionDidChangeAnimated: will be called.
From there mapViewWillStartLoadingMap: will be called.
Next mapViewDidFailLoadingMap:withError: or mapViewDidFinishLoadingMap: will be called if the tiles have been fetched from the server.
However if neither are called, you can assume the tiles are being loaded from the cache.
As mentioned, mapViewDidFinishLoadingMap is sometimes not called at all, especially if the map tiles are already cached, and sometimes it is called multiple times.
I notice that when it is called multiple times at the last call all of the tiles are rendered. So I think you can get this to work if you set up a 2 second timer after the map starts changing. Disable interactions so that the map does not continue to change, and enable user interactions when the timer goes off.
If mapViewDidFinishLoadingMap gets called reset the timer again for 2 seconds into the future. When the timer finally goes off, you should have a fully rendered map.
You will want to consider the other callbacks such as mapViewDidFailLoadingMap. Also test this on a noisy connection, since 2 seconds may not be long enough if it takes a long time to fetch the tiles.
- (void)restartTimer
{
[self.finishLoadingTimer invalidate];
self.finishLoadingTimer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:#selector(mapLoadingIsFinished)
userInfo:nil
repeats:NO];
}
- (void)mapLoadingIsFinished
{
self.finishLoadingTimer = nil;
self.mapChanging = NO;
self.view.userInteractionEnabled = YES;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView
{
if (self.mapChanging) {
[self restartTimer];
}
}
- (void)startLookingForMapChange
{
assert(self.mapChanging == NO);
if (self.mapChanging == NO) {
self.mapChanging = YES;
assert(self.finishLoadingTimer == nil);
self.view.userInteractionEnabled = NO;
[self restartTimer];
}
}

How can I stop views on screen from multiplying? (touchesBegan,touchesMoved,touchesEnded)

I am new to Objective C and I am trying to make a basic puzzle game. I am using multiple UIImage objects, some labels and a button. It consists in moving the pieces to its correct position. If the user fails to put a piece in a place, the piece goes back to its original location.
That part works perfectly, the problem begins once I 'remove' that view and continue on the other screens. Whenever I click ANYWHERE on screen the views get multiplied endlessly. Why is that happening?
What should I do?, I am so desperate, I've tried almost everything including ignoring touches, blocking touches, etc. And this only creates more trouble.
I have already tried setting using interactions to no, ignoring interaction events, autoreleasing the view, and I have not reached a solution.
Any help will be very much appreciated. Greetings!
---> I tried posting an image but given that I am a newbie I wasn't able to, however I can send the image to anyone if needed to show you the weird effect I get.
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self touchesCancelled:touches withEvent:event];
}
-(IBAction) navigationConversation: (id)sender{
//[self.view.superview setUserInteractionEnabled:NO];
//[[UIApplication sharedApplication] endIgnoringInteractionEvents];
if (nextButton.hidden == NO) {
conversation *navigationConversationController=[[conversation alloc] initWithNibName:#"conversation" bundle:nil];
[self.view addSubview:navigationConversationController.view];
if (self.view.superview == nil)
[navigationConversationController autorelease];
}
return;
}
Thank God, the problem is solved now. This are the changes I made, and this corrected the mistake. :)
-(IBAction) navigationConversation: (id)sender{
if (nextButton.hidden == NO) {
//I disabled the interactions with the puzzle view in here, thus eliminating the problem
[self.view.superview setUserInteractionEnabled:NO];
conversation *navigationConversationController=[[conversation alloc] initWithNibName:#"conversation" bundle:nil];
[self.view addSubview:navigationConversationController.view];
if (self.view.superview == nil)
[navigationConversationController autorelease];
}
return;
}
Thanks to everyone who looked! and wanted to help! I hope this works for other people having the same issues.

Using Cocos2D scheduleUpdate to delay loading

I have an algorithm that takes a few seconds to load some stuff, and I want to first set the string on a label to say "loading" before the actual loading begins. This is all within the same layer, this is not switching between scenes.
I thought I could simply do this:
-(void)startLoading{
[self unscheduleAllSelectors];//just in case the update is already scheduled
[self.loadingLabel setString:#"Loading...."];
[self scheduleUpdate];
}
Then, I have this:
-(void)update:(ccTime)delta{
[self unscheduleUpdate];
[self beginLoading];//another method that loads all the stuff
}
My understanding is that my method beginLoading should not run until the next frame. Thus my label should get updated correctly. However this is not happening. There is a slight freeze while all my assets get loaded and my label never gets updated before the loading begins.
Am I missing a step?
Nope ure not missing anything. I stopped fighting this and now use this kind of 'delayed' task catapult. It should make certain you will get a draw in the transition from the first to the second tick:
-(void) startLoading{
_loadTicker=0; // an NSUInteger iVar declared in the .h
[self schedule:#selector(tickOffLoading:)];
}
-(void) tickOffLoading:(ccTime) dt{
_loadTicker++;
if(_loadTicker==1) {
[self.loadingLabel setString:#"Loading...."];
} else {
[self unschedule:#selector(tickOffLoading:)];
[self beginLoading];
}
}

How can I disable the touch detection?

How can I disable the touch detection within the action that running, because I don't want the character flying in the sky like a superman if the player clicking and clicking within the action, the character will never land if they keep clicking.
I found the method "isDone", is that relate to this method??
player click -> action(cannot click within the action) -> action finish -> click again.....
that's what i want~
This is the best answer to your question:
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
Disable user interactions in your view till the action completes and then enable it again.
To disable touch
[self.view setUserInteractionEnabled:NO];
To enable touch
[self.view setUserInteractionEnabled:YES];
Please try and be a bit more concise of what you want the next time.
Swift 3.0
self.view.isUserInteractionEnabled = false
In Swift 2.2
self.view.userInteractionEnabled = false
Just gonna make a wild assumption that you're talking about the specific Action class in Cocos2D. If that's true, then you should know that every Action has an "isDone" Bool you can check to see if it's done. Let me know if that's what you're asking and I'll post an example, but there's a huge chance you could be talking about something else because your wording is so confusing ;)
You could always put a transparent UIView over top of the area you want to "disable" tap input for, have it listen for taps, and have it ignore them. Remove the UIView (or hide it) when you want input to be listened to again.
Why don't you use some kind of (simple version) boolean to remember i.e. isInAction = true and after the action finished isInAction = false...
So when someone clicks, u use something like
if (!isInAction) {
isInAction=true;
try {
doYourAction;
} catch {
...
} finally {
isInAction=false;
}
}
// The Code is some kind of pseudocode, because I haven't yet programmed for the IPhone, just to visualize what I mean.
Perhaps I didn't understand your question but is this what you're looking for?
- (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[Superman Fly];
self.isTouchEnabled = NO;
}
- (void)SupermanLanded{
self.isTouchEnabled = YES;
}