ARKit series of articles directory
Ray Wenderlich’s ARKit by Tutorials is a summary of his reading notes
In this article, we’ll learn about some of the special physics in SceneKit using an example of a Monster Truck mini-game. What you didn’t know :SceneKit has real vehicle physics built in!
The basic structure
There are three parts: Body, Axle and Wheel.
Assemble it in the SceneKit editor:
Note that the wheels are attached to the real Axle by a Axle.
Load these parts in the code:
/ / 1
let truckScene = SCNScene(
named: "MonsterTruck.scnassets/Models/MonsterTruck.scn")!
truckNode = truckScene.rootNode.childNode(
withName: "Truck", recursively: true)
wheelFLNode = truckScene.rootNode.childNode(
withName: "Wheel_FL", recursively: true)
wheelFRNode = truckScene.rootNode.childNode(
withName: "Wheel_FR", recursively: true)
wheelRLNode = truckScene.rootNode.childNode(
withName: "Wheel_RL", recursively: true)
wheelRRNode = truckScene.rootNode.childNode(
withName: "Wheel_RR", recursively: true)
/ / 2
truckNode.addChildNode(wheelFLNode!)
truckNode.addChildNode(wheelFRNode!)
truckNode.addChildNode(wheelRLNode!)
truckNode.addChildNode(wheelRRNode!)
/ / 3
truckNode.isHidden = true
sceneView.scene.rootNode.addChildNode(truckNode)
Copy the code
Added vehicle physics
SceneKit has dedicated physics effects:
- SCNPhysicsVehicle: Makes a standard physical vehicle behave like a car.
- SCNPhysicsBody: The standard physical form under normal circumstances. It’s used on things like car bodies. This type of shape will be during the creation process
SCNPhysicsVehicle
Type. - SCNPhysicsVehicleWheel: a dedicated physical body that simulates not only the behavior of the wheel, but also the appearance and other physical properties. This type of shape will be during the creation process
SCNPhysicsVehicle
Type.
Select Truch node and make the Settings as shown below:
Create wheel physics
Define some constants and assign them to the SCNPhysicsVehicleWheel node.
let wheelRadius: CGFloat = 0.04
let wheelFrictionSlip: CGFloat = 0.9
let suspensionMaxTravel: CGFloat = 4.0
let suspensionMaxForce: CGFloat = 100
let suspensionRestLength: CGFloat = 0.08
let suspensionDamping: CGFloat = 2.0
let suspensionStiffness: CGFloat = 2.0
let suspensionCompression: CGFloat = 4.0
func createPhysicsVehicleWheel(wheelNode: SCNNode, position: SCNVector3) -> SCNPhysicsVehicleWheel {
let wheel = SCNPhysicsVehicleWheel(node: wheelNode)
wheel.connectionPosition = position
wheel.axle = SCNVector3(x: -1.0, y: 0, z: 0)
wheel.maximumSuspensionTravel = suspensionMaxTravel
wheel.maximumSuspensionForce = suspensionMaxForce
wheel.suspensionRestLength = suspensionRestLength
wheel.suspensionDamping = suspensionDamping
wheel.suspensionStiffness = suspensionStiffness
wheel.suspensionCompression = suspensionCompression
wheel.radius = wheelRadius
wheel.frictionSlip = wheelFrictionSlip
return wheel
}
Copy the code
The meaning of each constant:
- Wheel Radius: indicates the actual Radius of the physical appearance of a Wheel.
- Wheel Friction Slip: Specifies the Friction force between the Wheel itself and the contact surface.
- Suspension Maximum Travel Defines the Maximum Travel allowed by the wheel along the connection point. The units are centimeters.
- Suspension Maximum Force: defines the Maximum Force of the Suspension wheels and body. It’s in Newtons.
- Suspension Rest Length: Defines the Length of the Suspension at Rest. It’s in meters.
- Suspension Damping: Defines the Damping coefficient of the Suspension during oscillation.
- Define the spring coefficient between the wheel itself and the chassis of the vehicle.
- Suspension Compression: defines the speed at which the Suspension returns to the resting state after Compression.
Full vehicle physics
Attach the wheels to the body of the car and use physics:
func createVehiclePhysics(a) {
/ / 1
ifphysicsVehicle ! =nil {
sceneView.scene.physicsWorld.removeBehavior(physicsVehicle)
}
/ / 2
letwheelFL = createPhysicsVehicleWheel( wheelNode: wheelFLNode! , position:SCNVector3(x: -0.07, y: 0.04, z: 0.06))
letwheelFR = createPhysicsVehicleWheel( wheelNode: wheelFRNode! , position:SCNVector3(x: 0.07, y: 0.04, z: 0.06))
letwheelRL = createPhysicsVehicleWheel( wheelNode: wheelRLNode! , position:SCNVector3(x: -0.07, y: 0.04, z: -0.06))
letwheelRR = createPhysicsVehicleWheel( wheelNode: wheelRRNode! , position:SCNVector3(x: 0.07, y: 0.04, z: -0.06))
/ / 3
physicsVehicle = SCNPhysicsVehicle( chassisBody: truckNode.physicsBody! , wheels: [wheelFL, wheelFR, wheelRL, wheelRR])/ / 4
sceneView.scene.physicsWorld.addBehavior(physicsVehicle)
}
Copy the code
Place the vehicle on top of the focusNode in the focus frame:
func updatePositions(a) {
/ / 1
self.truckNode.position = self.focusNode.position
self.truckNode.position.y += 0.20
/ / 2
self.truckNode.physicsBody? .velocity =SCNVector3Zero
self.truckNode.physicsBody? .angularVelocity =SCNVector4Zero
/ / 3
self.truckNode.physicsBody? .resetTransform() }Copy the code
In addition, there are adding ground, setting up the game state and so on.
Add the engine force
We want the user to accelerate when they click on the screen and slow down when they release it
var maximumSpeed: CGFloat = 2.0
var isThrottling = false
var engineForce: CGFloat = 0
let defaultEngineForce: CGFloat = 10.0
var brakingForce: CGFloat = 0
let defaultBrakingForce: CGFloat = 0.01
override func touchesBegan(_ touches: Set<UITouch>,
with event: UIEvent?) {
isThrottling = true
}
override func touchesEnded(_ touches: Set<UITouch>,
with event: UIEvent?) {
isThrottling = false
}
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
DispatchQueue.main.async {
self.updateStatus()
self.updateFocusNode()
self.updateVehiclePhysics()
}
}
func updateVehiclePhysics(a) {
/ / 1
guard self.gameState == .playGame else { return }
/ / 2
if isThrottling {
engineForce = defaultEngineForce
brakingForce = 0
} else {
engineForce = 0
brakingForce = defaultBrakingForce
}
// 3 The apply method is provided by SCNPhysicsVehicle
physicsVehicle.applyEngineForce(engineForce, forWheelAt: 0)
physicsVehicle.applyEngineForce(engineForce, forWheelAt: 1)
physicsVehicle.applyEngineForce(engineForce, forWheelAt: 2)
physicsVehicle.applyEngineForce(engineForce, forWheelAt: 3)
physicsVehicle.applyBrakingForce(brakingForce, forWheelAt: 0)
physicsVehicle.applyBrakingForce(brakingForce, forWheelAt: 1)
physicsVehicle.applyBrakingForce(brakingForce, forWheelAt: 2)
physicsVehicle.applyBrakingForce(brakingForce, forWheelAt: 3)
// Limit Speed
if self.physicsVehicle.speedInKilometersPerHour >
CGFloat(maximumSpeed) {
engineForce = CGFloat(0.0)}}Copy the code
Control the direction
You can use the CoreMotion frame to control the direction of the vehicle.
let motionManager = CMMotionManager(a)let steeringClamp: CGFloat = 0.6
var steeringAngle: CGFloat = 0
func updateSteeringAngle(acceleration: CMAcceleration) {
steeringAngle = (CGFloat)(acceleration.y)
if steeringAngle < -steeringClamp {
steeringAngle = -steeringClamp;
} else ifsteeringAngle > steeringClamp { steeringAngle = steeringClamp; }}func startAccelerometer(a) {
/ / 1
guard motionManager.isAccelerometerAvailable else { return }
/ / 2
motionManager.accelerometerUpdateInterval = 1/60.0
/ / 3
motionManager.startAccelerometerUpdates(
to: OperationQueue.main,
withHandler: { (accelerometerData: CMAccelerometerData? , error:Error?).in
self.updateSteeringAngle(acceleration: accelerometerData! .acceleration) }) }func stopAccelerometer(a) {
motionManager.stopAccelerometerUpdates()
}
Copy the code
In addition, you need to add it to the updateVehiclePhysics() method, which is also the system’s own way of handling vehicle steering:
physicsVehicle.setSteeringAngle(steeringAngle, forWheelAt: 0)
physicsVehicle.setSteeringAngle(steeringAngle, forWheelAt: 1)
Copy the code
Part five Reading notes end! Look forward to the second edition of the reading notes.
ARKit was launched at WWDC2017, and spring 2018 saw version 1.5 of ARKit. The first edition of ARKit by Tutorials was written before WWDC2018, so the first edition of ARKit by Tutorials was relatively simple and did not mention ARKit New 2.0 features: world maps, image tracking,3D object detection, etc. The second update was released in fall 2018, adding two chapters of ARKit 2.0 Demo and explanation, and I will continue to update the book notes series.