Search code examples
iosswiftsprite-kitsktilemapnodeskcameranode

SKTileMapNode disappears when off-camera, does not reappear


I have a SpriteKit platformer that uses a tile map for a background. The background in question is positioned 1 screen-height above the main content (it's positioned off-screen), acting as a forest canopy above the player. I accomplish that programmatically, like this:

let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
let columns = 20
let rows = 1
let tileSize = CGSize(width: screenWidth, height: screenHeight)

let container = SKSpriteNode()
let tileDefinition = SKTileDefinition(texture: MainData.textureAtlas.textureNamed("someTexture"), size: CGSize(width: screenWidth, height: screenHeight))
let tileGroup = SKTileGroup(tileDefinition: tileDefinition)
let tileSet = SKTileSet(tileGroups: [tileGroup])
let layer = SKTileMapNode(tileSet: tileSet, columns: columns, rows: rows, tileSize: tileSize)

container.position = CGPoint(x: screenWidth*0.5, y: screenHeight*1.5)
container.size = CGSize(width: CGFloat(columns)*screenWidth, height: screenHeight)
container.zPosition = 3.0

layer.fill(with: tileGroup)
                
container.addChild(layer)
addChild(container)

A camera node follows the player.

The problem: If the player jumps up, the SKTileMapNode disappears when he comes back down. It never reappears. Its parent node, container, remains visible, so I think the problem is with the SKTileMapNode, not the container.

What I've tried: I've tried the following, with numbers 2-5 being checked for the SKTileMapNode:

  1. Setting view.shouldCullNonVisibleNodes = false.
  2. Checking the alpha value. It's always 1.0.
  3. Checking the position. It's always CGPoint(x: 0, y: 0).
  4. Checking the anchorPoint. It's always CGPoint(x: 0.5, y: 0.5).
  5. Checking the zPosition. It does not change, and there are no other nodes that could be obscuring the SKTileMapNode or its parent. Setting a higher value has no effect on the problem.
  6. Checking that container remains visible. It does.

On culling: It seems like the problem should be related to culling, but setting view.shouldCullNonVisibleNodes=false has no effect on the situation. I also checked to make sure the SKTileMapNode is always present as a child node of container. It is. I suppose this means that the node is not being culled. However, if I position container so that it's always on-screen, the problem does not occur at all; the SKTileMapNode remains visible. This leaves me very confused because it seems like these are conflicting facts.

On devices: Using the simulator, at least, the problem does not occur on the older-style iPhones such as the SE and the iPhone 8. It only happens on the newer iPhones, such as the iPhone 11 and iPhone 12. Having access to an iPhone 11, I can confirm that the problem is occurring on real devices, too.

Question: Why is my SKTileMapNode disappearing when off-camera (even with culling disabled)? How can I keep this node visible?

Thank you!


Solution

  • It seems that I've solved the problem.

    I'm presenting my scene via SwiftUI SpriteView, which I had configured to allow background transparency, like this:

    SpriteView(scene: theScene, options: [.allowsTransparency])
    

    Removing the transparency option solved the problem:

    SpriteView(scene: theScene)
    

    Now, why should this be the case? I have no idea.