iOS

ARKit Tutorial: Understanding Physics by Launching a Rocketship


Did that just move? Is that real? That’s augmented reality. Welcome back to the fourth installment of the ARKit tutorial series. In this tutorial, we will be looking at the basics of physics inside of ARKit. We shall launch a rocketship by the end of this tutorial then celebrate like it’s the 4th of July because we can. Let’s go!

First, let’s begin by downloading the starter project here. Build and run. You should be prompted to allow camera access in the App.

physics-camera-access

Tap OK. If all goes well, you should be able to see your camera’s view.

Also just a note, this tutorial is built on top of previous knowledge from previous tutorials. If you happen to get stuck, feel free to check out the ARKit tutorial series to help you out as much as possible when needed.

Physics Body Explained

First things first, physics body. This is one of the fundamentals. In order for SceneKit to know how to simulate a SceneKit node(s) inside of our app, we need to attach it a SCNPhysicsBody. A SCNPhysicsBody is an object which adds physics simulation to a node.

SceneKit performs physics calculations to nodes with attached physics bodies in a scene before rendering a frame. These calculations include gravity, friction, and collisions with other bodies. You can also apply forces and impulses to a body. After these calculations, it updates the positions and orientations of the nodes, then renders the frame.

Basically, before each rendered frame, physics calculation.

Physics Body Types

To construct a physics body, you’d first need to specify the physics body type. A physics body determines how a physics body interacts with forces and other bodies. The three physics body types are static, dynamic, and kinematic.

Static

You’d want to use a static physics body type for SceneKit objects like floors, walls, and terrain. A static physics body type is unaffected by forces or collisions and cannot move.

Dynamic

You’d want to use a dynamic physics body type for SceneKit objects like a flying fire-breathing dragon, Steph Curry shooting a basketball, or a blasting off rocketship. Dynamic physics body is a physics body that can be affected by forces and collisions.

Kinematic

You’d want to use a kinematic physics body say when you create a game where you need to push a block with your finger. So you create an “invisible” block pusher which is triggered by your finger movement. The “invisible” block is not affected by other blocks, however the “invisible” block moves other blocks when in contact. Kinematic physics body is a physics body that is unaffected by forces or collisions, but it can cause collisions affecting other bodies when moved. Can move others, can’t be moved.

Creating a Physics Body

Let’s begin by giving our detected horizontal plane a static physics body. This way, we have a solid ground for our rocketship to stand on.

Add the following method below renderer(_:didUpdate:for:) of ViewController.swift:

In this method, we created a SCNPhysicsShape object. A SCNPhysicsShape object represents the shape of a physics body. When SceneKit detects contact for the SCNPhysicsBody objects of your scene, it uses the physics shapes you defined instead of the rendered geometry of visible objects.

Next, we created a SCNPhysicsBody object by passing .static into the type parameter and our SCNPhysicsShape object into the shape parameter.

Then, we set the node’s physics body to the physics body we created together.

Attaching a Static Physics Body

We are now going to attach a static physics body to the detected plane inside of the renderer(_:didAdd:for:) method. Call the following method right before adding planeNode as the child node:

After the change, your renderer(_:didAdd:for:) method should now look like this:

When our detected plane is updated with new information, it may change in geometry. Hence, we need to call the same method inside of render(_:didUpdate:for:):

The render(_:didUpdate:for:) method should now look like this after the modification:

Ground solid work!

Attaching a Dynamic Physics Body

Now let’s give our rocketship node a dynamic physics body because we want this node to be affected by forces and collisions. Declare a rocketship node name constant inside of the ViewController class:

Then inside the addRocketshipToSceneView(withGestureRecognizer:) method, add the following code right after adjusting the rocketship node’s position:

We gave our rocketshipNode static physics body and a name. We’ll see the name be used to identify the rocketshipNode later on. Build and run. And you should be able to see something like:

rocket-landing

Applying Force

We are now going to apply force onto our rocketship.

Before we do that, we need a way of triggering the action. We can do this with the help of aUISwipeGestureRecognizer. First, add the following method below the addRocketshipToSceneView(withGestureRecognizer:) method:

This method above will help us get the rocket ship node from the swipe location of the swipe gesture. You may be wondering why we safely unwrapped the parent node. The reason is the returned node from the hit test result could be any one of the five nodes that make up the rocketship.

rocket-ship-3dmodel

Right below the previous method, add the following method:

From the code above, we:

  1. Made sure the swipe gesture state is ended.
  2. Get hit test results from the swipe location.
  3. See if the swipe gesture was acted on the rocketship.
  4. We apply a force in the y direction to the parent node’s physics body. If you notice, we also set the impulse argument to true. This applies an instantaneous change in momentum and accelerates the physics body immediately. Basically, this option allows you to simulate an instantaneous effects like a projectile launch when set to true.

Great! Build and run. Swipe up on the rocketship. And you should be able to apply a force onto your rocketship!

rocket-jump

Adding SceneKit Particle System and Changing Physics Properties

The starter project comes with a reactor SceneKit particle system under the “Particles” folder.

explode

In this tutorial, we will not go over how to create a SceneKit particle system. We will go over how to add a SceneKit particle system onto a node and some its physics properties.

Open up ViewController.swift. Declare the following variable inside of the ViewController class:

Inside of the renderer(_:didAdd:for:) method, add the following as the method’s last line of code:

Simply, when a new plane is detected, we append it onto our plane nodes array. We are referencing the plane nodes for the reactor SceneKit particle system’s collider nodes property later on.

Right below the renderer(_:didAdd:for:) method, add implement the following delegate method:

This delegate method gets called when a SceneKit node corresponding to a removed AR anchor has been removed from the scene. At this time, we will filter the plane nodes array to only the ones that does not equal to the removed plane node.

Next, add the following method right below the applyForceToRocketship(withGestureRecognizer:) method:

In the code above, we:

  1. Made sure the swipe gesture state is ended.
  2. Safely unwrapped the rocket ship node and its physics body like before. Also, we safely unwrapped the reactor SceneKit particle system and the engine node. We want to add the reactor SceneKit particle system onto the rocketship’s engine. Hence, the interest in the engine node.
  3. Set the physics body’s *is affected by gravity *property to false and its effect is as it sounds. Gravity will no longer affect the rocketship node. We also set the damping property to zero. The damping property simulates the effect of fluid friction or air resistance on a body. Setting it it zero will result in zero effect from fluid friction or air resistance on the rocketship node’s physics body.
  4. Set the reactor particle system to collide with the plane nodes. This will make the particles from the particle system to bounce off of the detected planes when in contact instead of flying right through them.
  5. Add the reactor particle system onto the engine node.
  6. We move the rocketship node up by 0.3 meters with a ease in and ease out animation effect.

Adding Swipe Gestures

Before we can apply force and launch our rocketship, we need to add swipe gesture recognizers onto our scene view. Add the following below addTapGestureToSceneView():

A swipe up gesture will apply force onto the rocketship node. A swipe down gesture will launch the rocketship. Nice!

Last but not least, call the method inside of viewDidLoad():

That’s it!

Showtime!

Congratulations, it’s showtime. Try to swipe down and see what you get!

rocket-init

And, try to swipe down then up. Off the rocketship goes!

rocket-launch

Final Words

I hope you have enjoyed and learned something valuable from my tutorial. Feel free to share this tutorial on your social networks so that your circle can make some knowledge gains too!

For reference, you can download the sample project on GitHub.

macOS
Getting Started with macOS Programming
iOS
Introduction to Custom View Controller Transitions and Animations
iOS
A Step by Step Guide on how to Create a XCFramework and Distribute it as a Swift package
Shares