The function touchesMoved behaves differently in iPhone and simulator.
The repeating interval (refresh rate) of the function touchesMoved is much faster than simulator. Is there a way to deal with the difference?
Often people are finding this to be a problem because they are doing something intensive in the touchesMoved handler and when events arrive very frequently, it makes the interface appear to lag.
A relatively simple way to deal with this is: First of all, in the touchesMoved handler, store the touch position in a variable that represents the position of whatever is tracking the finger.
Return from the touchesMoved handler immediately. Create an NSTimer object and set your view controller as a delegate of it and have that do whatever re-drawing/view moving behaviour used to be in your touchesMoved handler. Thus, you get a near constant movement regardless of the time between touchesMoved events.
If you're really advanced you can use a custom NSRunLoop instead of using a timer, but that's more than I can explain here :) The general idea is: don't be doing everything in the touch event handlers.
Related
I have seen several posts (E.g. this one) on this but I still don't get it.
If I call the CCDirector pause method it sets the animation interval to 1/4 and the value isPaused_ to YES (see code below). In the CCDirector.m class the isPaused_ variable
doesn't seem to be used much apart of in the pause and resume methods.
I thus decided to call also the stopAnimation method but in some posts this is not mentioned:
[[CCDirector sharedDirector] stopAnimation]
It doesn't apparently stop accelerometer data and input data to be sent to the main scene. It kind of does make sense to me because the developer of the Game might want to allow the user to resume by shaking the iPhone or tapping a resume button. Is this the reason behind this choice?
Also, why is the animation interval set to 1/4 and why things even with this value don't move (apart of my player entity that moves using accelerometer input)?
Thanks a lot!
-(void) pause
{
if( isPaused_ )
return;
oldAnimationInterval_ = animationInterval_;
// when paused, don't consume CPU
[self setAnimationInterval:1/4.0];
[self willChangeValueForKey:#"isPaused"];
isPaused_ = YES;
[self didChangeValueForKey:#"isPaused"];
}
Pausing CCDirector reduces framerate to 4 fps in order to conserve both battery and CPU cycles. The latter is necessary if you use UIKit views, in some cases it is necessary to pause the director in order for UIKit animations to animate smoothly.
What pausing the director also does is that it stops updating all nodes. Specifically the CCScheduler doesn't fire any scheduled selectors or update methods. It also prevents touches from being passed on to nodes, because they are relayed through the CCTouchDispatcher which is also paused when the director is paused.
But as you noticed, the accelerometer isn't paused. That's because cocos2d doesn't provide a wrapper for UIAccelerometer and therefore you get these notifications directly from iOS, ignoring the pause status of the director. If you then change the position of nodes inside the didAccelerate method or another method called directly from it, that node will change its position despite director being paused.
This is but one reason why director's pause isn't really suitable for a "pause game" feature. Another issue is that pausing simply would prevent any pause menu built with cocos2d features would also be paused, which kind of defies the purpose.
Then startAnimation and stopAnimation are simply extreme measures that prevent cocos2d from updating the screen altogether. This is normally only used in situations where either the cocos2d view is removed temporarily from the view hierarchy, or hidden, or some UIKit view is going fullscreen. In that sense stopAnimation is like a suspend feature.
I'm wondering if iOS allows one to do the following:
I have a puzzle game and I've been working on saving data when the user returns to the home screen. To do this, using NSNotificationCenter, I had one of my game classes to observe [UIApplication sharedApplication]'s ApplicationWillResignActive method so when that happens I save my game state. But if the user decides to exit while animations are going on, the game will save a midState where the model values are still changing and that will often cause crashes. My question is if it is possible to somehow delay the saving process (even though it is on the background) until the animations are complete (or some variable equals 1)?
My first idea is to create scheduled event with NSTimer to try to save until everything is set. Any ideas would be appreciated. Thank you
You can use performSelector:withObject:afterDelay:
// Call doSomething after a 1 second delay
[self performSelector:#selector(doSomething) withObject:nil afterDelay:1.0f];
Rather than trying to delay the saving, especially in ApplicationWillResignActive, you should look into how to stop the animation and record the expected final values of the animation. Depending on the method of animation (UIView static methods, block based, 3rd party) there is usually a way to stop them, and since you define what the animation does you should already know the final state.
In the case of block based animations:
How to cancel UIViews block-based animation?
There's probably something really obvious I'm missing, but no matter how I trawl the documentation & the blogs, I can't find a way to make a button report whether or not it is being touched, regardless of whether the touch moves, etc. I have an up & down button, & I need to call the relevant method whenever there is a finger on it.
Many thanks,
Franklyn Weber
Add an action to the touch down event and you are being touched up until any of the touch up events are fired. If you need to be continuously called, use an NSTimer. Start the timer on touch down and then check to see if you are still down in the timer handler. If you are, do your thing and set another timer.
The best method I can think of is to start a timer in the touchesBegan event method. If the timer expires before the touchesEnded event arrives, then you know the user is holding down on the screen. If the touchesMoved event is called, then simply reset the timer so as to only detect holding down without movement.
Is there any functionality built into the iOS SDK to handle exactly this? Or any better, simpler, faster methods anyone can think of?
Thanks in advance for your help!
Try using the UILongPressGestureRecognizer.
UILongPressGestureRecognizer* gr = [[UILongPressGestureRecognizer alloc]
initWithTarget:theTarget
action:#selector(someAction:)];
// change options of gr if you like.
// default: tolerate movement up to 4 px, fire the event after 0.4 secs.
[theView addGestureRecognizer:gr];
[gr release];
When the user long-pressed [theTarget someAction:gr] will be called.
I don't know of another way to test for no movement; I think how you are doing it would be simple enough.
You will most likely not be able to use touchesMoved to reset the timer since it is very, very sensitive and you move your finger without even being able to see it with the naked eye (feel free to test this with NSLogs to see what I mean).
You may want to implement some type of threshold difference value for how much the touchesMoved value has changed from the original value before you reset the timer.
My app is playing a pretty complex animation. It's like a flipbook.
What I do is: I have a huge loop with selectors, and after every delayed call the next one is called.
Now someone calls the user and the device suddenly shows up this fat green status bar and maybe some big pick-up-the-phone-call overlay. Or: The alarm clock rings, and a big alert sheet appears in front of just about everything.
It would be great to just pause the whole animation in case of ANY interruption. Probably I've also missed like 5 more possible interruptions.
How are you doing that? How do you get notified for all interruptions and then call one single -stopEverything method?
Whenever the app becomes inactive, the UIApplicationWillResignActiveNotification local notification will be posted. In the opposite suituation, the UIApplicationDidBecomeActiveNotification notification will be posted.
Your animation logic can listen to this and respond appropriately. There is an +setAnimationsEnabled: method to kill all current and future animations, but there isn't a documented "global pause" method.
Depending on the animation, you might be better off using CoreAnimation directly by using a single CAKeyframeAnimation on the view's -layer rather than having one animation's completion selector start another animation.