I'm making a game and trying to add a set of obstacles in one call.
I'm making two nodes and inside theses nodes creating an obstacle 14 to 18 times, and if theses obstacles are outside of the scene to not even add them.
All my textures are inside an sprite.atlas and I already called preload at didMove. The problem is that whenever I called the function above the scene drops to 58fps and this makes the game looks like is lag. I really do not know what to do to make this code works better.
Maybe seeing the code makes more sense on what I'm trying to do.
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()]))
}
SOLVED: I know it is not a clean code but I'm working on that aspect idk why I feel so comfortable doing it like that. Thanks for your guide I manage to set the fps to normal whenever the function is called:
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()]))
}
Give this a try, let me know what fails you. Basically, I eliminated the process of building new nodes and physics bodies, and cleaned up your code so that we are not double looping
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()]))
}