SuperCodeBrah
SuperCodeBrah

Reputation: 3144

Simple SpriteKit game performance issues - Swift

Apologies in advance as I'm not sure exactly what the right question is. The problems that I'm ultimately trying to address are:

1) Game gets laggy at times

2) CPU % can get high, as much as 50-60% at times, but is also sometimes relatively low (<20%)

3) Device (iPhone 6s) can get slightly warm

I believe what's driving the lagginess is that I'm constantly creating and removing circles in the SKScene. It's pretty much unavoidable because the circles are a critical element to the game and I have to constantly change their size and physicsBody properties so there's not much I can do in terms of reusing nodes. Additionally, I'm moving another node almost constantly.

func addCircle() {

    let attributes = getTargetAttributes() //sets size, position, and color of the circle


    let target = /*SKShapeNode()*/SKShapeNode(circleOfRadius: attributes.size.width)
    let outerPathRect = CGRect(x: 0, y: 0, width: attributes.size.width * 2, height: attributes.size.width * 2)

    target.position = attributes.position
    target.fillColor = attributes.color
    target.strokeColor = attributes.stroke
    target.lineWidth = 8 * attributes.size.width / 35
    target.physicsBody = SKPhysicsBody(circleOfRadius: attributes.size.width)

    addStandardProperties(node: target, name: "circle", z: 5, contactTest: ContactCategory, category: CircleCategory) //Sets physicsBody properties

    addChild(target)


}

The getAttributes() function is not too costly. It does have a while loop to set the circle position, but it doesn't usually get used when the function is called. Otherwise, it's simple math.

Some other details:

1) The app runs at a constant 120 fps. I've tried setting the scene/view lower by adding view.preferredFramesPerSecond = 60 in GameScene.swift and gameScene.preferredFramesPerSecond = 60 in GameViewController. Neither one of these does anything to change the fps. Normally when I've had performance issues in other apps, the fps dipped, however, that isn't happening here.

2) I’ve tried switching the SKShapeNode initializer to use a path versus circleOfRadius and then resetting the path. I’ve also tried images, however, because I have to reset the physicsBody, there doesn’t appear to be a performance gain.

3) I tried changing the physicsWorld speed, but this also had little effect.

4) I've also used Instruments to try to identify the issue. There are big chunks of resources being used by SKRenderer, however, I can't find much information on this.

Upvotes: 0

Views: 610

Answers (1)

Knight0fDragon
Knight0fDragon

Reputation: 16837

Creating SKShapeNodes are inefficient, try to use it as few times as you can. instead, create a template shape, and convert it to an SKSpriteNode.

If you need to change the size, then use xScale and yScale, if you need to change the color, then use color with colorBlendFactor of 1

If you need to have a varying color stroke, then change the below code to have 2 SKSpriteNodes, 1 SKSpriteNode that handles only the fill, and 1 SKSpriteNode that handles only the stroke. Have the stroke sprite be a child of the fill sprite with a zPosition of 0 and set the stroke color to white. You can then apply the color and colorBlendFactor to the child node of the circle to change the color.

lazy var circle =
{
   let target = SKShapeNode(circleOfRadius: 1000)
   target.fillColor = .white
   //target.strokeColor = .black //if stroke is anything other than black, you may need to do 2 SKSpriteNodes that layer each other
   target.lineWidth = 8 * 1000 / 35

   let texture = SKView().texture(from:target)
   let spr = SKSpriteNode(texture:texture)
   spr.physicsBody = SKPhysicsBody(circleOfRadius: 1000)
   addStandardProperties(node: spr, name: "circle", z: 5, contactTest:ContactCategory, category: CircleCategory) //Sets physicsBody properties
   return spr
}()

func createCircle(of radius:CGFloat,color:UIColor) -> SKSpriteNode
{
   let spr = circle.copy()
   let scale = radius/1000.0
   spr.xScale = scale
   spr.yScale = scale
   spr.color = color
   spr.colorBlendFactor = 1.0
   return spr

}

func addCircle() {

    let attributes = getTargetAttributes() //sets size, position, and color of the circle
    let spr = createCircle(of:attribute.width,color:attributes.color)
    spr.position = attributes.position
    addChild(str)
}

Upvotes: 2

Related Questions