简体   繁体   中英

Spritekit - Shifting between two functions with a timer

I'm making a game where I have two different functions that holds different types of enemies. I want to make a code that shifts between the two every 10 score. So from 0-10 "function 1" is active, and from 10-20 "function 2" is active, and then it changes back again and then back again and so on.

This is my two functions containing enemies:

var score = 0

func createPipes() {
    PipesHolder = SKNode()
    PipesHolder.name = "Pipe"


    let pipeLeft = SKSpriteNode(imageNamed: "PipeRight")
    pipeLeft.name = "Pipe"
    pipeLeft.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    pipeLeft.position = CGPoint(x: 300, y: 0)
    pipeLeft.physicsBody = SKPhysicsBody(rectangleOf: pipeLeft.size)
    pipeLeft.physicsBody?.categoryBitMask = ColliderType.Pipe
    pipeLeft.physicsBody?.affectedByGravity = false

    let pipeRight = SKSpriteNode(imageNamed: "PipeLeft")
    pipeRight.name = "Pipe"
    pipeRight.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    pipeRight.position = CGPoint(x: -300, y: 0)
    pipeRight.physicsBody = SKPhysicsBody(rectangleOf: pipeRight.size)
    pipeRight.physicsBody?.categoryBitMask = ColliderType.Pipe
    pipeRight.physicsBody?.affectedByGravity = false


    PipesHolder.zPosition = 2
    PipesHolder.xScale = 1.5
    PipesHolder.yScale = 0.8
    PipesHolder.position.x = CGFloat.randomBetweenNumbers(firstNum: 
    -220, secondNum: 220)
    PipesHolder.position.y = self.frame.height + 100

    PipesHolder.addChild(pipeLeft)
    PipesHolder.addChild(pipeRight)

    self.addChild(PipesHolder)

    let destination = self.frame.height * 2
    let move = SKAction.moveTo(y: -destination, duration: 10)
    let remove = SKAction.removeFromParent()

    let moveRight = SKAction.moveBy(x: 200, y: 0, duration: 1)

    let moveLeft = SKAction.moveBy(x: -200, y: 0, duration: 1)


    let moveBackAndForth = 
    SKAction.repeatForever(SKAction.sequence([moveRight, moveLeft]))


    PipesHolder.run(moveBackAndForth)

    PipesHolder.run(SKAction.sequence([move, remove]), withKey: 
    "MovePipes")

}

func spawnPipes() {
    let spawn = SKAction.run({ () -> Void in
        self.createPipes()
    })

    let delay = SKAction.wait(forDuration: 1)
    let sequence = SKAction.sequence([spawn, delay])

    self.run(SKAction.repeatForever(sequence), withKey: "SpawnPipes")
}

func createRedEnemies() {
    let enemyHolder = SKNode()
    enemyHolder.name = "Holder"

    let enemyLeft = SKSpriteNode(imageNamed: "Enemy")
    let enemyMiddle = SKSpriteNode(imageNamed: "Enemy")
    let enemyRight = SKSpriteNode(imageNamed: "Enemy")

    enemyLeft.name = "Enemy"
    enemyLeft.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    enemyLeft.position = CGPoint(x: 200, y: 0)
    enemyLeft.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 
    enemyLeft.size.width - 5, height: enemyLeft.size.height - 5))
    enemyLeft.physicsBody?.categoryBitMask = ColliderType.Enemy
    enemyLeft.physicsBody?.collisionBitMask = 0
    enemyLeft.physicsBody?.affectedByGravity = false


    enemyMiddle.name = "Enemy"
    enemyMiddle.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    enemyMiddle.position = CGPoint(x: 0, y: 0)
    enemyMiddle.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 
    enemyMiddle.size.width - 5, height: enemyMiddle.size.height - 5))
    enemyMiddle.physicsBody?.categoryBitMask = ColliderType.Enemy
    enemyLeft.physicsBody?.collisionBitMask = 0
    enemyMiddle.physicsBody?.affectedByGravity = false


    enemyRight.name = "Enemy"
    enemyRight.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    enemyRight.position = CGPoint(x: -200, y: 0)
    enemyRight.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 
    enemyRight.size.width - 5, height: enemyRight.size.height - 5))
    enemyRight.physicsBody?.categoryBitMask = ColliderType.Enemy
    enemyLeft.physicsBody?.collisionBitMask = 0
    enemyRight.physicsBody?.affectedByGravity = false


    enemyHolder.zPosition = 2

    enemyHolder.position.y = self.frame.height + 100
    enemyHolder.position.x = CGFloat.randomBetweenNumbers(firstNum: 
    -100, secondNum: 100)

    enemyHolder.addChild(enemyLeft)
    enemyHolder.addChild(enemyMiddle)
    enemyHolder.addChild(enemyRight)

    self.addChild(enemyHolder)

    let destination = self.frame.height * 4
    let move = SKAction.moveTo(y: -destination, duration: 9)
    let remove = SKAction.removeFromParent()

    enemyHolder.run(SKAction.sequence([move, remove]), withKey: 
    "MoveEnemies")

}

func spawnEnemies() {
    let spawn = SKAction.run({ () -> Void in
        self.createRedEnemies()
    })

    let delay = SKAction.wait(forDuration: 0.4)
    let sequence = SKAction.sequence([spawn, delay])

    self.run(SKAction.repeatForever(sequence), withKey: "SpawnEnemies")

}

Here is the code I have for the shifted functions that I add in the "didMove":

func shiftEnemies() {

    if score >= 0 && score <= 10 {
        spawnEnemies()
    } else if score >= 11 && score <= 20 {
        spawnPipes()
    } else if score >= 21 && score <= 30 {
        spawnEnemies()
    } else if score >= 31 && score <= 40 {
        spawnPipes()
    }

}

Two problems with the "shiftedEnemies()". The first one is obvious, I cant write a code for every 10 score. The second problem is that this code doesn't even work. "SpawnEnemies()" is the only function that is shown. "spawnPipes()" doesn't show, ever. Maybe problem number two will be solved when I fix problem number 1.

Thx guys!

the reason your SpawnEnemies function is the only function that is being called is because you put the function shiftEnemies in the didMove(toView:) method and didMove(toView:) only gets called one time when you present your scene

what i recommend is try calling the function shiftEnemies() in the part of code where the score is being added (most likely in your didBeginContact method)

So you want to start by calling spawnenemies and when the score goes past a multiple of 10, switch to calling spawnPipes and then back to spawnEnemies at the next multiple of 10 etc?

Simply have a bool called shouldSpawnEnemies:

var shouldSpawnEnemies = true  // Start by spawning enemies

(if you want to start by spawning pipes, initialise this to false ).

Initialise the score at which functions should switch:

var switchFunctionScore = 10

Put a property watcher on your score. When the score passes the 'switch' score, set the bool indicating which function to use to false . Then set the next score at which functions should be switched.

var score : int = 0 {
   didSet {
      if (score >= switchFunctionScore) && oldValue < switchFunctionScore) {
         shouldSpawnEnemies = !shouldSpawnEnemies
         switchFunctionScore += 10
      }
   }

Then, whenever you need to call one of these functions; just check the value of shouldSpawnEnemies :

if shouldSpawnenemies {
   spawnEnemies
} else {
   spawnPipes
}

I would avoid using Timer, Timer works outside of the SpriteKit time system, so for me to cheat in your game, I could constantly exit and return the app, and since Timer is based on real time and not game time, the time that is spent outside of the game will still be accounted for.

What you want to do is use SKAction wait(duration:) , 'sequence , 'run(_ block:) repeatForever and repeat(_:count)

To do this, you need to break it down into steps:

1st, we want to wait 1 second and fire function 1:

let wait1Sec = SKAction.wait(duration:1)
let function1 = SKAction.run({[weak self] in self?.function1()})
let seq1 = SKAction.sequence([wait1Sec,function1])

2nd, we want to create an action that repeats it 10 times:

let repeat1 = SKAction.repeat(seq1,count:10)

3rd, we want to do this again for function 2:

let function2 = SKAction.run({[weak self] in self?.function2()})
let seq2 = SKAction.sequence([wait1Sec,function2])
let repeat2 = SKAction.repeat(seq2,count:10)

Finally, we want to combine the 2 and run it indefinetely

let seqForever = SKAction.sequence([repeat1,repeat2])
let repeatForever = SKAction.repeatForever(seqForever)

Now that we have the action, we can attach it to the scene once

scene.run(repeatForever,withKey:"forever")

You now have a solution that will constantly fire a method 10 times in 10 seconds, then switch to the other function for 10 more times in 10 seconds, repeating forever.

override func didMove(to view:SKView)
{
    let wait1Sec = SKAction.wait(duration:1)
    let function1 = SKAction.run({[weak self] in self?.function1()})
    let seq1 = SKAction.sequence([wait1Sec,function1])
    let repeat1 = SKAction.repeat(seq1,count:10)

    let function2 = SKAction.run({[weak self] in self?.function2()})
    let seq2 = SKAction.sequence([wait1Sec,function2])
    let repeat2 = SKAction.repeat(seq2,count:10)

    let seqForever = SKAction.sequence([repeat1,repeat2])
    let repeatForever = SKAction.repeatForever(seqForever)
    scene.run(repeatForever,withKey:"forever")
}

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