物理行为
本节学习任务
掌握SceneKit游戏框架中的物理行为。
物理行为的定义
定义一个或多个物理组织的高级行为,行为包括连接多个物体的关节,可以让他们一起移动,也可以定义车轮这种行为,让身体想骑车一样滚动。
相关的类(SCNPhysicsBehavior)
你不会直接使用这个类,你实例化这个类的一个子类,定义你想要的行为,并且添加到物理世界去。我去在文档中找,有这样一句话 SCNPhysicsBehavior is an abstract class that represents a behavior in the physics world.
看来这个类是物理行为的一个基类,这个类是一个抽象的类,我们没法设置它的属性,但是它有四个子类,我们就从它的四个子类入手,去发掘子类的作用。
SCNPhaysicBehavior 子类的介绍
a.SCNPhysicsHingeJoint
作用:连接两个物体,并允许他们在一个单一的轴上围绕对方转动
b.SCNPhysicsBallSocketJoint
作用:连接两个物体,并允许他们在任何方向上围绕对方转动
c.SCNPhysicsSliderJoint
作用:连接两个物体,并允许他们彼此之间滑动或旋转。滑块关节像电机一样工作,在两个物理身体之间施加力或转矩。
d.SCNPhysicsVehicle
作用:组合物理身体成为类似汽车底盘的东西,你可以控制汽车的驾驶,刹车和加速。使用SCNPhysicsVehicleWheel 对象定义车轮的外观和物理属性。
使用步骤
- 创建一个或者多个SCNPhysicsBody 绑定他们到每个节点上,作为物理行为的执行者。
- 创建配置上面列表中的行为
- 使用物理世界(SCNPhysicsWorld)的方法addBehavior: 添加到行为到物理世界中去。
在进入下一个话题,有必要介绍一个方法
@interface SCNPhysicsHingeJoint : SCNPhysicsBehavior
+ (instancetype)jointWithBodyA:(SCNPhysicsBody *)bodyA axisA:(SCNVector3)axisA anchorA:(SCNVector3)anchorA bodyB:(SCNPhysicsBody *)bodyB axisB:(SCNVector3)axisB anchorB:(SCNVector3)anchorB;
参数: bodyA bodyB 物理身体没啥好说的. axisA axisB 沿着哪个轴转动,比如(1,0,0)沿着X轴转动 anchorA anchorB 锚点A,锚点B。有些几何体的锚点不在几何体的中心,比如字体的这样几何体,它的锚点在左下角,使用时请注意一下。
import UIKit
import SceneKit
class Test13VC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scnView = SCNView(frame: view.bounds)
scnView.backgroundColor = UIColor.black
scnView.allowsCameraControl = true
scnView.scene = SCNScene()
view.addSubview(scnView)
let camera = SCNCamera()
let cameraNode = SCNNode()
cameraNode.camera = camera
camera.automaticallyAdjustsZRange = true
cameraNode.position = SCNVector3Make(0, 10, 20)
scnView.scene?.rootNode.addChildNode(cameraNode)
let floor = SCNFloor()
floor.firstMaterial?.diffuse.contents = UIColor.brown
let floorNode = SCNNode(geometry: floor)
floorNode.physicsBody = SCNPhysicsBody(type: .static, shape: nil)
scnView.scene?.rootNode.addChildNode(floorNode)
let box = SCNBox(width: 3, height: 3, length: 3, chamferRadius: 0)
box.firstMaterial?.diffuse.contents = "art.scnassets/2.jpg"
let boxNode = SCNNode(geometry: box)
boxNode.position = SCNVector3Make(0, 50, 0)
boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape.init(geometry: SCNBox.init(width: 3, height: 3, length: 3, chamferRadius: 0), options: nil))
scnView.scene?.rootNode.addChildNode(boxNode)
let ball = SCNSphere(radius: 1.5)
ball.firstMaterial?.diffuse.contents = "art.scnassets/earth/earth1.jpg"
let ballNode = SCNNode(geometry: ball)
ballNode.position = SCNVector3Make(0, 45, 0)
ballNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape.init(geometry: SCNSphere.init(radius: 1.5), options: nil))
scnView.scene?.rootNode.addChildNode(ballNode)
let cylinder = SCNCylinder(radius: 1.5, height: 3)
cylinder.firstMaterial?.diffuse.contents = "art.scnassets/1.jpg"
let cylinderNode = SCNNode(geometry: cylinder)
cylinderNode.position = SCNVector3Make(0, 40, 0)
cylinderNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape.init(geometry: SCNCylinder(radius: 1.5, height: 3), options: nil))
scnView.scene?.rootNode.addChildNode(cylinderNode)
//创建物理身体之前的物理行为
let joint1 = SCNPhysicsHingeJoint(bodyA: boxNode.physicsBody!, axisA: SCNVector3Make(0, 1, 0), anchorA: SCNVector3Make(0, -0.5, 0), bodyB: ballNode.physicsBody!, axisB: SCNVector3Make(0, 1, 0), anchorB: SCNVector3Make(0, 0.5, 0))
// 将物理行为添加物理世界中去
scnView.scene?.physicsWorld.addBehavior(joint1)
let joint2 = SCNPhysicsHingeJoint(bodyA: ballNode.physicsBody!, axisA: SCNVector3Make(0, 1, 0), anchorA: SCNVector3Make(0, -0.5, 0), bodyB: cylinderNode.physicsBody!, axisB: SCNVector3Make(0, 1, 0), anchorB: SCNVector3Make(0, 0.5, 0))
scnView.scene?.physicsWorld.addBehavior(joint2)
}
}