El Tomato
El Tomato

Reputation: 6707

Removing a Particular Tile from SKTileMapNode

enter image description here

I have a Tile Map Node that covers my entire game scene (GameScene.sks). There's an enemy at the top of the screen. And there are tiny houses that are laid out at the bottom. Only these houses come from the tile map node. The enemy is supposed to fire a shot at any of those houses. contactBitMask is set to both fired shots and house tiles. And I want to remove the house that is being hit by the shot with contactBitMask. Anyway, I have the following lines code.

class GameScene: SKScene, SKPhysicsContactDelegate {

    var destructibleCount = Int() // destructibleCount
    func setupDestructiblePhysics() {
        guard let obstaclesTileMap = obstaclesTileMap else { return }
        for row in 0..<obstaclesTileMap.numberOfRows {
            for column in 0..<obstaclesTileMap.numberOfColumns {
                guard let tile = tile(in: obstaclesTileMap, at: (column, row)) // a function returning SKTileDefinition
                    else { continue }
                guard tile.userData?.object(forKey: "destructible") != nil // 'destructible' is set through TileSet
                    else { continue }
                let node = SKNode()
                node.physicsBody = SKPhysicsBody(rectangleOf: tile.size)
                node.physicsBody?.isDynamic = false
                node.physicsBody?.categoryBitMask = PhysicsCategory.Building
                node.position = obstaclesTileMap.centerOfTile(atColumn: column, row: row)
                node.name = "building"
                obstaclesTileMap.addChild(node)
                destructibleCount += 1
            }
        }
    }

    func didBegin(_ contact: SKPhysicsContact) {
        let enemyBeamContact = contact.bodyA.categoryBitMask == PhysicsCategory.EnemyShot ? contact.bodyB : contact.bodyA
        switch enemyBeamContact.categoryBitMask {
        case PhysicsCategory.Building:
            if let nodeA = contact.bodyA.node {
                let column = obstaclesTileMap!.tileColumnIndex(fromPosition: nodeA.position)
                let row = obstaclesTileMap!.tileRowIndex(fromPosition: nodeA.position)
                print(column, row)
                enumerateChildNodes(withName: "building", using: { node, _ in
                    if node.position == nodeA.position {
                        node.removeFromParent()
                    }
                })

                if let tile = tile(in: obstaclesTileMap!, at: (column, row)) {
                    // not being used
                }
            }
            if let nodeB = contact.bodyB.node {
                // bullet //
                if nodeB.name == "beam" {
                    nodeB.removeFromParent()
                }
            }
        default:
            break
        }
    }
}

When a shot hits a house, the didBegin physics methods does tell me the tile that is being hit. (See print(column, row)). What I have difficulty with is how to remove the tile that is being hit. node.removeFromParent() isn't effective. And I cannot remove any of the tiles. I have a feeling that you cannot remove one tile. Or can we? I thought use of tiles is an efficient way of developing SpriteKit games. But it seems otherwise to me. I guess I could just add those houses to the scene programatically. Thanks.

Upvotes: 2

Views: 729

Answers (1)

BadgerBadger
BadgerBadger

Reputation: 696

An SKTilemapNode is a whole in itself, so contact test will only tell you when you make contact with the tile map, not the individual tiles.

What you can do though, is use a tilemap to design the levels, but in the didMove(to:) function, you walk the tile map and create individual SKSpriteNode for each house you find. You can use SKTilemapNode's functions to get the info you need (which texture you used, position, etc):

Once you are done walking the tilemap and all your houses are created, remove the tilemap from the scene and make contact with the houses as you would normally.

Hope it helps!

Upvotes: 2

Related Questions