Change Time Interval in Skaction.Waitforduration() as Game Goes On

Change time interval in SKAction.waitForDuration() as game goes on

You can use the recursive way to accomplish what you want (increment duration of wait parameter):

class GameScene:SKScene {

var wait:NSTimeInterval = 0

override func didMoveToView(view: SKView) {

NSLog("Start") //Using NSLog just to print the current time
recursive()

}

func recursive(){

let recursive = SKAction.sequence([

SKAction.waitForDuration(++wait),
//Do your stuff here, eg. run scale, move...
SKAction.runBlock({[unowned self] in NSLog("Block executed"); self.recursive()})
])

runAction(recursive, withKey: "aKey")
}
}

What you are currently experiencing, is that wait action is created, initialized and reused in an action sequence. You have to rebuild an action each time.

How to change wait for duration SKAction ran by an SKScene?

don't use an action in this case. They don't really work in a dynamic way. Once you set them, they're stuck. just use your update method.

I'll show you how I'm periodically launching missles:

first set two timers in your class

var missleTimer:NSTimeInterval = NSTimeInterval(2)
var missleInterval:NSTimeInterval = NSTimeInterval(2)

now in our update method we count down the time and spawn missles

// subtract time from our timer
self.missleTimer -= self.delta

// when our timer reaches zero
if self.missleTimer <= 0 {
// run your spawning code
self.launchMissle()
// reset timer
self.missleTimer = self.missleInterval
}

this is better than using an action in this case because I can set missleInterval anywhere in my code and the change will always be reflected.

SKAction.repeatActionForever only calculates random number on first call

So this is one way (and there are many ways) to the same thing.

What this code does is:

  • create an obstacle
  • move it from the left side, to the right side of the screen
  • remove the obstacle when off-screen
  • randomize obstacle's y coordinate on every obstacle creation

Just copy and paste to see how it works:

    import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

//MARK: - Sprite kit functionality
override func didMoveToView(view: SKView) {

startSpawning()
}

func startSpawning(){

let wait = SKAction.waitForDuration(1.5)
let block = SKAction.runBlock({[unowned self] in self.spawnObstacle()})
let sequence = SKAction.sequence([wait, block])

runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")
}

func spawnObstacle(){

// 1) create an obstacle
let obstacle = SKSpriteNode(color: .purpleColor(), size: CGSize(width: 50, height: frame.size.height/2.0))

// 2) Place it outside the screen, next to the right edge and randomize the y position each time
let lowerBound:CGFloat = -200 //Calcluate this to match your needs
let upperBound:CGFloat = 200 //Calcluate this to match your needs
let obstacleRandomY = randomBetweenNumbers(lowerBound, secondNum: upperBound)
obstacle.position = CGPoint(x: frame.maxX + obstacle.size.width, y: obstacleRandomY)

// 3) Add it to the scene
addChild(obstacle)

// 4) Move the obstacle from the right side, to the left side of a screen
let move = SKAction.moveToX(-obstacle.calculateAccumulatedFrame().width, duration: 3)

// 5) Remove the obstacle from the scene when off-screen
let moveAndRemove = SKAction.sequence([move, SKAction.removeFromParent()])


obstacle.runAction(moveAndRemove)
}

func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat{
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}

}

You can add another obstacle (upper pipe) and adjust a bit lowerBound and upperBound variables, so you will have an effect like in Flappy Birds...

swift spritekit increase frequency of node creation as time goes on

Create a spawnDuration property and key reference in your scene class.

class SomeClass: SKScene {

private var spawnDuration: NSTimeInterval = 2.0
private let spawnKey = "SpawnKey"

}

Than adjust your spawn code to use this spawn property and key. I slightly changed the syntax as well to make it more legible in my opinion.

func createSequentialEnemies(){
removeActionForKey(spawnKey) // remove previous action if running. This way you can adjust the spawn duration property and call this method again and it will cancel previous action.

let spawnAction = SKAction.runBlock(createEnemy)
let spawnDelay = SKAction.waitForDuration(spawnDuration)
let spawnSequence = SKAction.sequence([spawnAction, spawnDelay])
runAction(SKAction.repeatActionForever(spawnSequence), withKey: spawnKey) // run action with key so you can cancel it later
}

Than you have to add some logic of when you want to change the spawn duration property you created.

Time based could be a func like this you also call once in DidMoveToView

 func startDifficultyTimer() {

let difficultyTimerKey = "DifficultyTimerKey"

let action1 = SKAction.waitForDuration(30)
let action2 = SKAction.runBlock { [unowned self] in

guard self.spawnDuration > 0.2 else { // set a min limit
removeActionForKey(difficultyTimerKey) // if min duration has been reached than you might as well stop running this timer.
return
}

self.spawnDuration -= 0.5 // reduce by half a second
self.createSequentialEnemies() // spawn enemies again

}
let sequence = SKAction.sequence([action1, action2])
runAction(SKAction.repeatActionForever(sequence), withKey: difficultyTimerKey)
}

Hope this helps

How to gradually speed up falling nodes over time?

This is completely doable! You just need to add some variables.

If you want to change how fast they fall then you need to make a variable like

Var droptime:NSTimeInterval = 11.5

Then in your "dropdot()" method you need to do two things.

  1. At the beginning subtract or devide your droptime variable like...

    Droptime -= 1

  2. Then at the end when you generate the falling action make it

    Duration: droptime

Instead of what it was before.

If you want to make the generation time be shorter then you need to make a function that you can trigger each time you want to make your action that the scene runs (like you did in the viewdidload) and edit it so that it has variable wait and triggers itself. Also you will need to self trigger it once in your didMoveToView method.

    func controlMethod() {
waitdur -= 1
runAction(SKAction.repeatActionForever( SKAction.sequence([
SKAction.runBlock(generateDots),
SKAction.waitForDuration(waitdur),
SKAction.runBlock(controlMethod)
])))
}

Good luck!

So sorry for the formatting! I'm on mobile... Hopefully someone can fix it.

How to remove SKSpriteNodes after specific amount of time

You are running your sequence action on self instead of your fruit node.

Simply change your function like so :

func placeFruit() {

let fruit = SKSpriteNode(imageNamed: "apple")
fruit.position = CGPoint(x: frame.size.width * random(min: 0, max: 1), y: frame.size.height * random(min: 0, max: 1))

addChild(fruit)

fruit.runAction(
SKAction.sequence([
SKAction.waitForDuration(1.0),
SKAction.removeFromParent()
])
)

}

Run Two Action At The Same Time Inside ONE Sequence

You can group actions together to a sequence:

var actions = Array<SKAction>()

actions.append(SKAction.sequence([animationWait, animationScale]))
actions.append(SKAction.sequence([animationWait, animationAlpha]))

let group = SKAction.group(actions)

node.runAction(group)

When the action executes, the actions that comprise the group all start immediately and run in parallel. The duration of the group action is the longest duration among the collection of actions. If an action in the group has a duration less than the group’s duration, the action completes, then idles until the group completes the remaining actions. This matters most when creating a repeating action that repeats a group.

Timers in Sprite Kit

To achieve functionality similar to cocos scheduler you can use SKAction.

For example for the to achieve something like this

[self schedule:@selector(fireMethod:) interval:0.5];

using SKAction You would write this

SKAction *wait = [SKAction waitForDuration:0.5];
SKAction *performSelector = [SKAction performSelector:@selector(fireMethod:) onTarget:self];
SKAction *sequence = [SKAction sequence:@[performSelector, wait]];
SKAction *repeat = [SKAction repeatActionForever:sequence];
[self runAction:repeat];

It isn't best looking, and lacks some flexibility of CCScheduler, but it will pause upon backgrounding, pausing scene/view etc. + it is like playing with LEGOs :)



Related Topics



Leave a reply



Submit