0
votes

I have searched around the internet / StackOverflow for the past few days without much success in finding an answer to a few questions that I believe are intertwined in some way.

  1. How do I prevent my game from freezing when it is rendering an SKPhysicsBody from a texture?
  2. Why are my physics bodies sometimes not created at all, and why are they sometimes the wrong shapes?

Below is the code I am using to try and generate these pillars (image attached at the bottom of the post. There are roughly 6-8 at any point in time before they are removed. When I change the shape to just a rectangle, I get no lag / freezing at all and the physics object is created properly every time.

Is this SKPhysicsBody rendering too complex, or is there a way that I can have my game run smoothly while still generating a correctly shaped physics object? Below is the function I use to set up the walls as they are created in my game.

func createWalls() {

    let scoreNode = SKSpriteNode()

    wallPair = SKNode()
    wallPair.name = "wallPair"

    //MARK: - Top Wall Setup
    let topWall = SKSpriteNode(imageNamed: "Pillar")
    topWall.size = CGSize(width: 100, height: 700)
    topWall.physicsBody = SKPhysicsBody(texture: topWall.texture!, size: topWall.size)
    topWall.position = CGPoint(x: self.frame.maxX+50, y: 0 + 400)
    topWall.physicsBody?.categoryBitMask = PhysicsCategory.Wall
    topWall.physicsBody?.collisionBitMask = PhysicsCategory.Character
    topWall.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    topWall.physicsBody?.isDynamic = false
    topWall.physicsBody?.affectedByGravity = false
    topWall.zRotation = .pi



    //MARK: - Bot Wall Setup
    let botWall = SKSpriteNode(imageNamed: "Pillar")
    botWall.size = CGSize(width: 100, height: 700)
    botWall.physicsBody = SKPhysicsBody(texture: botWall.texture!, size: botWall.size)
    botWall.position = CGPoint(x: self.frame.maxX+50, y: 0 - 400)
    botWall.physicsBody?.categoryBitMask = PhysicsCategory.Wall
    botWall.physicsBody?.collisionBitMask = PhysicsCategory.Character
    botWall.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    botWall.physicsBody?.isDynamic = false
    botWall.physicsBody?.affectedByGravity = false


    scoreNode.size = CGSize(width: 1, height: 600)
    scoreNode.position = CGPoint(x: topWall.position.x+15, y: 0)
    scoreNode.physicsBody = SKPhysicsBody(rectangleOf: scoreNode.size)
    scoreNode.physicsBody?.affectedByGravity = false
    scoreNode.physicsBody?.isDynamic = false
    scoreNode.physicsBody?.categoryBitMask = PhysicsCategory.Score
    scoreNode.physicsBody?.collisionBitMask = 0
    scoreNode.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    scoreNode.color = SKColor.blue

    wallPair.addChild(topWall)
    wallPair.addChild(botWall)
    wallPair.zPosition = 1

    let randomPosition = CGFloat.random(min: -200, max: 200)
    wallPair.position.y = wallPair.position.y + randomPosition
    wallPair.addChild(scoreNode)
    wallPair.run(moveAndRemove)
    self.addChild(wallPair)

}

Pillar Image

1
Related to this issue? stackoverflow.com/questions/58062098/… We haven't had problems with iOS 13.3 and physics bodies from textures as long as the textures aren't in an atlas. Using textures in an atlas is still broken I believe. Regardless, I haven't tried to make physics bodies from such large textures. Maybe make one at the start of your game during setup, then body.copy() as! SKPhysicsBody will make a copy of the body, though it's not really documented. Worst case, for a simple shape, making polygons by hand isn't too bad.bg2b
@bg2b Thank you! This worked for me. The game is running smoothly / properly now. I think running the SKPhysicsBody from texture repeatedly on such a large image was too intensive.Frodgers
@bg2b, I do not have this issue. i.stack.imgur.com/CfJyW.png I added Frodgers image to my atlas.... still no problem i.stack.imgur.com/mlQZ8.png ... ok, I tested on different devices I am getting errors now. It is definelty dependant on device.Knight0fDragon
@Knight0fDragon I'm not sure what is the root cause of the breakage, but it's definitely affected a lot of others (as well as me). I even see problems in Xcode when doing a quick look at some textures; the previews have odd effects, and the cgImage method sometimes gives screwy results that match what Xcode shows me. Our textures aren't big enough for a few non-atlas duplicates to be worth worrying about fortunately.bg2b
@bg2b I normally use codeandweb.com/physicseditor and make CGPaths of my bodies. This allows me to fine tune the polygon, since the less lines the better.Knight0fDragon

1 Answers

0
votes

you can use this extension:

extension SKTexture{
  func pristineCopy() -> SKTexture{
      return SKTexture(cgImage:self.cgImage)
  }
}

This should temporarily create a new texture for your physics body to use without getting bogged down by the atlas.

Once the SKPhysicsBody creates the CGPath out of this texture, the memory should get released, so try not to retain it with a variable.

example:

func createWalls()
    let scoreNode = SKSpriteNode()

    wallPair = SKNode()
    wallPair.name = "wallPair"

    //MARK: - Top Wall Setup
    let topWall = SKSpriteNode(imageNamed: "Pillar")
    topWall.size = CGSize(width: 100, height: 700)
    topWall.physicsBody = SKPhysicsBody(texture: topWall.texture!.pristineCopy(), size: topWall.size)
    topWall.position = CGPoint(x: self.frame.maxX+50, y: 0 + 400)
    topWall.physicsBody?.categoryBitMask = PhysicsCategory.Wall
    topWall.physicsBody?.collisionBitMask = PhysicsCategory.Character
    topWall.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    topWall.physicsBody?.isDynamic = false
    topWall.physicsBody?.affectedByGravity = false
    topWall.zRotation = .pi



    //MARK: - Bot Wall Setup
    let botWall = SKSpriteNode(imageNamed: "Pillar")
    botWall.size = CGSize(width: 100, height: 700)
    botWall.physicsBody = SKPhysicsBody(texture: botWall.texture!.pristineCopy(), size: botWall.size)
    botWall.position = CGPoint(x: self.frame.maxX+50, y: 0 - 400)
    botWall.physicsBody?.categoryBitMask = PhysicsCategory.Wall
    botWall.physicsBody?.collisionBitMask = PhysicsCategory.Character
    botWall.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    botWall.physicsBody?.isDynamic = false
    botWall.physicsBody?.affectedByGravity = false


    scoreNode.size = CGSize(width: 1, height: 600)
    scoreNode.position = CGPoint(x: topWall.position.x+15, y: 0)
    scoreNode.physicsBody = SKPhysicsBody(rectangleOf: scoreNode.size)
    scoreNode.physicsBody?.affectedByGravity = false
    scoreNode.physicsBody?.isDynamic = false
    scoreNode.physicsBody?.categoryBitMask = PhysicsCategory.Score
    scoreNode.physicsBody?.collisionBitMask = 0
    scoreNode.physicsBody?.contactTestBitMask = PhysicsCategory.Character
    scoreNode.color = SKColor.blue

    wallPair.addChild(topWall)
    wallPair.addChild(botWall)
    wallPair.zPosition = 1

    let randomPosition = CGFloat.random(min: -200, max: 200)
    wallPair.position.y = wallPair.position.y + randomPosition
    wallPair.addChild(scoreNode)
    wallPair.run(moveAndRemove)
    self.addChild(wallPair)
}