Class

SKPhysicsBody

An object which adds physics simulation to a node.

Overview

Assign a SKPhysicsBody object to the physicsBody property of the SKNode object to add physics simulation to the node. When a scene processes a new frame, it performs physics calculations on physics bodies attached to nodes in the scene. These calculations include gravity, friction, and collisions with other bodies. You can also apply your own forces and impulses to a body. After the scene completes these calculations, it updates the positions and orientations of the node objects.

SpriteKit supports two kinds of physics bodies, volume-based bodies and edge-based bodies. When you create a physics body, its kind, size, and shape are determined by the constructor method you call. An edge-based body does not have mass or volume and is unaffected by forces or impulses in the system. Edge-based bodies are used to represent volume-less boundaries or hollow spaces in your physics simulation. In contrast, volume-based bodies are used to represent objects with mass and volume. The isDynamic property controls whether a volume-based body is affected by gravity, friction, collisions with other objects, and forces or impulses you directly apply to the object.

The SKPhysicsBody class defines the physical characteristics for the body when it is simulated by the scene. For volume-based bodies, the most important property is the mass property. A volume-based body is assumed to have a uniform density. You can either set the mass property directly, or you can set the body’s density property and let the physics body calculate its own mass. All values in Sprite Kit are specified using the International System of Units (SI units). The actual forces and mass values are not important so long as your game uses consistent values.

When you design a game that uses physics, you define the different categories of physics objects that appear in the scene. You define up to 32 different categories of physics bodies, and a body can be assigned to as many of these categories as you want. In addition to declaring its own categories, a physics body also declares which categories of bodies it interacts with. See Working with Collisions and Contacts. You use a similar mechanism to declare which physics field nodes (SKFieldNode) can affect the physics body.

For a volume-based body, you can dynamically control how the body is affected by forces or collisions. See Defining How Forces Affect a Physics Body.

All Physics is Simulated on Physics Bodies

An SKPhysicsBody object defines the shape and simulation parameters for a physics body in the system. When the scene simulates physics, it performs the calculations for all physics bodies connected to the scene tree. So, you create an SKPhysicsBody object, configure its properties, and then assign it to a node’s physicsBody property.

There are three kinds of physics bodies:

  • A dynamic volume simulates a physical object with volume and mass that can be affected by forces and collisions in the system. Use dynamic volumes to represent items in the scene that need to move around and collide with each other.

  • A static volume is similar to a dynamic volume, but its velocity is ignored and it is unaffected by forces or collisions. However, because it still has volume, other objects can bounce off it or interact with it. Use static volumes to represent items that take up space in the scene, but that should not be moved by the simulation. For example, you might use static volumes to represent the walls of a maze. While it is useful to think of static and dynamic volumes as distinct entities, in practice these are two different modes you can apply to any volume-based physics body. This can be useful because you can selectively enable or disable effects for a body.

  • An edge is a static volume-less body. Edges are never moved by the simulation and their mass doesn’t matter. Edges are used to represent negative space within a scene (such as a hollow spot inside another entity) or an uncrossable, invisibly thin boundary. For example, edges are frequently used to represent the boundaries of your scene. The main difference between a edge and a volume is that an edge permits movement inside its own boundaries, while a volume is considered a solid object. If edges are moved through other means, they only interact with volumes, not with other edges.

SpriteKit provides a few standard shapes, shapes based on arbitrary paths and shapes generated from the alpha channel of a texture. shows the shapes available.

Creating physics bodies for a sprite node

shows the code used to generate the four physics bodies illustrated above:

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

The shape of a physics body affects performance. A circular physics body offers the best performance and can be significantly faster than other physics bodies. If your simulation contains many physics bodies, circular bodies are the best solution. Rectangular then polygonal shapes improve collision accuracy with reduced speed. Physics bodies created from the alpha channel of a texture offer the best fidelity at the expense of highest computational cost.

Creating Physics Bodies

A physics body is created by calling one of the SKPhysicsBody class methods. Each class method defines whether a volume-based or edge-based body is being created and what shape it has.

Creating and Assigning Physics Bodies

As soon as a node has its physics body set and is added to a scene, it begins to participate in the physics simulation. The following code shows how to create a simple scene containing a shape node that is the curvy ground and a sprite node — the elephant. The shape node’s physics body is created from its path and the sprite node’s physics body is created from the texture automatically generated by SpriteKit when the node was initialized. Because the ground node has its isDynamic set to false, it is not affected by gravity and remains stationary.

Listing 1

Creating and assigning physics bodies

// Create the elephant node and physics body
let spriteNode = SKSpriteNode(imageNamed: “elephant”)
spriteNode.position = CGPoint(x: 320, y: 320)
spriteNode.physicsBody = SKPhysicsBody(texture: spriteNode.texture!,
                                       size: spriteNode.texture!.size())
spriteNode.physicsBody?.usesPreciseCollisionDetection = true
     
// Create the ground node and physics body
var splinePoints = [CGPoint(x: 0, y: 500),
                    CGPoint(x: 100, y: 50),
                    CGPoint(x: 400, y: 110),
                    CGPoint(x: 640, y: 20)]
let ground = SKShapeNode(splinePoints: &splinePoints,
                         count: splinePoints.count)
ground.lineWidth = 5
ground.physicsBody = SKPhysicsBody(edgeChainFrom: ground.path!)
ground.physicsBody?.restitution = 0.75
ground.physicsBody?.isDynamic = false
     
// Add the two nodes to the scene
scene.addChild(spriteNode)
scene.addChild(ground)

After running for a few moments, the above code creates a scene that looks like the illustration in Figure 1 — the sprite node has come to rest in one of the valleys of the curvy ground line:

Figure 1

Physics body from texture at rest

Physics body from texture at rest

Use a Physics Shape That Matches the Graphical Representation

In most cases, a physics body should have a size and shape that closely approximates the visual representation of the corresponding node. For example, in Figure 2, the rocket has a narrow shape that is not well represented by either a circle or a rectangle. A convex polygon shape is chosen and fitted to match the sprite’s artwork.

Figure 2

Match the shape with a close representation

Match the shape with a close representation

If you do not want to create your own shapes, you can use SpriteKit to create a shape for you based on the sprite’s texture.

let sprite = SKSpriteNode(imageNamed: "Spaceship")
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!,
                                   size: sprite.texture!.size())

When choosing a shape for your physics body, do not be overly precise. More complex shapes require more work to be properly simulated. For volume-based bodies, use the following guidelines:

  • A circle is the most efficient shape (init(circleOfRadius:))

  • A path-based polygon is the least efficient shape, and the computational work scales with the complexity of the polygon (init(polygonFrom:))

An edge-based body is more expensive to compute than a volume-based body. This is because the bodies it interacts with can potentially be on either side of an open edge or on the inside or outside of a closed shape. Use these guidelines:

Creating an Edge Loop Around the Scene

The following shows code that is used frequently in games that do not need to scroll the content. In this case, the game wants physics bodies that hit the borders of the scene to bounce back into the gameplay area:

Listing 3

A scene border

func createSceneContents() {
    self.backgroundColor = .black
    self.scaleMode = .aspectFit
    self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
}

Configuring the Physical Properties of a Physics Body

The SKPhysicsBody class defines properties that determine how the physics body is simulated. These properties affect how the body reacts to forces, what forces it generates on itself (to simulate friction), and how it reacts to collisions in the scene. In most cases, the properties are used to simulate physical effects.

Each individual body also has its own property values that determine exactly how it reacts to forces and collisions in the scene. Here are the most important properties:

  • The mass property determines how forces affect the body, as well as how much momentum the body has when it is involved in a collision.

  • The friction property determines the roughness of the body’s surface. It is used to calculate the frictional force that a body applies to other bodies moving along its surface.

  • The linearDamping and angularDamping properties are used to calculate friction on the body as it moves through the world. For example, this might be used to simulate air or water friction.

  • The restitution property determines how much energy a body maintains during a collision—its bounciness.

Other properties are used to determine how the simulation is performed on the body itself:

  • The isDynamic property determines whether the body is simulated by the physics subsystem.

  • The affectedByGravity property determines whether the simulation exerts a gravitational force on the body. For more information on the physics world, see Configuring the Physics World.

  • The allowsRotation property determines whether forces can impart angular velocity on the body.

Mass Determines a Body’s Resistance to Acceleration

You should set the mass on every volume-based body in your scene so that it properly reacts to forces applied to it.

A physics body’s mass, area, and density properties are all interrelated. When you first create a body, the body’s area is calculated, and never changes afterwards. The other two properties change values at the same time, based on the following formula:

mass = density x area

When you configure a physics body, you have two options:

• Set the mass property of the body. The density property is then automatically recalculated. This approach is most useful when you want to precisely control each body’s mass.

• Set the density property of the body. The mass property is then automatically recalculated. This approach is most useful when you have a collection of similar bodies created with different sizes. For example, if your physics bodies were used to simulate asteroids, you might give all asteroids the same density, and then set an appropriate bounding polygon for each. Each body automatically computes an appropriate mass based on its size on the screen.

When to Adjust a Body’s Properties

Most often, you configure a physics body once and then never change it. For example, the mass of a body is unlikely to change during play. However, you are not restricted from doing so. Some kinds of games may require the ability to adjust a body’s properties even while the simulation is executing. Here are a few examples of when you might do so:

  • In a realistic rocket simulation, the rocket expends fuel to apply thrust. As fuel is used up, the mass of the rocket changes. To implement this in SpriteKit, you might create a rocket class that includes a fuel property. When the rocket thrusts, the fuel is reduced and the corresponding body’s mass is recalculated.

  • The damping properties are usually based on the body’s characteristics and the medium it is traveling through. For example, a vacuum applies no damping forces, and water applies more damping forces than air. If your game simulates multiple environments and bodies can move between those environments, your game can update a body’s damping properties whenever it enters a new environment.

Typically, you make these changes as part of scene pre- and post-processing using the SKSceneDelegate methods.

Rotating Physics Bodies

A common task in a physics is to pin bodies together. Pinning locks the position of an object but allows it to rotate - for example fixing a wheel to a vehicle. SpriteKit offers two options for pinning physics bodies — either using the pinned property or creating an SKPhysicsJointPin joint.

The following code shows how you can implement the simpler method: using the pinned property. The code creates a sprite node with an image of a pendulum (two circles of different sizes joined by a center rod). A physics body is created based on the generated texture, has its pinned set to true, and assigned to the node. The node is rotated 90 degrees — to align horizontally — so that gravity pulls the heavier end towards the ground.

let pinned = SKSpriteNode(imageNamed: "pendulum")
  
pinned.physicsBody = SKPhysicsBody(texture: pinned.texture!,
                                   size: pinned.size)
pinned.position = CGPoint(x: 320,
                          y: 320)
pinned.zRotation = CGFloat.pi / 2
pinned.physicsBody?.pinned = true
  
scene.addChild(pinned)

Since the node’s physics body is pinned, it stays in position but rotates around its center.

The following code shows how you create a similar scene, but using a physics joint. In this example, a static anchor is created and added to the scene. The sprite node is added as a child of the anchor node and a SKPhysicsJointPin joins the two together:

let anchor = SKNode()
  
anchor.position = CGPoint(x: 320,
                          y: 320)
anchor.zRotation = CGFloat.pi / 2
anchor.physicsBody = SKPhysicsBody()
anchor.physicsBody?.isDynamic = false
  
let jointed = SKSpriteNode(imageNamed: “pendulum”)
jointed.physicsBody = SKPhysicsBody(texture: pinned.texture!,
                                    size: pinned.size)
  
scene.addChild(anchor)
anchor.addChild(jointed)
  
let pinJoint = SKPhysicsJointPin.joint(withBodyA: anchor.physicsBody!,
                                       bodyB: jointed.physicsBody!,
                                       anchor: anchor.position)
scene.physicsWorld.add(pinJoint)

The resulting scenes behave identically.

The advantage of the first approach is simplicity: it requires less code and, if you don’t need to limit or control the speed of the rotation is the preferred solution. However, using a physics joint offers more functionality: you have control over the anchor point, you can limit the rotation angles with lowerAngleLimit and upperAngleLimit, and you can define the rotation speed with rotationSpeed. If you wish to simulate friction, the physics body’s angularDamping property is analogous to the joint’s frictionTorque property.

Other Related Physics Classes

A scene’s physicsWorld property holds an SKPhysicsWorld object that provides physics characteristics that affect the entire scene.

You can use fields to apply forces to a set of physics bodies or to change their velocities. See SKFieldNode.

You can connect physics bodies together using joints. See SKPhysicsJoint.

Symbols

Creating Volume-Based Physics Bodies

init(circleOfRadius: CGFloat)

Creates a circular physics body centered on the owning node’s origin.

init(circleOfRadius: CGFloat, center: CGPoint)

Creates a circular physics body centered on an arbitrary point.

init(rectangleOf: CGSize)

Creates a rectangular physics body centered on the owning node’s origin.

init(rectangleOf: CGSize, center: CGPoint)

Creates a rectangular physics body centered on an arbitrary point.

init(bodies: [SKPhysicsBody])

Creates a physics body by performing a union of a group of volume-based physics bodies.

init(polygonFrom: CGPath)

Creates a polygon-shaped physics body.

init(texture: SKTexture, size: CGSize)

Creates a physics body from the contents of a texture.

init(texture: SKTexture, alphaThreshold: Float, size: CGSize)

Creates a physics body from the contents of a texture, capturing only the texels that exceed a specified transparency value.

Creating Edge-Based Physics Bodies

init(edgeLoopFrom: CGRect)

Creates an edge loop from a rectangle.

init(edgeFrom: CGPoint, to: CGPoint)

Creates an edge between two points.

init(edgeLoopFrom: CGPath)

Creates an edge loop from a path.

init(edgeChainFrom: CGPath)

Creates an edge chain from a path.

Defining How Forces Affect a Physics Body

var affectedByGravity: Bool

A Boolean value that indicates whether this physics body is affected by the physics world’s gravity.

var allowsRotation: Bool

A Boolean value that indicates whether the physics body is affected by angular forces and impulses applied to it.

var isDynamic: Bool

A Boolean value that indicates whether the physics body is moved by the physics simulation.

Defining a Body’s Physical Properties

var mass: CGFloat

The mass of the body in kilograms.

var density: CGFloat

The density of the object in kilograms per square meter.

var area: CGFloat

The area covered by the body.

var friction: CGFloat

The roughness of the surface of the physics body.

var restitution: CGFloat

The bounciness of the physics body.

var linearDamping: CGFloat

A property that reduces the body’s linear velocity.

var angularDamping: CGFloat

A property that reduces the body’s rotational velocity.

Working with Collisions and Contacts

When two physics bodies come into contact or attempt to occupy the same space, SpriteKit supports two kinds of interaction between them:

  • A contact is used when you need to know that two bodies are touching each other. In most cases, you use contacts when you need to make gameplay changes when a collision occurs.

  • A collision is used to prevent two objects from interpenetrating each other. When one body strikes another body, SpriteKit automatically computes the results of the collision and applies impulse to the bodies in the collision.

Your game configures the physics bodies in the scene to determine when collisions should occur and when interactions between physics bodies require additional game logic to be performed. Limiting these interactions is not only important for defining your game’s logic, it is also necessary in order to get good performance from SpriteKit. SpriteKit uses two mechanisms to limit the number of interactions in each frame:

  • Edge-based physics bodies never interact with other edge-based bodies. This means that even if you move edge-based bodies by repositioning the nodes, the physics bodies never collide or contact each other.

  • Every physics body is categorized. Categories are defined by your app; each scene can have up to 32 categories. When you configure a physics body, you define which categories it belongs to and which categories of bodies it wants to interact with. Contacts and collisions are specified separately.

The following code creates a red and a blue ball, and a ground object constructed from a series of points. By giving the red ball a collisionBitMask that matches the ground’s categoryBitMask, the red ball bounces off it. However, the blue ball’s collisionBitMask is set to a different value and doesn’t interact with the ground:

Listing 4

Controlling collisions with masks

let ballRadius: CGFloat = 20
let redBall = SKShapeNode(circleOfRadius: ballRadius)
redBall.fillColor = .red
redBall.position = CGPoint(x: 280, y: 320)
redBall.physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)

let blueBall = SKShapeNode(circleOfRadius: ballRadius)
blueBall.fillColor = .blue
blueBall.position = CGPoint(x: 360, y: 320)
blueBall.physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)

var splinePoints = [CGPoint(x: 0, y: 300),
                    CGPoint(x: 100, y: 50),
                    CGPoint(x: 400, y: 110),
                    CGPoint(x: 640, y: 20)]
let ground = SKShapeNode(splinePoints: &splinePoints,
                         count: splinePoints.count)
ground.physicsBody = SKPhysicsBody(edgeChainFrom: ground.path!)
ground.physicsBody?.restitution = 0.75

redBall.physicsBody?.collisionBitMask = 0b0001
blueBall.physicsBody?.collisionBitMask = 0b0010
ground.physicsBody?.categoryBitMask = 0b0001

Figure 3 illustrates the paths taken by both balls when the code above is executed.

Figure 3

Paths taken by nodes with different collision bit masks

Paths taken by nodes with different collision bit masks
var categoryBitMask: UInt32

A mask that defines which categories this physics body belongs to.

var collisionBitMask: UInt32

A mask that defines which categories of physics bodies can collide with this physics body.

var usesPreciseCollisionDetection: Bool

A Boolean value that determines whether the physics world uses a more precise collision detection algorithm.

var contactTestBitMask: UInt32

A mask that defines which categories of bodies cause intersection notifications with this physics body.

func allContactedBodies()

The physics bodies that this physics body is in contact with.

Applying Forces and Impulses to a Physics Body

Making Physics Bodies Move

By default, only gravity is applied to physics bodies in the scene. In some cases, that might be enough to build a game. But in most cases, you need to take other steps to change the speed of physics bodies.

First, you can control a physics body’s velocity directly, by setting its velocity and angularVelocity properties. As with many other properties, you often set these properties once when the physics body is first created and then let the physics simulation adjust them as necessary. For example, assume for a moment you are making a space-based game where a rocket ship can fire missiles. When the ship fires a missile, the missile should have a starting velocity of the ship plus an additional vector in the direction of the launch. The following code shows one implementation for calculating the launch velocity.

Listing 5

Calculating the missile’s initial velocity

missile.physicsBody?.velocity = self.physicsBody!.velocity
missile.physicsBody?.applyImpulse(CGVector(dx: missileLaunchImpulse * cos(shipDirection),
                                           dy: missileLaunchImpulse * sin(shipDirection)))

When a body is in the simulation, it is more common for the velocity to be adjusted based on forces applied to the body. Another source of velocity changes, collisions, is discussed later.

The default collection of forces that apply to a body include:

  • The gravitational force applied by the physics world

  • The damping forces applied by the body’s own properties

  • A frictional force based on contact with another body in the system

You can also apply your own forces and impulses to physics bodies. Most often, you apply forces and impulses in a pre-processing step before the simulation executes. Your game logic is responsible for determining which forces need to be applied and for making the appropriate method calls to apply those forces.

You can choose to apply either a force or an impulse:

  • A force is applied for a length of time based on the amount of simulation time that passes between when you apply the force and when the next frame of the simulation is processed. So, to apply a continuous force to an body, you need to make the appropriate method calls each time a new frame is processed. Forces are usually used for continuous effects

  • An impulse makes an instantaneous change to the body’s velocity that is independent of the amount of simulation time that has passed. Impulses are usually used for immediate changes to a body’s velocity.

To continue with the rocket example, a rocket ship probably applies a force to itself when it turns on its engines. However, when it fires a missile, it might launch the missile with the rocket’s own velocity and then apply a single impulse to it to give it the initial burst of speed.

Because forces and impulses are modeling the same concept—adjusting a body’s velocity—the remainder of this section focuses on forces.

You can apply a force to a body in one of three ways:

  • A linear force that only affects the body’s linear velocity.

  • An angular force that only affects the body’s angular velocity.

  • A force applied to a point on the body. The physics simulation calculates separate changes to the body’s angular and linear velocity, based on the shape of the object and the point where the force was applied.

The following code shows code you could implement in a sprite subclass to apply a force to the ship. This force accelerates the rocket when the main engines are activated. Because the engines are at the back of the rocket, the force is applied to linearly to the rocket body. The code calculates the thrust vector based on the current orientation of the rocket. The orientation is based on the zRotation property of the corresponding node, but the orientation of the artwork may differ from the orientation of the node. The thrust should always be oriented with the artwork. The following code shows a similar effect, but this time the rocket is being rotated by the force, so the thrust is applied as an angular thrust.

Listing 6

Applying lateral thrust

self.physicsBody?.applyTorque(thrust)

func applyForce(CGVector)

Applies a force to the center of gravity of a physics body.

func applyTorque(CGFloat)

Applies a torque to an object.

func applyForce(CGVector, at: CGPoint)

Applies a force to a specific point of a physics body.

func applyImpulse(CGVector)

Applies an impulse to the center of gravity of a physics body.

func applyAngularImpulse(CGFloat)

Applies an impulse that imparts angular momentum to an object.

func applyImpulse(CGVector, at: CGPoint)

Applies an impulse to a specific point of a physics body.

Inspecting the Physics Body’s Position and Velocity

var velocity: CGVector

The physics body’s velocity vector, measured in meters per second.

var angularVelocity: CGFloat

The physics body’s angular speed.

var isResting: Bool

A Boolean property that indicates whether the object is at rest within the physics simulation.

Reading the Physics Body’s Node

var node: SKNode?

The node that this body is connected to.

Determining Which Joints Are Connected to a Physics Body

var joints: [SKPhysicsJoint]

The joints connected to this physics body.

Interacting with Physics Fields

var fieldBitMask: UInt32

A mask that defines which categories of physics fields can exert forces on this physics body.

var charge: CGFloat

The electrical charge of the physics body.

Pinning a Physics Body to the Node’s Parent

var pinned: Bool

A Boolean value that indicates whether the physics body’s node is pinned to its parent node.

Relationships

Inherits From