2

I have been developing a 2D SpriteKit game that makes use of tile maps. I gave to my tile maps an SKPhysicsBody with this func:

import SpriteKit

func giveTileMapPhysicsBody(map: SKTileMapNode) {
    let tileMap = map
    let tileSize = tileMap.tileSize
    let halfWidth = CGFloat(tileMap.numberOfColumns) / 2.0 * tileSize.width
    let halfHeight = CGFloat(tileMap.numberOfRows) / 2.0 * tileSize.height

    for col in 0..<tileMap.numberOfColumns {

        for row in 0..<tileMap.numberOfRows {

            if let tileDefinition = tileMap.tileDefinition(atColumn: col, row: row)

            {

                //let isEdgeTile = tileDefinition.userData?["AddBody"] as? Int      //uncomment this if needed, see article notes
                //if (isEdgeTile != 0) {
                let tileArray = tileDefinition.textures
                let tileTexture = tileArray[0]
                let x = CGFloat(col) * tileSize.width - halfWidth + (tileSize.width/8)
                let y = CGFloat(row) * tileSize.height - halfHeight + (tileSize.height/8)
                _ = CGRect(x: 0, y: 0, width: tileSize.width, height: tileSize.height)
                let tileNode = SKNode()

                tileNode.position = CGPoint(x: x, y: y)
                tileNode.physicsBody = SKPhysicsBody(texture: tileTexture, size: CGSize(width: (tileTexture.size().width), height: (tileTexture.size().height)))
                tileNode.physicsBody?.linearDamping = 0.8 //60.0
                tileNode.physicsBody?.affectedByGravity = false
                tileNode.physicsBody?.allowsRotation = false
                tileNode.physicsBody?.restitution = 0.2
                tileNode.physicsBody?.isDynamic = false


                tileNode.physicsBody?.categoryBitMask = PhysicsCategory.tileMap
                tileNode.physicsBody?.contactTestBitMask = PhysicsCategory.player
                tileNode.physicsBody?.collisionBitMask = PhysicsCategory.player
                tileNode.physicsBody?.friction = 0.8 // 3.0

                tileMap.addChild(tileNode)
                //}
            }
        }
    }
}

As you can see on the first screenshot, when i run my game on the simulator everything works properly, but when i run it on my real iPhone or iPad there is a bug on the tile map physics (second image). As you can on the second image there is a physics gap when running it on my real devices. Do you know what it could be?

enter image description here

enter image description here

EDIT:

unfortunately it does not work on my project. The physics shape won't match the map correctly. enter image description here

I Don't Tell
  • 264
  • 1
  • 15
  • What is a physics gap? – Magnas Mar 27 '19 at 17:12
  • Thanks for your reply. Look at the second picture. Can you see that the tile map physics body is bigger than its texture? This only happen on real devices, not on the simulator (first pic). – I Don't Tell Mar 27 '19 at 17:23
  • I am guessing you have rounding issues happening. If you are doing tiles, I would not recommend using texture bodies – Knight0fDragon Mar 27 '19 at 17:32
  • Thanks! You mean that it’s better to assign a square physics body to my tiles rather than a physics body based on tile texture? – I Don't Tell Mar 27 '19 at 17:35
  • also, having a physics body per tile is going to kill your performance. You are essentially killing all efficiencies that come with tiles by implementing your own tile system on top of the built in tile system. – Knight0fDragon Mar 27 '19 at 17:35
  • Do you know how can i assign the physics body just on the external tiles? – I Don't Tell Mar 27 '19 at 18:13

1 Answers1

1

Try implementing it like this

typealias TileCoordinates = (column: Int, row: Int)

func giveTileMapPhysicsBody(map: SKTileMapNode)  {
    let tileMap = map

    var physicsBodies = [SKPhysicsBody]()

    for row in 0..<tileMap.numberOfRows {
        for column in 0..<tileMap.numberOfColumns {
            guard let tile = tile(in: tileMap, at: (column, row)) else { continue }

            let center = tileMap.centerOfTile(atColumn: column, row: row)
            let body = SKPhysicsBody(rectangleOf: tile.size, center: center)
            physicsBodies.append(body)
        }
    }

    tileMap.physicsBody = SKPhysicsBody(bodies: physicsBodies)
    tileMap.physicsBody?.categoryBitMask = PhysicsCategory.tileMap
    tileMap.physicsBody?.contactTestBitMask = PhysicsCategory.player
    tileMap.physicsBody?.collisionBitMask = PhysicsCategory.player
    tileMap.physicsBody?.linearDamping = 0.8 //60.0
    tileMap.physicsBody?.affectedByGravity = false
    tileMap.physicsBody?.allowsRotation = false
    tileMap.physicsBody?.restitution = 0.2
    tileMap.physicsBody?.isDynamic = false
    tileMap.physicsBody?.friction = 0.8 // 3.0
}

func tile(in tileMap: SKTileMapNode, at coordinates: TileCoordinates) -> SKTileDefinition? {
    return tileMap.tileDefinition(atColumn: coordinates.column, row: coordinates.row)
}
Arie Pinto
  • 1,274
  • 1
  • 11
  • 19
  • Thank you so much! I've go an error "Use of undeclared type 'TileCoordinates'". How can I fix it? – I Don't Tell Mar 27 '19 at 19:39
  • Sorry, forgot to add that variable, check edited answer, at the top. – Arie Pinto Mar 27 '19 at 19:41
  • Humm..its hard to pinpoint the problem exactly without knowing the tiles you're using. – Arie Pinto Mar 27 '19 at 20:01
  • I’m using the standard tiles provided by Xcode. You can try it too. Isn’t strange that my code works perfectly on simulators and not on real devices? – I Don't Tell Mar 27 '19 at 20:04
  • Strange indeed, but unfortunately for you I don't know why, tried my best to help, sorry I couldn't do more. – Arie Pinto Mar 27 '19 at 20:06
  • Thanks for your helping! The only way to keep going is to don’t use a physics body on my tiles but creating an array of nodes and placing it like “floor”. It’s a dirty and long way. Do you think it could be fine? – I Don't Tell Mar 27 '19 at 20:17