前回、SceneKitの3次元世界がどの様に構築されているかを確認しました。
今回は、SceneKitの世界に重力や、あたり判定などの物理シュミレーションを設定していきたいと思います。
球体に重力を設定する
ノードに設定するプロパティのうち、Geometryがカタチや表面の色を、物理情報はPhysicsBodyが担当しています。
ここで球体ノードにPhysicsBodyを設定していきます。
PhysicsBodyで物理情報を設定
PhysicsBodyの種類は下記3つ。
- Static : 静止物
- Dynamic : 動く
- Kinematic : 単体だと動かないけど、他の物体の影響で動く
今回はDynamicを選択します。
その他の物理情報のパラメータも設定していきます。
- Restitution: 衝突時のエネルギーの増減 (反発)
- Friction: 摩擦の値を設定。摩擦0だと、滑り続ける。
- PhysicsShape: 物理シュミレーション時の物体のカタチ (衝突時の当たり判定など)
詳細は公式リファレンスを参照
https://developer.apple.com/documentation/scenekit/scnphysicsbody
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
func generateBall() {
//ジオメトリを設定
let ball: SCNGeometry = SCNSphere(radius: 0.4)
ball.firstMaterial?.diffuse.contents = [UIColor.red, UIColor.blue, UIColor.white].shuffled().first
//Body情報を設定
let physicsShape = SCNPhysicsShape(geometry: ball, options: nil)
let ballBody = SCNPhysicsBody(type: .dynamic, shape: nil)
ballBody.restitution = 1.0
ballBody.physicsShape = physicsShape
//ノードを設定
let ballNode = SCNNode(geometry: ball)
ballNode.position.x = Float.random(in: –5 ... 5)
ballNode.position.y = 10
//Body情報をノードにセット
ballNode.physicsBody = ballBody
scene.rootNode.addChildNode(ballNode)
}
|
床を固定する
球体を受け止める床も設定。
床は動かさないので、PhysicsBodyはStaticにします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
func setFloor() {
//ジオメトリを設定
let floor: SCNFloor = SCNFloor()
floor.reflectivity = 0.1
//Body情報を設定
let floorShape = SCNPhysicsShape(geometry: floor, options: nil)
let floorBody = SCNPhysicsBody(type: .static, shape: floorShape)
//ノードを設定
let floorNode = SCNNode(geometry: floor)
//Body情報をノードにセット
floorNode.physicsBody = floorBody
scene.rootNode.addChildNode(floorNode)
}
|
全体のコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
import UIKit
import SceneKit
class ViewController: UIViewController {
@IBOutlet weak var sceneView: SCNView!
var scene: SCNScene!
override func viewDidLoad() {
super.viewDidLoad()
scene = SCNScene()
self.sceneView.scene = scene
sceneView.autoenablesDefaultLighting = true
setCamera()
setFloor()
setTimer()
}
@objc func update(tm: Timer) {
generateBall()
}
func setTimer() {
let timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
timer.fire()
}
func setFloor() {
let floor: SCNFloor = SCNFloor()
floor.reflectivity = 0.1
let floorShape = SCNPhysicsShape(geometry: floor, options: nil)
let floorBody = SCNPhysicsBody(type: .static, shape: floorShape)
let floorNode = SCNNode(geometry: floor)
floorNode.physicsBody = floorBody
scene.rootNode.addChildNode(floorNode)
}
func setCamera() {
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 1, z: 20)
scene.rootNode.addChildNode(cameraNode)
}
func generateBall() {
let ball: SCNGeometry = SCNSphere(radius: 0.4)
ball.firstMaterial?.diffuse.contents = [UIColor.red, UIColor.blue, UIColor.white].shuffled().first
let physicsShape = SCNPhysicsShape(geometry: ball, options: nil)
let ballBody = SCNPhysicsBody(type: .dynamic, shape: nil)
ballBody.restitution = 1.0
ballBody.physicsShape = physicsShape
let ballNode = SCNNode(geometry: ball)
ballNode.position.x = Float.random(in: –5 ... 5)
ballNode.position.y = 10.0
ballNode.physicsBody = ballBody
scene.rootNode.addChildNode(ballNode)
}
}
|
実行
無事、球体ノードに重力が追加されました。
次回は、球体同士がぶつかった際のインタラクションや、音なども設定して、ゲームっぽくしていきたいと思います。
コメント