I have a CCB file with a timeline animation in it. I load the file like this.
CCSprite *spriteAnimation = (CCSprite*)[CCBReader load:#"MyGreatAnimation"];
spriteAnimation.paused = TRUE;
At some point later, I add it to the scene and run the animation
[MyScene addChild:spriteAnimation];
CCAnimationManager* animationManager = _deletionAnimaion.userObject;
[animationManager runAnimationsForSequenceNamed:#"Default Timeline"];
This is great. My animation runs. I then remove spriteAnimation from the scene until I need it again.
[spriteAnimation removeFromParent];
.
The problem
I can't figure out how to get the animation to run the next time I add it to the scene.
I've tried:
[animationManager jumpToSequenceNamed:#"Default Timeline" time:0];
And also..
[animationManager runAnimationsForSequenceNamed:#"Default Timeline"];
But the animation doesn't seem to run. If at this point I call:
spriteAnimation.userObject.runningSequenceName
to see the running sequence, it returns NULL.
.
My Question
How do I arbitrarily run a timeline animation repeatedly?
To be clear, I'm not asking about looping the animation. I want to start it from frame 1 whenever I need.
If you need it repeatedly, you shouldn't remove it from the scene:
[spriteAnimation removeFromParent];
Instead, just make the animation invisible for the time being:
spriteAnimation.visible = NO;
Later just make it visible again.
After all when you remove a node it is gone from the scene hierarchy unless you addChild: it back in which I can't see in your code above.
Related
A SpriteKit game presents MainMenuScene then LevelSelectionScene and finally the GamePlayScene. Once the game is over, in GamePlayScene, the user is transferred back to MainMenuScene like so:
MainMenuScene *newScene = [MainMenuScene sceneWithSize:self.view.bounds.size];
[self.view presentScene:newScene transition:[SKTransition fadeWithDuration:0.5]];
It takes me to the scene but the buttons, that worked previously, don't work anymore. I press them, they seem to do their little animation as if they're being pressed but they don't present me appropriate scenes they're supposed to.
I have a very specific bundle of code activated every time a scene is about to be left and I don't actually know if it influences this whole conundrum:
-(void)willMoveFromView:(SKView *)view
{
/* Remove anything stuck in memory. */
[self removeAllActions];
[self removeAllChildren];
[self removeFromParent];
[self.scene removeAllActions];
[self.scene removeAllChildren];
[self.scene removeFromParent];
//[self.scene.view removeFromSuperview]; <--TOTALLY DESTROYS ALLS SCENES IN THE GAME. Don't use it.
}
Has any had previously working scenes presented as partially working duds?
From what you said looks like the button is triggering the animation but not the action, still not much information to be sure how to exactly fix it, probably the creation of the actions of the button is working. Double check if the part of the code that creates the SKActions is actually running and active.
So I poked around and found out the culprit is in the class I used to create buttons. It's called AGSpriteButton and I highly recommend it (You can find it on github). It has built-in SELECTORS, ACTIONS and BLOCKS functionality offered by default that is very easy to tap into. I'm not sure as to why, but SELECTORS stopped functioning correctly. I just switched to ACTIONS calling my methods & everything works perfectly.
I have tried many times to implement a D-Pad for my new maze game, but am having trouble doing so. I am doing it in the style of 4 UIButtons and if you press one, it moves another image up, down, left or right. I have tried using the quartzcore and CAAnimation, but only know limited code.
I have the methods and the buttons declared, but cannot code a working one.
I was doing:
-(IBAction)Up:(id)sender{
CGPoint origin1 = self.Player.center;
CGPoint target1 = CGPointMake(self.Player.center.x, self.Player.center.y-124);
CABasicAnimation *bounce1 = [CABasicAnimation animationWithKeyPath:#"position.y"];
bounce1.duration = 0.1;
bounce1.fromValue = [NSNumber numberWithInt:origin1.y];
bounce1.toValue = [NSNumber numberWithInt:target1.y];
[self.Player.layer addAnimation:bounce1 forKey:#"position"];
}
The ghost moves down, but bops back up immediately. I've been stumped for hours and it may be glaring me in the face, but please understand my noobishness.
In Core Animation, there are two layer hierarchies: one of model layers and one of presentation layers. Presentation layers are what you see; model layers are what you often interact with in code. This separation is valuable because it lets you create implicit animation -- e.g. set the position of a layer, and it'll animate to the new spot. (But if you assign a value to position, you want that to be the value you read back immediately thereafter, even if the animation is still in progress.)
When you use addAnimation:forKey:, you're affecting the presentation, not the model. So, during the animation, you see the Player layer moving, but that layer is "really" still where you left it. As soon as the animation ends, it's removed from the layer, so the presentation matches the model again -- you see it at its original position.
If you want the model position to change as well, you need to change it separately:
self.player.layer.position = CGPointMake(self.player.layer.position.x, target1.y);
You can either update the model immediately after adding the animation (you'll see the change after the animation completes), or use a completion block to schedule it at the end of the animation. There are subtleties to consider for either approach.
Often, though, if you just want to animate a specific change like that, especially for the main layer of a UIView, it's simpler to use the implicit animation API on UIView:
[UIView animateWithDuration:0.1 animations: ^{
self.player.center = CGPointMake(self.player.center.x, target1.y);
}];
This will both update the model value and create and run an animation for moving from the current position to the target position.
BTW: It helps to follow Cocoa code style conventions: use initial caps only for class names or other type names, and lowercase for variable/property/method names.
I have a scene that is calling the next one using a transition like this:
SKTransition *transition = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:0.5];
SKView *skView = (SKView *)self.view;
SKScene * scene = [[GameOverScene alloc] initWithSize:self.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene transition:transition];
The elements that compose GameOverScene (buttons, images, etc.) are added on its init method.
The problem is that the transition is not seen. One scene immediately cuts to the other one.
I guess that transition happens before the next scene has a chance to build its elements.
I have tried to move the creation of the next scene to didMoveToView without success.
For test purposes I have tried to delay the presentScene line in times even bigger than 2 seconds. When I do that I barely see the end frames of the transition.
How do I do that? What is the correct way of building the next scene and doing a transition that works.
If the new scene is particular resource heavy, i.e., requires a lot of texture loading, that will delay any frame rendering. If the texture loading takes longer than your transition time, you will miss all of it because the first frame that will be displayed has been rendered after your transition is finished.
I ran into this as well, although I was better able to determine the root cause because I had a transition of 2 seconds of which only the last 0.5 seconds were shown.
How to fix this? Preload your textures. See Apple Docs.
+ (void)preloadTextures:(NSArray *)textures withCompletionHandler:(void (^)(void))completionHandler
I should emphasize the differences between SKSprite, SKTexture and your "image.png".
SKSprite draws itself based on its texture property (or background color), and size. You can use one SKTexture for many sprites. In turn, an image file ("image.png") can supply multiple SKTexture objects.
Important: you want to use textures from the array of SKTexture objects passed to the method above to actually benefit from the texture loading. This will require some form of texture management.
If your problem is indeed texture related, let me know if you need me to expand on the texture management. A related post (which may be a bit dry) can be found here: SO sktexture-preloading.
I wrote exactly the same code in my app to show the game over scene with one minor difference. My code is as follows:
- (void)showGameOverScene
{
SKTransition* reveal = [SKTransition doorsCloseVerticalWithDuration:0.5];
SKScene* gameOverScene = [[RSGameOverScene alloc] initWithSize:self.size];
[self.view presentScene:gameOverScene transition: reveal];
}
And it's been working like a charm. The only difference is that I am not calling:
scene.scaleMode = SKSceneScaleModeAspectFill;
In my RSGameOverScene I set up nodes in -(id)initWithSize:(CGSize)size, and again there is no problems. Everything just works.
I can't see a reason why this line could be a source of a problem but you might want to try commenting it out to see if it helps. However your code looks ok so the source of the problem can be somewhere else.
I'm making a platform game with SpriteKit, and I'm trying to use the method setValue:forKey:
inside of the touchesMoved:withEvent method because I have a mess: I need to remove an animation of type SKAction. I run this SKAction animation in touchesMoved:withEvent with an if, checking all the needed conditions. One of these conditions is this:
if(NO ==[[self childNodeWithName:#"hero"] hasActions])
{
//code to run animation
}
I check if it has no actions, because I don't want to create more animations than needed.
The animation runs forever while I touch the screen with my finger, and it will remove only if I remove my finger from the screen, in the touchesEnded:withEvent method
So until I'm touching the screen, the hero animation will loop forever. The problem I have is if I move my finger from the right side of the screen to the left side of the screen, the animation is still the same: the hero running to the right, even if the sprite is moving to the left, because the if check if there is actions, and don't create the new animation to the left, and of course don't remove the right animation.
I think I can fix it setting a key for the animation action, and removing it in the same method with an if and using the location of the finger. The problem is that I don't know how to use the removeActionForKey method. I've tried reading documentation but I didn't find it very clear. Can anyone post me some code example of how to use it?
You need to use runAction:withKey: method:
// if direction == right
[node removeActionForKey:#"left"];
SKAction *animationRight = [SKAction animateWithTextures:......];
[node runAction:animationRight withKey:#"right"];
...........
// if direction == left
[node removeActionForKey:#"right"];
SKAction *animationLeft = [SKAction animateWithTextures:......];
[node runAction:animationLeft withKey:#"left"];
I have a simple UIImageView (myimageview) loaded with an NSArray(animationArray) of images for animation (in my ViewController.m):
[self.myimageview setAnimationImages:self.animationArray];
[self.myimageview setAnimationDuration:[self durationTime]];
[self.myimageview setAnimationRepeatCount: 1];
[self.myimageview startAnimating];
I know where to use stopAnimating, etc.. However I have weird problem. When the screen locks then nothing happens to my animation. Anything works like a charm. It continue after I unlock the screen.
However when my app goes in to Background mode then the whole animation stops (my animations are 2-3 minutes long, thus it is not acceptable). I've searched a little and found this topic:
How to pause a UIImageView animation
Where it says to use this code:
UIView *viewBeingAnimated = //your view that is being animated
viewBeingAnimated.frame = [[viewBeingAnimated.layer presentationLayer] frame];
[viewBeingAnimated.layer removeAllAnimations];
//when user unpauses, create new animation from current position.
Now I'm trying to implement this to my code in AppDelegate.m
// in -(void)applicationDidEnterBackground:
self.viewController.myimageview.frame = [[self.myimageview.frenchPress.layer presentationLayer] frame];
However i got this issue within XCode (for the line above) and I can't further continue:
AppDelegate.m:40:47: Receiver type 'CALayer' for instance message is a forward declaration
I'm saving the time if I exit into the background to the value: self.currentDate (just for sidenote, in case we need it).
How can i pause and play the animation without interruptions?
In order to get access to all the messages and properties of CALayer, you have to include its corresponding framework header:
#import <QuartzCore/QuartzCore.h>
This will hopefully eliminate the warning.