How to set physics body for a sprite with rounded

2019-08-11 17:01发布

问题:

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?

回答1:

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))


回答2:

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.



回答3:

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)