In the What's New in SpriteKit WWDC video, a feature was shown off that you can apply custom data to certain tiles (the edgeTile boolean, shown at 21:00). What else (other code) do I need to make a sprite collide with these tiles?
Replies
Also wondering about this.
I'm also really interested to know how he did it.
After reading around on the internet about how people are doing it with Cocos2d and other frameworks, I'm planning to create a node for each tile just so that I can add a physics body to it. I'll probably add user data to the TileDefinition objects like he did. Then, I'll walk the map and generate the physics bodys and nodes that way. Some people create one shape (or a few shapes if they're not connected) from the whole map. In my game, I don't want to do that because my tiles will occassionally change and I don't want to have to regenerate the physics body.
If others have better ideas, I'm very interested.
This is what I'm doing right now:
self.tileMap = self.childNode(withName: "Tile Map") as? SKTileMapNode
guard let tileMap = self.tileMap else { fatalError("Missing tile map for the level") }
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 {
let tileDefinition = tileMap.tileDefinition(atColumn: col, row: row)
let isEdgeTile = tileDefinition?.userData?["edgeTile"] as? Bool
if (isEdgeTile ?? false) {
let x = CGFloat(col) * tileSize.width - halfWidth
let y = CGFloat(row) * tileSize.height - halfHeight
let rect = CGRect(x: 0, y: 0, width: tileSize.width, height: tileSize.height)
let tileNode = SKShapeNode(rect: rect)
tileNode.position = CGPoint(x: x, y: y)
tileNode.physicsBody = SKPhysicsBody.init(rectangleOf: tileSize, center: CGPoint(x: tileSize.width / 2.0, y: tileSize.height / 2.0))
tileNode.physicsBody?.isDynamic = false
tileNode.physicsBody?.collisionBitMask = playerCollisionMask | wallCollisionMask
tileNode.physicsBody?.categoryBitMask = wallCollisionMask
tileMap.addChild(tileNode)
}
}
}
Hey,
I was wondering if your solution worked for you ? I tried it on my game and still my player keeps falling through the tiles .. if yours worked can i know more details that i could be missing ? like some definitions or where did you include that code ? in the update function ? thats what i did .. let me know i would appreciate some help on this.
Agreed, I think your best bet is basically a "dummy" node for each tile that just defines a physics body. The body doesn't need to actually have any visual artwork with it. You'd end up with many physics bodies in a row of course, but just as simple boundary, thats fine.
Welldone, Its worked for me too. thanks alot. 🙂🙂🙂
Hi All,
I had a look at this and found you can make the tilemap objects have collision detection of alpha mask. here is the code.
func tileMapPhysics(name: SKTileMapNode)
{
let tileMap = name
/
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?["hit"] as? Int
if (isEdgeTile != 0)
{
let tileArray = tileDefinition.textures
let tileTexture = tileArray[0]
let x = CGFloat(col) * tileSize.width - halfWidth + (tileSize.width/2)
let y = CGFloat(row) * tileSize.height - halfHeight + (tileSize.height/2)
let rect = 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 * 2),
height: (tileTexture.size().height * 2)))
tileNode.physicsBody?.linearDamping = 60.0
tileNode.physicsBody?.affectedByGravity = false
tileNode.physicsBody?.allowsRotation = false
tileNode.physicsBody?.restitution = 0.0
tileNode.physicsBody?.isDynamic = false
tileNode.physicsBody?.collisionBitMask = CollisionCategoryBitmask.frogmanCC
tileNode.physicsBody?.categoryBitMask = CollisionCategoryBitmask.chestCC
tileNode.name = "jelly"
tileNode.yScale = tileMap.yScale
tileNode.xScale = tileMap.xScale
/
tileMap.addChild(tileNode)
}
}
}
}
}
You can not have 2 objects that are both Alpha Masks i.e main sprite and object in tilemap, as it is overload on the detection procressing.
dontangg,
Correct, adding an invisible child node for each tile in the SKTileMapNode that needs a physics body is the right approach. SKTileMapNode doesn't use nodes for its tiles and therefore its tiles are incapable of having physics bodies. A simple example would be to add the node (that has the physics body for a given tile) as a child node to the SKTileMapNode at the same position and anchor point for the tile that needs the physics body.
Thank you for contributing some insight regarding the best approach for this. It helps to know what the recommended practice is for something that is a common workflow in SpriteKit, but does not have a clear solution.
What I'd really like to see is for Apple to enhance the tile map API so that we can add physics bodies directly to individual tiles. Maybe in the process they could optimize the engine so that physics bodies on individual tiles would be automatically merged to form larger, more optimal shapes in order to improve system performance. (Apple Bug Reporter request filed under report number 38488605).
>What I'd really like to see is
Suggestions such as this are perhaps best put to the bug reporter, link bottom right, adding your report# to your thread for reference, thanks and good luck.
Cocos2D... wow I didnt think I would hear that again.
Cocos2D and objective C? Or the Android version.
Thats how I initially learned how to code.
Until Swift just swept right on in.
Brings back memories. LOL.