简体   繁体   English

Spritekit-使用计时器在两个功能之间切换

[英]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. 我想编写一个每10分在两者之间转换的代码。 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. 因此,从0-10开始,“功能1”处于活动状态,从10-20开始,“功能2”处于活动状态,然后它又变回来,然后又变回来,依此类推。

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": 这是我在“ 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()". “ shiftedEnemies()”存在两个问题。 The first one is obvious, I cant write a code for every 10 score. 第一个很明显,我不能为每10分写一个代码。 The second problem is that this code doesn't even work. 第二个问题是该代码甚至不起作用。 "SpawnEnemies()" is the only function that is shown. “ SpawnEnemies()”是显示的唯一功能。 "spawnPipes()" doesn't show, ever. “ spawnPipes()”永远不会显示。 Maybe problem number two will be solved when I fix problem number 1. 当我解决问题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 SpawnEnemies函数是唯一被调用的函数的原因是因为您将函数shiftEnemies放在了didMove(toView:)方法中,并且在呈现场景时didMove(toView:)只被调用了一次

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) 我建议尝试在要添加分数的代码部分中调用函数shiftEnemies() (最有可能在您的didBeginContact方法中)

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? 因此,您想从调用spawnenemies开始,并且当分数超过10的倍数时,切换到调用spawnPipes ,然后在下一个10的倍数处返回spawnEnemiesspawnEnemies

Simply have a bool called shouldSpawnEnemies: 只需添加一个名为shouldSpawnEnemies的布尔值:

var shouldSpawnEnemies = true  // Start by spawning enemies

(if you want to start by spawning pipes, initialise this to false ). (如果要从产生管道开始,请将其初始化为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 . 当分数超过“切换”分数时,将指示要使用的功能的布尔值设置为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 : 只需检查shouldSpawnEnemies的值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. 我会避免使用Timer,Timer在SpriteKit时间系统之外运行,因此,为了让我在您的游戏中作弊,我可以不断退出并返回该应用程序,并且由于Timer基于实时而不是游戏时间,因此该时间就是在游戏之外花费的费用仍将被考虑在内。

What you want to do is use SKAction wait(duration:) , 'sequence , 'run(_ block:) repeatForever and repeat(_:count) 您想要做的是使用SKAction wait(duration:) ,'sequence , 'run(_ block:) repeatForeverrepeat(_:count)

To do this, you need to break it down into steps: 为此,您需要将其分解为以下步骤:

1st, we want to wait 1 second and fire function 1: 首先,我们要等待1秒并触发功能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: 第二,我们要创建一个重复10次的动作:

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

3rd, we want to do this again for function 2: 第三,我们要针对功能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 最后,我们要合并2并无限期运行

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. 您现在有了一个解决方案,它将在10秒内不断触发一种方法10次,然后在10秒内再切换至另一种功能10次,直到永远重复一次。

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")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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