So in the game I'm building I want to repeat an action, but I want it to have an initial delay. So for example, the action would execute three seconds after the user started the game, but after it executes for the first time, there's no longer a three second delay. What can I do to solve this?
Thanks in advance!
You could use an SKAction to make a delay, then put it at the beginning of your sequence.
Apple gives some sample code on sequences:
SKAction *moveUp = [SKAction moveByX:0 y:100.0 duration:1.0];
SKAction *zoom = [SKAction scaleTo:2.0 duration:0.25];
SKAction *wait = [SKAction waitForDuration: 0.5];
SKAction *fadeAway = [SKAction fadeOutWithDuration:0.25];
SKAction *removeNode = [SKAction removeFromParent];
SKAction *sequence = [SKAction sequence:#[moveUp, zoom, wait, fadeAway, removeNode]];
[node runAction: sequence];
You can use SKAction waitForDuration to make a delay.
Related
I have used sequence of action and one of the action plays sound for me.
SKAction *wait = [SKAction waitForDuration:1];
NSString* completion_sound = self.gameData[#"level_data"][#"completion_sound"];
SKAction *playSound = [SKAction playSoundFileNamed:completion_sound waitForCompletion:NO];
SKAction *completion = [SKAction runBlock:^{
// do some code here.
}];
SKAction *sequence = [SKAction sequence:#[wait, playSound, completion]];
[self runAction:sequence];
But I want to detect a completion of sound. seems like sound is still playing while block is invoking.
It appears you are passing NO for the waitForCompletion: argument and it should be YES.
If YES, the duration of this action is the same as the length of the audio playback. If NO, the action is considered to have completed immediately.
So change to YES in this line of code...
SKAction *playSound = [SKAction playSoundFileNamed:completion_sound waitForCompletion:YES];
...and the playSound action duration will be the length of the sound, therefor the 'completion block' SKAction *completion will not be executed until the sound is finished.
Your sequence is wrong. The correct order should be:
SKAction *sequence = [SKAction sequence:#[playSound, wait, completion]];
I have an SKScene where I am adding an SKSpriteNode. I have subclassed SKSpriteNode class to create this node. In the subclass i am defining certain SKActions on the sprite. What i want is that when the SKAction sequence that runs on this sprite ends, i add a new sprite node to the scene. How is this possible. Following is my code:
code for sequence that i am running on skspritenode subclass (TEMissileNode) :-
SKAction *moveDown = [SKAction moveToY:self.position.y - 20 duration:0.2];
SKAction *animation = [SKAction animateWithTextures:textures timePerFrame:time/7];
SKAction *moveMissileProjectile = [SKAction moveTo:pointoffScreen duration: time];
SKAction *group = [SKAction group:#[animation, moveMissileProjectile]];
SKAction *sequence = [SKAction sequence : #[moveDown,group, [SKAction removeFromParent]]];
[self runAction:sequence];
From the main scene I am calling the method which executes these actions
TEMissileNode *missile = [TEMissileNode missileAtPoint: CGPointMake(copter.position.x + copter.size.width/2, copter.position.y - 20)
Type:TEMissileTypeA];
[self addChild:missile];
[missile moveTowardsPosition:position];
What i want is that after the completion of the method (moveTowardsPosition:position), I add another child sprite node to the scene but how to get a completion notification from the method.
There are two ways of going about calling code after the completion of an action.
Use the completion block after runAction.
[self runAction:sequence completion:^{
//Add relevant code here.
}];
Or, add another block to execute at the end of the sequence.
SKAction *actionBlock = [SKAction runBlock:^{
//Add relevant code here.
}];
SKAction *sequence = [SKAction sequence : #[moveDown,group, [SKAction removeFromParent], actionBlock]];
I am using following code to fire a missile.
SKAction *missileMoveAction = [SKAction moveTo:destination duration:1.0];
SKAction *moveMissileActionWithDone = [SKAction sequence:#[_missileShootSound, missileMoveAction]];
[_cannonMissile runAction:moveMissileActionWithDone];
This is working fine but as soon as i use
[_cannonMissile runAction:moveMissileActionWithDone withKey:#"Canon_Fired"];
Nothing happen the run action do not move the object to destination. What is the problem with using RunAction: WithKey:?
I have a runAction which is animating a SKSpriteNode. I have the node moving up and down in a repeatActionForever. I would like the node to slow down as the node is moving up and speed up as the node is moving down.
[node runAction:[SKAction repeatActionForever:
[SKAction sequence:#
[[SKAction speedTo:0.1 duration:0.5],
[SKAction moveToY:2 * node.size.height / 3 duration:0.5],
[SKAction speedTo:1 duration:0.5],
[SKAction moveToY:node.size.height / 2 duration:0.5],
[SKAction moveToY:node.size.height duration:1],
[SKAction moveToY:node.size.height / 2 duration:1]]]]];
When I add the line [SKAction speedTo:0 duration:0.5], the rest of the code is run at speed of 0 after the 0.5 seconds even though I added a second speedTo action which would increase the speed to 1.
The problem: How do I change the speed of a node as the node is moving rather than having a stagnant speed for each direction.
Thanks in advance.
Look up the various types of SKActionTimingMode and apply the ones as needed to your situation. This will remove the need for anything like [SKAction speedTo:0.1 duration:0.5].
https://developer.apple.com/library/mac/documentation/SpriteKit/Reference/SKAction_Ref/Reference/Reference.html#//apple_ref/c/tdef/SKActionTimingMode
You can use the SKActionTimingEaseOut for the action that makes the node move up and SKActionTimingEaseIn for the action that makes the node move down.
SKAction *actionMoveUp = [SKAction moveToY:2 * node.size.height / 3 duration:0.5];
actionMoveUp.timingMode = SKActionTimingEaseOut;
SKAction *actionMoveDown = [SKAction moveToY:node.size.height / 2 duration:0.5];
actionMoveDown.timingMode = SKActionTimingEaseIn;
SKAction *actionMoveUpHalf = [SKAction moveToY:node.size.height duration:1];
actionMoveUp.timingMode = SKActionTimingEaseOut;
[node runAction:[SKAction repeatActionForever:
[SKAction sequence:#
[actionMoveUp,
actionMoveDown,
actionMoveUpHalf,
actionMoveDown]]]];
I have a trouble trying to make one circle big and small using [SKAction scaleBy: duration:]
SKAction *scaleDown = [SKAction scaleBy:0.2 duration:1.8];
SKAction *scaleUp= [scaleDown reversedAction];
SKAction *fullScale = [SKAction sequence:#[scaleDown, scaleUp, scaleDown, scaleUp]];
[_circleChanging runAction:fullScale];
What I get is the circle becoming so small that disappears and then doesn't come back. It has to become small and then come back to his original size doing it 2 times.
Try:
SKAction *scaleDown = [SKAction scaleTo:0.2 duration:0.75];
SKAction *scaleUp= [SKAction scaleTo:1.0 duration:0.75];
SKAction *fullScale = [SKAction repeatActionForever:[SKAction sequence:#[scaleDown, scaleUp, scaleDown, scaleUp]]];
[_circleChanging runAction:fullScale];
Not all actions are reversible, and the reverse sometimes doesn't mean "go back to the original value".
If you check the documentation, the reverse action of scaleBy is actually scaling to -0.2 in your case. Just create a new scale action instead of reversing.
Also try making a copy of the actions for the 2nd use:
SKAction *fullScale = [SKAction sequence:
#[scaleDown, scaleUp, [scaleDown copy], [scaleUp copy]]];