I have created a SKShapeNode
in the following way,
let sprite = SKShapeNode(rect: CGRect(x: -20, y: -10, width: 40, height: 20), cornerRadius: 10)
I also set a physics body like so,
sprite.physicsBody = SKPhysicsBody(rectangleOf: sprite.frame.size)
but I realized that the collisions and contacts weren't precise, so I changed showsPhysics
to true
and got the following. How can I make the physics body precise, even for the rounded corners?
From the documentation:
Maybe the #4 is your case
let spaceShipTexture = SKTexture(imageNamed: "spaceShip.png")
Spaceship 1: circular physics body
let circularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
circularSpaceShip.physicsBody = SKPhysicsBody(circleOfRadius: max(circularSpaceShip.size.width / 2,
circularSpaceShip.size.height / 2))
Spaceship 2: rectangular physics body
let rectangularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
rectangularSpaceShip.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: circularSpaceShip.size.width,
height: circularSpaceShip.size.height))
Spaceship 3: polygonal physics body
let polygonalSpaceShip = SKSpriteNode(texture: spaceShipTexture)
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: -5, y: 37), CGPoint(x: 5, y: 37), CGPoint(x: 10, y: 20),
CGPoint(x: 56, y: -5), CGPoint(x: 37, y: -35), CGPoint(x: 15, y: -30),
CGPoint(x: 12, y: -37), CGPoint(x: -12, y: -37), CGPoint(x: -15, y: -30),
CGPoint(x: -37, y: -35), CGPoint(x: -56, y: -5), CGPoint(x: -10, y: 20),
CGPoint(x: -5, y: 37)])
path.closeSubpath()
polygonalSpaceShip.physicsBody = SKPhysicsBody(polygonFrom: path)
Spaceship 4: physics body using texture’s alpha channel
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
size: CGSize(width: circularSpaceShip.size.width,
height: circularSpaceShip.size.height))
Remember that too much precision is very bad for performance. Read this:
https://developer.apple.com/reference/spritekit/skphysicsbody
For general cases, it would be better to ignore the corners and stick with the normal rectangle physics, unless you REALLY need that precision. If you do, you could use a SKTexture on a SKSpriteNode instead of a ShapeNode. That would be much easier, because you could simply do this:
let size = CGSize(width: 100, height: 50)
let roundedRectangleTexture = SKTexture(image: UIImage(named: "textureImage")!)
let mySpriteNode = SKSpriteNode(texture: roundedRectangleTexture, size: size)
mySpriteNode.physicsBody = SKPhysicsBody(texture: roundedRectangleTexture, size: size)
With a texture, you can easily make a more detailed and precise physicsBody by simply using the SKPhysicsBody(texture: size:)
constructor.
I would follow the documentation of SKPhysicsBody, and create a polygonal shape that approximates the rounded corners of your sprite.
An example on the documentation shows that you can define a polygonal physics body like so:
// Spaceship 3: polygonal physics body
let polygonalSpaceShip = SKSpriteNode(texture: spaceShipTexture)
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: -5, y: 37), CGPoint(x: 5, y: 37), CGPoint(x: 10, y: 20),
CGPoint(x: 56, y: -5), CGPoint(x: 37, y: -35), CGPoint(x: 15, y: -30),
CGPoint(x: 12, y: -37), CGPoint(x: -12, y: -37), CGPoint(x: -15, y: -30),
CGPoint(x: -37, y: -35), CGPoint(x: -56, y: -5), CGPoint(x: -10, y: 20),
CGPoint(x: -5, y: 37)])
path.closeSubpath()
polygonalSpaceShip.physicsBody = SKPhysicsBody(polygonFrom: path)