Is there a way to stop touch interaction when animation sequence is running. Animation sequence is load from ccbi file.
CCBAnimationManager* animationManager = self.userObject;
[animationManager runAnimationsForSequenceNamed:#"Blink"];
This depends on what interaction do you want to stop.
If it is a CCLayer, then set layer.touchEnabled = NO; and it will stop receiving touches. If it is your custom UI component, then you have to manually remove the touch delegate from it and add it when the animation ends.
Don't forget that you can set animationManager.delegate = self to get a callback when the animation finishes, so you can enable the touches again.
Related
I have a Scene that contains a GamePlay layer and an HUDLayer which contains my pause menu. I was wondering if there was anyway to pause just one layer in a scene so that I can pause the GamePlay layer but still access and click inside the pause menu in my HUDLayer. I tried using
[[CCDirector sharedDirector] pause];
but that pauses everything and doesn't accept touches in my pause menu. If there is no way to pause a single layer, what is the best way to incorporate a pause menu into a game? Thanks.
P.S. I am using the most recent version of cocos2d which is cocos2d 2.0.
This tutorial should help.
But basically what you wanna do is unschedule your scene then on resume reschedule it.
Here is what I did in my HUD layer.
-(void)pause:(id)sender
{
if(paused)
{
[gamescene scheduleUpdate];
}
else {
[gamescene unscheduleUpdate];
}
paused =!paused;
}
You shouldn't need to "pause" the desired layer unless I'm missing something. Why can't you just disable touches on everything except the pause layer while the pause layer is showing? It seems that is the end result that you would like anyways?
I make a animation and make it runs it forever. And now I want to stop it after clicking a button. Then animation is rotating a image of a button from 0 to 360 degree.
I'd like to stop the animation but make the animation to finish the current cycle. For example, if the button is rotated at 200 degree, and I click the stop button, I want that the animation still runs to reach 360 degree and then stop.
The animation code is like below:
CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
anim2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
anim2.fromValue = [NSNumber numberWithFloat:0];
anim2.toValue = [NSNumber numberWithFloat:-((360*M_PI)/180)];
anim2.repeatCount = HUGE_VALF;
anim2.duration = 10;
[self.imgBtn.layer addAnimation:anim2 forKey:#"transform"];
Thanks!
While you can get the animation from the layer using animationForKey:, you cannot modify the animation that way. As the documentation explains it:
Discussion
Attempting to modify any properties of the returned object will result in undefined behavior.
What you instead have to do
You have to remove the infinite animation and add another animation that makes the final end animation.
Use the presentation layer to determine the current rotation of your layer.
Remove the infinite animation
Add a new animation from the value you got from the presentation layer to the end state.
How to get the value from the presentation layer.
During animation your model doesn't change (when using Core Animation). Instead what you see on screen is the layers presentation layer. You can get then read the current value from the presentation layer just as if it was any other layer. In your case you could get the rotation using [myLayer valueForKey:#"transform.rotation"];
Alternately, you can create a single animation with a completion method that triggers the animation again, in an infinite loop.
Have the completion routine check a flag before submitting a repeat.
If the flag is false, don't trigger the animation again.
Then have your button action simply set the repeat flag to false. The current animation will run to completion, and then it won't be repeated.
The user drags the game piece (the i-th image view) to its target location. The program counts, sees that all the items are in the correct places, announces "Game Over" and sets userInteractionEnabled to NO.
Great, except that if the user's finger is still down on the game piece, the user can drag the piece back out of the target area by accident. "Game Over" is showing but the piece is no longer in the correct place.
Is there a way to force a touchesEnded (not detect a touchesEnded) so that the contact with the game piece is (effectively) broken when the piece is in its final destination (i.e. so that the user can't accidentally pull it out of position)?
userInteractionEnabled = NO does not seem to take effect until the touch is released.
I'm not aware of a way to force touchesEnded.
Obviously one way to handle this is for your application to maintain state that indicates that the game is over and guard against moving any game pieces when in that state.
You might try beginIgnoringInteractionEvents, though I doubt this will do what you are looking for. I really think managing state in your application that ensures that you will do the right thing, not moving the piece once the end state has been reached, is the way to go.
From Apple's Event Handling Guide for iOS:
Turning off delivery of touch events for a period. An application can
call the UIApplication method beginIgnoringInteractionEvents and later
call the endIgnoringInteractionEvents method. The first method stops
the application from receiving touch events entirely; the second
method is called to resume the receipt of such events. You sometimes
want to turn off event delivery while your code is performing
animations.
I found this question after wanting to do a very similar action within my own application. I wanted the touchesEnded: method to be run immediately after clicking on the moving action (like a touchDown action method), but did not know how to achieve this. In the end this is what I did and it WORKED! :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
...
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self touchesEnded:touches withEvent:event];
});
}
This worked perfectly!
I have an NSWindow subclass (GameWindow) containing an NSOpenGLView subclass (GameView).
The app is windowed (does not go fullscreen).
An OpenGL animation in GameView is fired ~30 times a second by a timer.
For presentation reasons, the GameView animation MUST continue regardless of what else is happening in the app. The only time it should stop is in the case of a fatal error.
I need to present various "modal" Cocoa windows (e.g. choose new game, confirm quit, etc.) while the animation in GameWindow continues. Some of these could be sheets, but major ones need to appear as standalone windows (complete with WebViews).
MY QUESTION: how can I display these "dialog" windows such that my app timer continues to fire, my animation continues, but user input to the GameView in the GameWindow is blocked until the "dialog" window is dismissed by the user?
(I need to support Tiger + Leopard at this time).
Have you tried the regular sheet/dialog techniques? They should work fine for this situation. Timers are scheduled as part of the run loop, which doesn't stop when you have a modal sheet or window, so it should be able to continue on rendering in the background while events are blocked.
[NSApp beginSheet:sheetWindow modalForWindow:mainWindow modalDelegate:nil didEndSelector:NULL contextInfo:nil];
(Except fill in your own delegate and end selector if needed.)
If you want to keep the current modal windows (without moving to sheets), you can try scheduling the NSTimer yourself in something besides the default runloop mode (NSDefaultRunLoopMode), which hangs as soon as that runloop stops running.
I have some NSViews that I'm putting in one of two layouts depending on the size of my window.
I'm adjusting the layout when the relevant superview receives the resizeSubviewsWithOldSize method.
This works, but I'd like to animate the change. So naturally I tried calling the animator proxy when I set the new frames, but the animation won't run while the user is still dragging. If I release the mouse before the animation is scheduled to be done I can see the tail end of the animation, but nothing until then. I tried making sure kCATransactionDisableActions was set to NO, but that didn't help.
Is it possible to start a new animation and actually have it run during the resize?
I don't think you can do this easily because CA's animations are run via a timer and the timer won't fire during the runloop modes that are active while the user is dragging.
If you can control the runloop as the user is dragging, play around with the runloop modes. That'll make it work. I don't think you can change it on the CA side.
This really isn't an answer, but I would advise against animating anything while dragging to resize a window. The screen is already animating (from the window moving) - further animations are likely going to be visually confusing and extraneous.
CoreAnimation effects are best used to move from one known state to another - for example, when a preference window is resizing to accompany a new pane's contents, and you know both the old and new sizes, or when you are fading an object in or out (or both). Doing animation while the window is resizing is going to be visually confusing and make it harder for the user to focus on getting the size of the window where they want it to be.