SKAction.repeatActionForever 只在第一次调用时计算随机数

SKAction.repeatActionForever only calculates random number on first call

我想做到这一点,以便我的专栏在超时时生成一个新的 y 值,它被传送,以便它始终在不同的高度移动。出于某种原因,随机数调用仅在第一次调用,从那时起,操作使用相同的数字而不是调用新的数字。这是我的代码:

let slideAction2A = SKAction.moveByX(-colTravel, y: 0, duration: 5)
let teleportAction2A = SKAction.moveToX(colInitialPosCGFloat, duration: 0)
let newLocation = SKAction.moveToY(getFloat(), duration: 0)
let teleportActionGroup2A = SKAction.group([teleportAction2A,newLocation])
let col2ASequence = SKAction.sequence([slideAction2A,teleportActionGroup2A])
let runCol2A = SKAction.repeatActionForever(col2ASequence)
let col2ADelaySlide = SKAction.moveByX(0, y: 0, duration: 2.5)
let delayAndRun2A = SKAction.sequence([col2ADelaySlide,runCol2A])
column2A.runAction(delayAndRun2A)


func getFloat() -> CGFloat {
    var x: CGFloat
    x = CGFloat(arc4random_uniform(200))
    x += CGFloat(newScreenHeight)
    print(x)
    return x
}

完整代码在这里:

```

//
//  GameScene.swift
//
//

import SpriteKit
import CoreMotion

class GameScene: SKScene {
    let world = SKNode()
    let house = Player()
    let ground = Ground()
    var screenCenterY = CGFloat()
    let initialPlayerPosition = CGPoint(x: 150, y: 250)
    var playerProgress = CGFloat()
    let motionManager = CMMotionManager()
    var destX:CGFloat = 0.0
    var destY:CGFloat = 0.0
    var test = SKNode()
    let newScreenHeight: Int = 0
    let screenSize: CGRect = UIScreen.mainScreen().bounds
    var screenHeight : CGFloat = 0

    let colWidInt:Int = 0
    let colWidCG:CGFloat = 0
    let houseWid = 0
    //let newScreenHeight:Int = 0
    let colInitialPosInt:Int  = 0
    let colInitialPosCGFloat:CGFloat = 0
    let colTravel:CGFloat = 0

    var column2A = SKSpriteNode()

    override func didMoveToView(view: SKView) {
        print("yao 1")
        // Set a sky-blue background color:
        self.backgroundColor = UIColor(red: 0.4, green: 0.6, blue: 0.95, alpha: 1.0)

        // Add the world node as a child of the scene:
        self.addChild(world)

        // Store the vertical center of the screen:
        screenCenterY = self.size.height / 2
        house.spawn(world, position: CGPoint(x: 100, y: 100))


        let screenSize: CGRect = UIScreen.mainScreen().bounds
        let screenWidth = screenSize.width
        screenHeight = screenSize.height
        //screenWidthInt = Int(screenWidth)

        let colWidInt = 50
        let colWidCG:CGFloat = CGFloat(colWidInt)
        let houseWid = 50
        let newScreenHeight:Int = Int(screenHeight)
        let colInitialPosInt:Int  = Int(screenWidth)+colWidInt/2
        let colInitialPosCGFloat:CGFloat = CGFloat(colInitialPosInt)
        let colTravel:CGFloat = CGFloat(colInitialPosInt+colWidInt/2)

        // A bronze coin:

        let column1A = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: colWidCG, height: screenHeight))
        column1A.position = CGPoint(x: colInitialPosInt, y: newScreenHeight+35)
        self.addChild(column1A)



        let column1B = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: colWidCG, height: screenHeight))
        column1B.position = CGPoint(x: colInitialPosInt, y: -35)
        self.addChild(column1B)

        column2A = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: colWidCG, height: screenHeight))
        column2A.position = CGPoint(x: colInitialPosInt, y: newScreenHeight+35)
        self.addChild(column2A)

        let column2B = SKSpriteNode(color: UIColor.greenColor(), size: CGSize(width: colWidCG, height: screenHeight))
        column2B.position = CGPoint(x: colInitialPosInt, y: -35)
        self.addChild(column2B)

        let slideAction1A = SKAction.moveByX(-colTravel, y: 0, duration: 5)
        let teleportAction1A = SKAction.moveToX(colInitialPosCGFloat, duration: 0)
        let col1ASequence = SKAction.sequence([slideAction1A,teleportAction1A])
        let runCol1A = SKAction.repeatActionForever(col1ASequence)
        column1A.runAction(runCol1A)

        let slideAction1B = SKAction.moveByX(-colTravel, y: 0, duration: 5)
        let teleportAction1B = SKAction.moveToX(colInitialPosCGFloat, duration: 0)
        let col1BSequence = SKAction.sequence([slideAction1B,teleportAction1B])
        let runCol1B = SKAction.repeatActionForever(col1BSequence)
        column1B.runAction(runCol1B)

        let slideAction2A = SKAction.moveByX(-colTravel, y: 0, duration: 5)
        let teleportAction2A = SKAction.moveToX(colInitialPosCGFloat, duration: 0)
        let newLocation = SKAction.moveToY(getFloat(), duration: 0)
        let teleportActionGroup2A = SKAction.group([teleportAction2A,newLocation])
        let col2ASequence = SKAction.sequence([slideAction2A,teleportActionGroup2A])
        let runCol2A = SKAction.repeatActionForever(col2ASequence)
        let col2ADelaySlide = SKAction.moveByX(0, y: 0, duration: 2.5)
        let delayAndRun2A = SKAction.sequence([col2ADelaySlide,runCol2A])
        column2A.runAction(delayAndRun2A)

        let slideAction2B = SKAction.moveByX(-colTravel, y: 0, duration: 5)
        let teleportAction2B = SKAction.moveToX(colInitialPosCGFloat, duration: 0)
        let col2BSequence = SKAction.sequence([slideAction2B,teleportAction2B])
        let runCol2B = SKAction.repeatActionForever(col2BSequence)
        let col2BDelaySlide = SKAction.moveByX(0, y: 0, duration: 2.5)
        let delayAndRun2B = SKAction.sequence([col2BDelaySlide,runCol2B])
        column2B.runAction(delayAndRun2B)
        print("yao 4")


        self.motionManager.startAccelerometerUpdates()
        if motionManager.accelerometerAvailable == true {
            // 2
            motionManager.startAccelerometerUpdatesToQueue(NSOperationQueue.currentQueue()!, withHandler:{
                data, error in

                let currentX = self.house.position.x
                let currentY = self.house.position.y

                // 3
                if data!.acceleration.x < 0 {
                    self.destX = currentX + 2*CGFloat(data!.acceleration.x * 200)
                }

                else if data!.acceleration.x > 0 {
                    self.destX = currentX + 2*CGFloat(data!.acceleration.x * 200)
                }

                if data!.acceleration.y < 0 {
                    self.destY = currentY + CGFloat(data!.acceleration.y * 400)
                }

                else if data!.acceleration.y > 0 {
                    self.destY = currentY + CGFloat(data!.acceleration.y * 400)
                }

            })

        }

    }

    override func didSimulatePhysics() {

    }

    func getRand() -> CGFloat{
        var x: CGFloat
        x = CGFloat(arc4random_uniform(200))
        //print("x is: ",x)
        //x += CGFloat(screenHeight)
        //print("ScreenHeight is : ",screenHeight)
        //print("new x is: ",x)
        return x
    }

    func getFloat() -> CGFloat {
        var x: CGFloat = getRand()
        //x = CGFloat(arc4random_uniform(200))
        //print("x is: ",x)
        x += CGFloat(screenHeight)
        //print("ScreenHeight is : ",screenHeight)
        //print("new x is: ",x)
        return x
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    }

    override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {

    }

    override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {

    }

    override func update(currentTime: NSTimeInterval) {
        let actionX = SKAction.moveToX(destX, duration: 0.3)
        let actionY = SKAction.moveToY(destY, duration: 0.3)
        let actionGroup = SKAction.group([actionX,actionY])
        house.runAction(actionGroup)


    }
}

```

所以这是对同一件事的一种方式(并且有很多方式)。

这段代码的作用是:

  • 制造障碍
  • 将它从左侧移动到屏幕的右侧
  • 移除屏幕外的障碍物
  • 在每次创建障碍物时随机化障碍物的 y 坐标

只需复制粘贴即可查看效果:

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

}

你可以添加另一个障碍物(上管)并调整一点 lowerBound 和 upperBound 变量,这样你就会有像 Flappy Birds 中的效果...