Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging or flattening background nodes to improve game performance?

I want to be able to improve my game's performance by somehow "flattening" my background nodes.


This youtube video demonstrates how I build up my background graphics.


But, I have my background graphics set up like this.

I use two textures like stamps and repeat then. In this case... one mountain texture with a snowy top... One mountain texture without the snow. I alter the zPosition of these stamps for a "layering" effect.

enter image description here

enter image description here

I then use "fills" which are just SKSpriteNodes of solid grey to layer over parts that need a grey fill.

E.g. Before fill nodes are added

enter image description here

A colour screen with alpha is then added on top to give the mountain a faded looked.

E.g. Before enter image description here

E.g. After enter image description here


The game sometimes freezes up... but it doesn't freeze when I remove these graphics.

Is there a way to improve performance by merging or flattening my background graphics nodes based on zPosition as a scene is loading up? How would I do this?

Would this improve performance? Or what would be the best way to improve performance in my case?

I think this question is similar... Merge all SKSpriteNode children into a single SKSpriteNode

But, how do I do this in Swift and take zPosition and alpha into account so I don't lose the layering effects?

like image 644
Corey F Avatar asked Oct 15 '17 20:10

Corey F


2 Answers

Somethings you may want to do:

Separate your foreground and background into separate SKS files, and load them into your main SKS file via SKReferenceNode

Convert these SKS files into textures instead of SKReferenceNodes via code using view!.texture(from: node)

Ensure your atlas is not being broken up in a way that adds to the draw count

Design your code in a way that not all nodes are on the scene, the more nodes the slower your code becomes.

If you have SKPhysicsBody's, try to use as few as possible. This can be done my merging multiple bodies together with SKPhysicBody(bodies:) or creating 1 body with a polygon that goes around multple objects.

Also, if your bodies are not moving via physics (Not by SKActions) then make sure that isDynamic is set to false

If you are running SKActions, make sure you use as few of these as possible. For example, if you have 4 different nodes travelling left at 10 points per second, you can put these 4 nodes into a parent node, and run the action on the parent node.

like image 106
Knight0fDragon Avatar answered Oct 07 '22 08:10

Knight0fDragon


Ok so here is an example of what you have now.. all your nodes here like this:

enter image description here

How to execute the bitblit easily is to move all these under a new empty node called "background"

enter image description here

Now head to your swift file, and set up an placeholder variable for the new node we will create in code

class GameScene: SKScene {

  var blitBackground = SKSpriteNode()

  override func didMove(to view: SKView) {

  }

}

Now , add this handy function that you can use in all of your projects if desired:

func blit(from node: SKNode) -> SKSpriteNode {
  return SKSpriteNode(texture: SKView().texture(from: node))
}

and here is the method we will use to initialize our bitblit background, and remove the laggy one from the game:

  func blitTheBackground() { // use in didMove
    let laggyBackground = childNode(withName: "background")!
    blitBackground = blit(from: laggyBackground)
    laggyBackground.removeFromParent()
    addChild(blitBackground)
  }

Here is the completed scene:

class GameScene: SKScene {

  var blitBackground = SKSpriteNode()

  func blit(from node: SKNode) -> SKSpriteNode {
    return SKSpriteNode(texture: SKView().texture(from: node))
  }

  func blitTheBackground() {
    let laggyBackground = childNode(withName: "background")!
    blitBackground = blit(from: laggyBackground)
    laggyBackground.removeFromParent()
    addChild(blitBackground)
  }

  override func didMove(to view: SKView) {
   blitTheBackground()
  }

}

and it reduced the node count from 10 to 4... hopefully, for you it will help with your draw count too!!

enter image description here NOTE, this method is EXTREMELY effective with shapenodes!!

If you need to do this in a loop, be sure to place it in an autorelease pool to be sure that the memory is freed up after it is used. Creating textures from the view uses a lot of memory, so you can expect to get errors if you are not careful with it.

for i in 0..<5
{
    autoreleasepool{
        let laggyBackground = childNode(withName: "background\(i)")!
        blitBackground = blit(from: laggyBackground)
        laggyBackground.removeFromParent()
        addChild(blitBackground)
    }
}
like image 21
Fluidity Avatar answered Oct 07 '22 08:10

Fluidity