Проблемы с производительностью при создании набора узлов - PullRequest
0 голосов
/ 19 июня 2019

Я делаю игру и пытаюсь добавить набор препятствий в один вызов.

Я делаю два узла и внутри этих узлов создаю препятствие от 14 до 18 раз, и если эти препятствия находятся за пределами сцены, даже не добавляем их.

Все мои текстуры находятся внутри sprite.atlas, и я уже вызывал preload в didMove. Проблема в том, что всякий раз, когда я вызываю функцию выше сцены, падает до 58 кадров в секунду, и это делает игру похожей на задержку. Я действительно не знаю, что нужно сделать, чтобы этот код работал лучше.

Может быть, видение кода имеет больше смысла в том, что я пытаюсь сделать.

  func createMeteor() {
    rightMeteors = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 400, height: 50))
    leftMeteors = SKSpriteNode(color: UIColor.clear, size: CGSize(width: 400, height: 50))
    rightMeteors.name = "MeteorPairs"
    leftMeteors.name = "MeteorPairs"

    let meteorsDistance: CGFloat = 90
    let maxX = scene!.size.width/2 + 150
    let minX = -scene!.size.width/2 + meteorsDistance + 250
    let xPosition = round(CGFloat.random(in: minX ... maxX))

    rightMeteors.position = CGPoint(x: xPosition, y: scene!.size.height/2 + 50)
    rightMeteors.zPosition = 2
    leftMeteors.position = CGPoint(x: xPosition - 400 - meteorsDistance, y: scene!.size.height/2 + 50)
    leftMeteors.zPosition = 2

    addChild(rightMeteors)
    addChild(leftMeteors)

    let randomNumberMeteors = Int.random(in: 14...18)

    for _ in 0...randomNumberMeteors {
        let numberGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 12)
        let randomMeteorNumber = numberGenerator.nextInt()
        let meteorTexture = meteorAtlas.textureNamed("Meteor_\(randomMeteorNumber)")

        meteor = SKSpriteNode(texture: meteorTexture)
        meteor.setScale(0.6)

        let xMin = meteor.size.width/2 - 200
        let xMax = 200 - meteor.size.width/2
        let xRange = xMax - xMin
        let xRandom = xMax - CGFloat(arc4random_uniform(UInt32(xRange)))
        meteor.position = CGPoint(x: xRandom, y: 0)

        var body = SKPhysicsBody()
        switch randomMeteorNumber {
        case 1:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 2:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 3:
            body = SKPhysicsBody(circleOfRadius: 17)
        case 4:
            body = SKPhysicsBody(circleOfRadius: 18)
        case 5:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 6:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 7:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 8:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 9:
            body = SKPhysicsBody(circleOfRadius: 3)
        case 10:
            body = SKPhysicsBody(circleOfRadius: 2)
        default:
            break
        }

        body.affectedByGravity = false
        body.categoryBitMask = obstacleCategory
        body.contactTestBitMask = shipCategory
        body.collisionBitMask = 0

        meteor.physicsBody = body
        if rightMeteors.convert(meteor.position, to: scene!).x < scene!.size.width/2  {
            rightMeteors.addChild(meteor)
        }

        let random = CGFloat.random(in: -0.1 ... 0.1)
        let xMove = SKAction.moveBy(x: random, y: 0, duration: 0.03)
        meteor.run(SKAction.repeatForever(xMove))
    }

    for _ in 0...randomNumberMeteors {
        let numberGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 12)
        let randomMeteorNumber = numberGenerator.nextInt()
        let meteorTexture = meteorAtlas.textureNamed("Meteor_\(randomMeteorNumber)")

        meteor = SKSpriteNode(texture: meteorTexture)
        meteor.setScale(0.6)

        let xMin = meteor.size.width/2 - 200
        let xMax = 200 - meteor.size.width/2
        let xRange = xMax - xMin
        let xRandom = xMax - CGFloat(arc4random_uniform(UInt32(xRange)))
        meteor.position = CGPoint(x: xRandom, y: 0)

        var body = SKPhysicsBody()
        switch randomMeteorNumber {
        case 1:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 2:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 3:
            body = SKPhysicsBody(circleOfRadius: 17)
        case 4:
            body = SKPhysicsBody(circleOfRadius: 18)
        case 5:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 6:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 7:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 8:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 9:
            body = SKPhysicsBody(circleOfRadius: 3)
        case 10:
            body = SKPhysicsBody(circleOfRadius: 2)
        default:
            break
        }

        body.affectedByGravity = false
        body.categoryBitMask = obstacleCategory
        body.contactTestBitMask = shipCategory
        body.collisionBitMask = 0

        meteor.physicsBody = body
        if leftMeteors.convert(meteor.position, to: scene!).x > -scene!.size.width/2  {
            leftMeteors.addChild(meteor)
        }

        let random = CGFloat.random(in: -0.1 ... 0.1)
        let xMove = SKAction.moveBy(x: random, y: 0, duration: 0.03)
        meteor.run(SKAction.repeatForever(xMove))
    }

    let moveDown = SKAction.moveBy(x: 0, y: -scene!.size.height - 100, duration: 2.5)

    leftMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
    rightMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
}

РЕШИТЬ: Я знаю, что это не чистый код, но я работаю над этим аспектом, поэтому я чувствую себя так комфортно, делая это так. Спасибо за ваше руководство, мне удается установить fps в нормальное состояние при каждом вызове функции:

var meteorsArray = [SKSpriteNode]()

func createMeteorsTemplate() {
    for i in 1 ... 12 {
        let texture = meteorAtlas.textureNamed("Meteor_\(i)")
        let newMeteor = SKSpriteNode(texture: texture)
        newMeteor.setScale(0.6)

        switch i {
        case 1:
            newMeteor.physicsBody = SKPhysicsBody(texture: texture, size: newMeteor.size)
        case 2:
            newMeteor.physicsBody = SKPhysicsBody(texture: texture, size: newMeteor.size)
        case 3:
            newMeteor.physicsBody = SKPhysicsBody(texture: texture, size: newMeteor.size)
        case 4:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 18)
        case 5:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 23)
        case 6:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 8)
        case 7:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 8)
        case 8:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 5)
        case 9:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 5)
        case 10:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 5)
        case 11:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 3)
        case 12:
            newMeteor.physicsBody = SKPhysicsBody(circleOfRadius: 10)
        default:
            break
        }

        newMeteor.physicsBody?.affectedByGravity = false
        newMeteor.physicsBody?.categoryBitMask = obstacleCategory
        newMeteor.physicsBody?.contactTestBitMask = shipCategory
        newMeteor.physicsBody?.collisionBitMask = 0

        meteorsArray.append(newMeteor)
    }

}
func createMeteor() {
    let rightMeteors = SKNode()
    let leftMeteors = SKNode()
    rightMeteors.name = "MeteorPairs"
    leftMeteors.name = "MeteorPairs"

    let meteorsDistance: CGFloat = 90
    let maxX = scene!.size.width/2 + 150
    let minX = -scene!.size.width/2 + meteorsDistance + 250
    let xPosition = round(CGFloat.random(in: minX ... maxX))

    rightMeteors.position = CGPoint(x: xPosition, y: scene!.size.height/2 + 50)
    leftMeteors.position = CGPoint(x: xPosition - 400 - meteorsDistance, y: scene!.size.height/2 + 50)

    rightMeteors.zPosition = 2
    leftMeteors.zPosition = 2

    addChild(rightMeteors)
    addChild(leftMeteors)

    for meteorSide in 0 ... 1 {
        let randomNumberOfMeteors = GKShuffledDistribution(lowestValue: 14, highestValue: 18).nextInt()
        for _ in 0 ... randomNumberOfMeteors {
            let randomMeteorNumber = GKShuffledDistribution(lowestValue: 1, highestValue: 12).nextInt()
            let meteorTemplate = meteorsArray[randomMeteorNumber-1]
            let meteor = meteorTemplate.copy() as! SKSpriteNode
            let xMin = meteor.size.width/2 - 200
            let xMax = 200 - meteor.size.width/2
            let xRange = xMax - xMin
            let xRandom = xMax - CGFloat(arc4random_uniform(UInt32(xRange)))
            meteor.position = CGPoint(x: xRandom, y: 0)

            switch meteorSide {
            case 0:
                if rightMeteors.convert(meteor.position, to: scene!).x < scene!.size.width/2  {
                    rightMeteors.addChild(meteor)
                }
            case 1:
                if leftMeteors.convert(meteor.position, to: scene!).x > -scene!.size.width/2  {
                    leftMeteors.addChild(meteor)
                }
            default:
                break
            }
        }
    }

    let moveDown = SKAction.moveBy(x: 0, y: -scene!.size.height - 100, duration: 2.5)
    leftMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
    rightMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
}

1 Ответ

0 голосов
/ 20 июня 2019

Дайте этому попытку, дайте мне знать, что вас не устраивает. По сути, я исключил процесс создания новых узлов и физических тел и очистил ваш код, чтобы мы не делали двойной цикл

let meteorsDistance: CGFloat = 90
let maxX = scene!.size.width/2 + 150
let minX = -scene!.size.width/2 + meteorsDistance + 250
let meteors = [SKSpriteNode](repeating: SKSpriteNode(), count: 13)
func createMeteorTemplate(){ //Call on init
    for meteorNumber in 1...12 {
        let meteorTexture = meteorAtlas.textureNamed("Meteor_\(meteorNumber)")
        let meteor = SKSpriteNode(texture: meteorTexture)
        meteor.setScale(0.6)
        var body : SKPhysicsBody!

        switch meteorNumber {
        case 1:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 2:
            body = SKPhysicsBody(texture: meteorTexture, size: meteor.size)
        case 3:
            body = SKPhysicsBody(circleOfRadius: 17)
        case 4:
            body = SKPhysicsBody(circleOfRadius: 18)
        case 5:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 6:
            body = SKPhysicsBody(circleOfRadius: 8)
        case 7:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 8:
            body = SKPhysicsBody(circleOfRadius: 5)
        case 9:
            body = SKPhysicsBody(circleOfRadius: 3)
        case 10:
            body = SKPhysicsBody(circleOfRadius: 2)
        default:
            break
        }
        body.affectedByGravity = false
        body.categoryBitMask = obstacleCategory
        body.contactTestBitMask = shipCategory
        body.collisionBitMask = 0
        meteor.physicsBody = body
        meteors[i] = meteor 
   }
}

func createMeteor() {
    rightMeteors = SKNode()
    leftMeteors = SKNode()
    rightMeteors.name = "MeteorPairs"
    leftMeteors.name = "MeteorPairs"

    let xPosition = round(CGFloat.random(in: minX ... maxX))

    rightMeteors.position = CGPoint(x: xPosition, y: scene!.size.height/2 + 50)
    rightMeteors.zPosition = 2
    leftMeteors.position = CGPoint(x: xPosition - 400 - meteorsDistance, y: scene!.size.height/2 + 50)
    leftMeteors.zPosition = 2

    addChild(rightMeteors)
    addChild(leftMeteors)

    let randomNumberMeteors = Int.random(in: 14...18)
    let numberGenerator = GKShuffledDistribution(lowestValue: 1, highestValue: 12)


    func createNewMeteor(numberGenerator : GKShuffleDistribution) -> SKSpriteNode
    {
        let meteorTemplate = meteors[randomMeteorNumber]
        let meteor = meteorsTemplate.copy()
        meteor.physicsBody = meteorTemplate.physicsBody.copy()
        let xMin = meteor.size.width/2 - 200
        let xMax = 200 - meteor.size.width/2
        let xRange = xMax - xMin
        let xRandom = xMax - CGFloat(arc4random_uniform(UInt32(xRange)))
        meteor.position = CGPoint(x: xRandom, y: 0)
        let random = CGFloat.random(in: -0.1 ... 0.1)
        let xMove = SKAction.moveBy(x: random, y: 0, duration: 0.03)
        meteor.run(SKAction.repeatForever(xMove))

        return meteor
    }

    for _ in 0...(randomNumberMeteors * 2 + 1) {
        let meteor = createNewMeteor(numberGenerator)
        if meteor.position.x < scene!.size.width/2  {
            rightMeteors.addChild(meteor)
        else
            leftMeteors.addChild(meteor)
        }
    }



    let moveDown = SKAction.moveBy(x: 0, y: -scene!.size.height - 100, duration: 2.5)

    leftMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
    rightMeteors.run(SKAction.sequence([moveDown, SKAction.removeFromParent()]))
}
...