【问题标题】:Why does the app lag a lot when calling functions为什么app调用函数时滞后很多
【发布时间】:2018-10-05 09:20:43
【问题描述】:

我正在构建一个游戏,它需要根据条件是否为真来调用一个函数(多个函数中的一个)。出于游戏目的,条件每 0.0001 秒检查一次变量,但函数每 4-6 秒调用一次。我只需要

每当我在设备上测试游戏时,我都会注意到应用在某些时候会出现延迟。我相信它何时调用函数但我不确定。

这是一个调用检查条件的函数的 SKAction:

let triangle = SKAction.sequence([SKAction.run(obstaclesFunc),SKAction.wait(forDuration: 0.0001)])

run(SKAction.repeatForever(triangle))

这是条件检查器:

  func obstaclesFunc() {
    GameScene.nextObstacle = Int(arc4random_uniform(6) + 1 )

    if(GameScene.first == true){
        GameScene.randomNum = 1     
    }

    if (GameScene.pass == true){
    number = GameScene.nextObstacle
        print(number)

     //Rectangle Call Function
    if(GameScene.randomNum == 1){

       sideRectangles()

      //More code at bottom 
    }

我注意到最大的延迟发生在调用这个函数时:

func sideRectangles() {

    let rectangle1 = SKSpriteNode(imageNamed: "rectangleWalls")
    let rectangle2 = SKSpriteNode(imageNamed: "rectangleWalls")
    let rectangle3 = SKSpriteNode(imageNamed: "rectangleWalls")

    let rectangleTexture = SKTexture(imageNamed: "rectangleWalls")

    //Physics World
    rectangle1.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle1.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_1
    rectangle1.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle1.physicsBody?.affectedByGravity = false
    rectangle1.physicsBody?.isDynamic = true
    rectangle1.physicsBody?.collisionBitMask = 0

    //Physics World
    rectangle2.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle2.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_2
    rectangle2.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle2.physicsBody?.affectedByGravity = false
    rectangle2.physicsBody?.isDynamic = true
    rectangle2.physicsBody?.collisionBitMask = 0

    //Physics World
    rectangle3.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle3.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_3
    rectangle3.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle3.physicsBody?.affectedByGravity = false
    rectangle3.physicsBody?.isDynamic = true
    rectangle3.physicsBody?.collisionBitMask = 0

    let moveDown = SKAction.moveTo(y: self.frame.minY - rectangle3.size.height / 2, duration: 2)
    let moveDown2 = SKAction.moveTo(y: self.frame.minY - rectangle3.size.height / 2, duration: 3)
    let moveDown3 = SKAction.moveTo(y: self.frame.minY - rectangle3.size.height / 2, duration: 4)

    let removeNode = SKAction.removeFromParent()

    rectangle1.position = CGPoint(x: self.frame.minX - rectangle3.size.height * 0.1, y: self.frame.maxY + rectangle3.size.width) //use 4.5 for the close one
    rectangle2.position = CGPoint(x: self.frame.minX - rectangle3.size.width / 40 , y: self.frame.maxY + rectangle3.size.height) //use 4.5 for the close one
    rectangle3.position = CGPoint(x: self.frame.midX - rectangle3.size.width / 1.55, y: self.frame.maxY + rectangle3.size.height * 1.8)

    rectangle1.run(SKAction.sequence([moveDown,removeNode]))
    rectangle2.run(SKAction.sequence([moveDown2,removeNode]))
    rectangle3.run(SKAction.sequence([moveDown3,removeNode]))

    //second set
    let rectangle5 = SKSpriteNode(imageNamed: "rectangleWalls")
    let rectangle6 = SKSpriteNode(imageNamed: "rectangleWalls")
    let rectangle7 = SKSpriteNode(imageNamed: "rectangleWalls")

    //Physics World
    rectangle5.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle5.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_5
    rectangle5.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle5.physicsBody?.affectedByGravity = false
    rectangle5.physicsBody?.isDynamic = true
    rectangle5.physicsBody?.collisionBitMask = 0

    //Physics World
    rectangle6.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle6.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_6
    rectangle6.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle6.physicsBody?.affectedByGravity = false
    rectangle6.physicsBody?.isDynamic = true
    rectangle6.physicsBody?.collisionBitMask = 0

    //Physics World
    rectangle7.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle7.physicsBody?.categoryBitMask = PhysicsNumbering.rectangle_7
    rectangle7.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle7.physicsBody?.affectedByGravity = false
    rectangle7.physicsBody?.isDynamic = true
    rectangle7.physicsBody?.collisionBitMask = 0

    rectangle5.zPosition = 0
    rectangle6.zPosition = 0
    rectangle7.zPosition = 0

    rectangle5.position = CGPoint(x: self.frame.maxX + rectangle3.size.height * 0.1, y: self.frame.maxY + rectangle3.size.width) //use 4.5 for the close one
    rectangle6.position = CGPoint(x: self.frame.maxX + rectangle3.size.width / 40 , y: self.frame.maxY + rectangle3.size.height) //use 4.5 for the close one
    rectangle7.position = CGPoint(x: self.frame.midX + rectangle3.size.width / 1.55, y: self.frame.maxY + rectangle3.size.height * 1.8)

    rectangle5.run(SKAction.sequence([moveDown,removeNode]))
    rectangle6.run(SKAction.sequence([moveDown2,removeNode]))
    rectangle7.run(SKAction.sequence([moveDown3,removeNode]))

    addChild(rectangle1)
    addChild(rectangle2)
    addChild(rectangle3)
    addChild(rectangle5)
    addChild(rectangle6)
    addChild(rectangle7)
}

有人可以帮我找出造成这种延迟的原因吗?我似乎无法弄清楚。提前谢谢你!

【问题讨论】:

  • 我真的不认为轮询变量是正确的方法。您可以使用 KVO 在值更改时创建通知,这意味着您正在限制操作。

标签: swift sprite-kit skspritenode skaction


【解决方案1】:

动态生成物理实体非常昂贵,这就是为什么您的游戏每次尝试这样做时都会滞后。

我建议您创建对象并将它们放入障碍物数组中,然后在需要重新创建它们时复制数组项。

你有太多代码要为每个对象重复,我试图通过为每个障碍重用大量代码来减少代码量。

仅供参考 SKAction.wait(forDuration: 0.0001) 与 0 相同,因此毫无意义

您的障碍函数中的代码包含不相关或未包含在您的问题中的代码,因此我省略了该功能,如果它对您的游戏不利,您必须弄清楚并将其放入 generateObstacles 函数中。

//variables needed in your scene
private var rectangles = [SKSpriteNode]()
private var moveDown: SKAction!
private var moveDown2: SKAction!
private var moveDown3: SKAction!
private var removeNode: SKAction!

//in your didMove func
//preload the obstacles into an array
createRectangles()

//in your startGame func
//this func call will start the generation of the obstacles
generateObstacles()

func createRectangles() {

    let rectangle1 = createRectangle(category: PhysicsNumbering.rectangle_1)
    rectangles.append(rectangle1)

    let rectangle2 = createRectangle(category: PhysicsNumbering.rectangle_2)
    rectangles.append(rectangle2)

    let rectangle3 = createRectangle(category: PhysicsNumbering.rectangle_3)
    rectangles.append(rectangle3)

    let rectangle5 = createRectangle(category: PhysicsNumbering.rectangle_5)
    rectangles.append(rectangle5)

    let rectangle6 = createRectangle(category: PhysicsNumbering.rectangle_6)
    rectangles.append(rectangle6)

    let rectangle7 = createRectangle(category: PhysicsNumbering.rectangle_7)
    rectangles.append(rectangle7)

    let width: CGFloat = rectangle3.size.width
    let height: CGFloat = rectangle3.size.height

    //position the rectangles afterward creating them since they appear to be relevant to each other
    rectangle1.position = CGPoint(x: frame.minX - height * 0.1, y: frame.maxY + width) //use 4.5 for the close one
    rectangle2.position = CGPoint(x: frame.minX - width / 40 , y: frame.maxY + height) //use 4.5 for the close one
    rectangle3.position = CGPoint(x: frame.midX - width / 1.55, y: frame.maxY + height * 1.8)
    rectangle5.position = CGPoint(x: frame.maxX + height * 0.1, y: frame.maxY + width) //use 4.5 for the close one
    rectangle6.position = CGPoint(x: frame.maxX + width / 40 , y: frame.maxY + height) //use 4.5 for the close one
    rectangle7.position = CGPoint(x: frame.midX + width / 1.55, y: frame.maxY + height * 1.8)

    //now create the actions so that they can be used again and again
    createActions(height: height / 2)
}

func createActions(height: CGFloat) {

    moveDown = SKAction.moveTo(y: frame.minY - height, duration: 2)
    moveDown2 = SKAction.moveTo(y: frame.minY - height, duration: 3)
    moveDown3 = SKAction.moveTo(y: frame.minY - height, duration: 4)
    removeNode = SKAction.removeFromParent()
}

func generateObstacles() {

    let randomWaitTime = Int(arc4random_uniform(6) + 1 )

    self.run(.wait(forDuration: randomWaitTime) {
        loadAndMoveRectangles()

        //now call the generate func again to get a diff random time to wait
        generateObstacles()
    }
}

func loadAndMoveRectangles() {

    let rectangle1 = rectangles[0].copy() as? SKSpriteNode
    addChild(rectangle1)

    let rectangle2 = rectangles[1].copy() as? SKSpriteNode
    addChild(rectangle2)

    let rectangle3 = rectangles[2].copy() as? SKSpriteNode
    addChild(rectangle3)

    let rectangle5 = rectangles[3].copy() as? SKSpriteNode
    addChild(rectangle5)

    let rectangle6 = rectangles[4].copy() as? SKSpriteNode
    addChild(rectangle6)

    let rectangle7 = rectangles[5].copy() as? SKSpriteNode
    addChild(rectangle7)

    rectangle1.run(.sequence([moveDown, removeNode]))
    rectangle2.run(.sequence([moveDown2, removeNode]))
    rectangle3.run(.sequence([moveDown3, removeNode]))

    rectangle5.run(.sequence([moveDown, removeNode]))
    rectangle6.run(.sequence([moveDown2, removeNode]))
    rectangle7.run(.sequence([moveDown3, removeNode]))
}

func createRectangle(category: UInt32) -> SKSpriteNode {

    let rectangle = SKSpriteNode(imageNamed: "rectangleWalls")
    rectangle.zPosition = 0

    rectangle.physicsBody = SKPhysicsBody(texture: rectangleTexture, size: CGSize(width: rectangle1.size.width - 20, height: rectangle1.size.height - 20))
    rectangle.physicsBody?.categoryBitMask = category
    rectangle.physicsBody?.contactTestBitMask = PhysicsNumbering.player
    rectangle.physicsBody?.affectedByGravity = false
    rectangle.physicsBody?.isDynamic = true
    rectangle.physicsBody?.collisionBitMask = 0

    return rectangle
}

【讨论】:

  • 我很确定等待 0.00001 与 0 不同,但是当我有机会时需要仔细检查。 0 只会在 1 个更新周期上运行,但 0.00001 会在 2 上运行
  • 嗯,很有趣。我假设这是因为最大帧速率可能是每秒 0.016 次触发的 60fps。因此,任何小于等于 0
  • 它不会应用经过的时间直到下一个更新周期,所以在第一个运行块经过的时间是 0, 0
  • 我也会对此进行测试,如果是这样,我很乐意从答案中删除我的评论。这不会影响我的回答,因为无论如何我都没有用它来控制时间
  • 不,我会尝试通过这个答案为您提供更多帮助,但我很难理解 OP 的进展情况
猜你喜欢
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 1970-01-01
  • 2016-02-08
相关资源
最近更新 更多