-1

I am building a game that requires a function (out of several) to be called depending if a condition is true or not. The condition checks the variable every 0.0001 seconds for game purposes, but the functions are called every 4-6 seconds. I just needed the

Whenever I was testing the game on a device, I noticed that the app lags at certain times. I believe its when a function is called but I'm not sure.

This is an SKAction that calls the function that checks the condition:

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

run(SKAction.repeatForever(triangle))

This is the condition checker:

  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 
    }

I noticed that the biggest lag occurs when this function is called:

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

Can someone please help me find out what is causing this lag? I cannot seem to figure it out. Thank You in advance!

sangony
  • 11,636
  • 4
  • 39
  • 55
Alex Merlin
  • 341
  • 1
  • 3
  • 12
  • I really don't think polling a variable is the right approach. You could use KVO to create a notification when the value changes, meaning you are limiting operations. – stevenpcurtis Apr 25 '18 at 03:12

1 Answers1

2

Generating physicsBodies on the fly is very expensive and that is why your game will lag everytime it tries to do that.

I suggest you create the objects and put them in an array of the obstacle and then copy the array items whenever you need to recreate them.

You have soooooo much code that is being repeated for every object, I've tried to reduce the amount of code by reusing a lot of it for every obstacle.

FYI SKAction.wait(forDuration: 0.0001) is the same as 0 so it is pointless

The code in your obstaclesFunc contains irrelevant or code not contained in your questions so I have omitted that functionality, if it is dire to your game you'll have to figure it out and put it in the generateObstacles func.

//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
}
Ron Myschuk
  • 6,011
  • 2
  • 20
  • 32
  • I am pretty sure waiting 0.00001 is different than 0, but will need to double check this when I get a chance. 0 would only run on 1 update cycle, but 0.00001 would run on 2 – Knight0fDragon Apr 25 '18 at 17:30
  • hmmm, interesting. I assumed that because the max frame rate could be 60fps that would fire every 0.016 times a second. Therefore anything less would be equivalent to 0 – Ron Myschuk Apr 25 '18 at 18:24
  • It doesn’t apply the elapsed time til the next update cycle, so on the first run block elapsed time is 0, 0 < 0.00001 , then next update, 0.016 < 0.00001 is false so complete. Again need to confirm this behavior. – Knight0fDragon Apr 25 '18 at 18:26
  • i'll test this out as well, and will gladly remove my comment from answer if that is so. It doesn't affect my answer as I did not use that as a means to control the timing anyway – Ron Myschuk Apr 25 '18 at 18:30
  • Nope, I would try and help you out more with this answer, but I am having difficulty trying to understand where the OP is going with it – Knight0fDragon Apr 25 '18 at 18:33