简体   繁体   中英

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

In my SpriteKit project, I have a spawnEnemy method. I want this method to be called over and over again so that enemies continue to spawn throughout the game.

What I did to achieve this is to put the spawnEnemy method in an SKAction runBlock and have my SKScene run that action forever with a delay in between calls (to prevent overloading the app).

Below is a snippet of the relevant code:

var _spawnSpeedSeconds: Double = 2.0

func startSpawning()
{
   let waitForXSeconds = SKAction.waitForDuration(self._spawnSpeedSeconds)

   let spawn = SKAction.runBlock({ () -> Void in
            self.spawnEnemy()
        })      
   self.runAction(SKAction.repeatActionForever(SKAction.sequence([spawn, waitForXSeconds])), withKey: "spawnEnemy")
}

func spawnEnemy()
{
...
}

Now after a certain time (for example when the player gets 5 points or something), I decrease the _spawnSpeedSeconds to make the enemies spawn more in a shorter amount of time to increase difficulty.

The problem is, even if I decrease my _spawnSpeedSeconds variable, the spawn action's delay being ran by the SKScene is still the same.

The only way I can think of resolving this issue is to remove the action, and then re-add the action with a new delay/spawn rate. Is there a better way to approach this issue?

Thanks

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.

-(void)recursiveMethod
{
    if(shouldSpawnEnemy)
    {
        _spawnSpeedSeconds -= 0.01;
        SKAction *wait = [SKAction waitForDuration: 0.5];
        SKAction *action = [SKAction performSelector:@selector(recursiveMethod) onTarget:self];
        SKAction *sequence = [SKAction sequence:@[wait,action]];
        [self repeatActionForever:sequence];
    }
}

Remember to call the recursiveMethod when you want to start spawning enemies. Hope that helps.

Providing swift solution without the need for timers, using recursion with a circuit breaker flag:

class YourScene: SKScene {
    
    var gameOver: Bool = false

    func spawnEnemies() {
        let waitAction = SKAction.wait(forDuration: yourDynamicDurationHere)
        self.run(SKAction.sequence([SKAction.run(self.spawnEnemy), waitAction])) {
            if !gameOver {
                spawnEnemies()
            }
        }
    }
}

This solution leverages the completion handler of run method to recursively schedule another execution of the sequence. Since each individual SKSequence is created just before it is executed, we can pass in a different wait time for each iteration.

To stop the recursive loop, just set gameOver = true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM