创建节点集的性能问题
Posted
技术标签:
【中文标题】创建节点集的性能问题【英文标题】:Performance issues creating set of nodes 【发布时间】:2019-06-19 17:56:34 【问题描述】:我正在制作游戏并尝试在一次调用中添加一组障碍。
我正在制作两个节点并在这些节点内部创建 14 到 18 次障碍物,如果这些障碍物在场景之外,甚至不添加它们。
我所有的纹理都在 sprite.atlas 中,并且我已经在 didMove 中调用了 preload。问题是每当我调用上面的函数时,场景都会下降到 58fps,这使得游戏看起来像是滞后。我真的不知道该怎么做才能使这段代码更好地工作。
也许看到代码对我正在尝试做的事情更有意义。
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】:试一试,让我知道你失败的地方。基本上,我消除了构建新节点和物理体的过程,并清理了你的代码,这样我们就不会重复循环了
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()]))
【讨论】:
感谢您提供的代码。我进行了编辑以展示我是如何解决这个小问题的。以上是关于创建节点集的性能问题的主要内容,如果未能解决你的问题,请参考以下文章
使用数据透视表关系提高大型数据集的性能(使用 Laravel)