Exploring physics simulation mechanics
Let's take a closer look at the specifics of SpriteKit's physics system. For instance, why are the bees subject to gravity while the ground stays where it is? Though we attached physics bodies to both nodes, we actually used two different styles of physics bodies. There are three types of physics bodies, and each behaves slightly differently:
- Dynamic: Physics bodies have volume and are fully subject to forces and collisions in the system. We will use dynamic physics bodies for most parts of the game world: the player, enemies, power-ups, and others.
- Static: Physics bodies have volume but no velocity. The physics simulation does not move nodes with static bodies, but they can still collide with other game objects. We can use static bodies for walls or obstacles.
- Edge: Physics bodies have no volume and the physics simulation will never move them. They mark off the boundaries of movement; other physics bodies will never cross them. Edges can cross each other to create small containment areas.
Voluminous (dynamic and static) bodies have a variety of properties that influence how they move through space and react to collisions. This allows us to create a wide range of realistic physics effects. Each property controls one aspect of a body's physical characteristics:
- Restitution: Determines how much energy is lost when one body bounces into another. This changes the body's bounciness. SpriteKit measures restitution on a scale from 0.0 to 1.0. The default value is 0.2.
- Friction: Describes the amount of force necessary to slide one body against another body. This property also uses a scale of 0.0 to 1.0, with a default value of 0.2.
- Damping: Determines how quickly a body slows as it moves through space. You can think of damping as air friction. Linear damping determines how quickly a body loses speed, while angular damping affects rotation. Both are measured from 0.0 to 1.0, with a default value of 0.1.
- Mass: This is measured in kilograms. It describes how far colliding objects push the body and factors in momentum during movement. Bodies with more mass will move less when hit by another body and will push other bodies further when they collide with them. The physics engine automatically uses the mass and the area of the body to determine density. Alternatively, you can set the density and let the physics engine calculate mass. It is usually more intuitive to set the mass.
There are other physics-related classes as well, such as PhysicsWorld
, SKFieldNode
, and SKPhysicsJoint
.
Physics World: You don't have to create an object of the class when you create a scene, as Physics World is already part of the scene when it is created. Physics World is responsible for the simulation of the physics objects in the scene. So, in a scene in which there are physics objects, it updates the position and collision information for all the physics objects in the scene. You can add properties such as gravity to the physics world in the scene and, depending on what you set the gravity in the scene to, the objects will behave accordingly.
Physics Field Nodes: Field Nodes can apply force on objects when they enter a certain area or field. This is similar to planets in the Angry Birds game, which start pulling the birds toward them when the birds go near a planet. That is one example; there are different types of FieldNodes
that can be created and attached to scenes.
Physics Joints: Using physics joints, we can join objects together and set conditions to make them behave with each other in a certain way. There are different joint types, such as spring, limit, pin, fixed, and sliding:
- Spring Joint: The connection between the bodies is such that there is resistance between the bodies, meaning that it will take some effort to pull or push the bodies apart or together. If you pull or push the bodies and then release, they will reset to their original positions.
- Limit Joint: In this case, there is no resistance, but you can pull the bodies apart only so much, which is controlled by a limiting factor.
- Pin Joint: You can pin a body to another body so that you can only rotate the object around the other object and will not be able to pull the bodies apart.
- Fixed Joint: You fix the bodies together so that they behave like a single object.
- Sliding Joint: This only allows the movement of one body around the other object:
More about Joint Physics can be obtained from here: https://developer.apple.com/documentation/spritekit/skphysicsjoint.
All right; enough with the textbook! Let's solidify our learning with some examples.
Firstly, we want gravity to leave our bees alone. We will set their flight paths manually. We need the bees to be dynamic physics bodies in order to interact properly with other nodes, but we need these bodies to ignore gravity. For such instances, SpriteKit provides a property named affectedByGravity
. Open Bee.swift
and, at the bottom of the init
function, add this code:
self.physicsBody?.affectedByGravity = false
The question mark after physicsBody
is optional chaining. We need to unwrap physicsBody
, since it is optional. If physicsBody
is nil, the entire statement will return nil (instead of triggering an error). You can think of it as gracefully unwrapping an optional property with an inline statement.
Run the project. The bees should now hover in place, as they did before we added their bodies, however, SpriteKit's physics simulation now affects them; they will react to impulses and collisions. Great—let's purposefully make the bees collide.