##はじめに
サイコロが転がるようなアニメーションを再現します。Unityでは軸を設定してその周りの回転を行うことができるRotateAround
というメソッドが用意されていますが、SceneKittには無いようです。主な動きは↓こんな感じ。SceneKit SceneFileの使い方についても触れています。
全方向への移動ver pic.twitter.com/PwEDmYHJre
— 二次曲線 (@Hyperbolic____) August 31, 2020
##考え方のヒント・実装の流れ
- Rotateなどのメソッドはオブジェクトの座標を原点とし、回転する方向を決めて、回転を行っている
- 親と子の階層関係にあるオブジェクトは、親が動くと子も動く
- 球や立方体のような形を持たないオブジェクト(ここではemptyNodeとしている)を生成することも可能
##再現したい動きをSceneKit SceneFileで確認する
SceneFileでは、Unityのように3Dオブジェクトを実際に配置することが可能です。動きの確認だけでなく、ファイルをそのまま起動させることもできます。
では実際に回転の流れを見ていきます。
###1.boxを追加する
右上の➕からboxを選択し、ドラッグ&ドロップします。その後、position(座標)を(0,0.5,0)、size(大きさ)を(1,1,1),Eular(回転)を(0,0,0)に設定します。
###2.形を持たないnodeを追加する
右下の➕ボタンを押し、nodeを追加します。<untitled>
が追加されればOKです。(以下これをemptyNodeとします。)
右側に回転する動きを再現したいので、中心となる立方体の辺の中点にemptyNode(0.5,0,0.5)に移動します。
###3.emptyNodeの階層下にboxを配置する
階層関係にあるnodeにおいて、子nodeは親nodeの動きの影響を受けます。boxをemptyNodeの下にドラッグ&ドロップし、子nodeとして設定します。
###4.emptyNodeを回転させる
emotyNodeのz軸を-90度回転させることで、回転を表現することができます。
##SceneFileで確認した動きをコードで再現する
SCNSceneクラスを継承したGameSceneクラスを作成します。GameSceneにはboxNodeとemptyNodeをプロパティとして持たせています。また、boxNodeの座標である0,0,0.5をそれぞれx,y,zをとして定義します。
class ViewController: UIViewController {
var x = 0.0
var y = 0.5
var z = 0.0
@IBOutlet weak var test: SCNView!
let scene = GameScene()
override func viewDidLoad() {
super.viewDidLoad()
test.scene = scene
}
}
rightボタンを紐付け、動きを記述します。
@IBAction func right(_ sender: Any) {
//EmptyNodeを定義
scene.emptyNode.position = SCNVector3(x: Float(scene.boxNode.worldPosition.x+0.5), y: Float(scene.boxNode.worldPosition.y-0.5), z: Float(scene.boxNode.worldPosition.z))
scene.emptyNode.addChildNode(scene.boxNode)
scene.boxNode.worldPosition = SCNVector3(x,y,z)
let a = SCNAction.rotate(by: -CGFloat(Float.pi/2), around: SCNVector3(0,0,1), duration: 0.1)
scene.emptyNode.runAction(a)
x+=1
}
基本的にはSceneFileで確認した動きをそのまま書くだけなのですが、addChildを行うと動くことが確認されたので、最初に定義したx,y,zを用いて解決しています。