SceneKitのアニメーションサンプル集

# 移動

![6.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/0ba78da8-a901-6627-98a8-65ae3f512946.gif)

上記はARKitにて、以下のようなコードで実行されています。

```swift
private func shoot(){
    guard let camera = sceneView.pointOfView else {
       return
    }
    boxNode.position = camera.position

    let targetPosCamera = SCNVector3Make(0, 0, -2)
    let target = camera.convertPosition(targetPosCamera, to: nil)
    let action = SCNAction.move(to: target, duration: 1)
    boxNode.runAction(action)
}
```

ここで使っているのはSCNActionの`move(to:duration:)`メソッドです。toが目的地、durationがアニメーションする時間です。

他にも引数の違うmoveがあるのでそれぞれ紹介します。

### move(to:duration:)

nodeのある座標系のtargetに向かって1秒移動させます。

```swift
let action = SCNAction.move(to: target, duration: 1)
node.runAction(action)
```

https://developer.apple.com/documentation/scenekit/scnaction/1522826-move

### move(by:duration:)

nodeの相対位置deltaに向かって1秒移動させます。注意なのは相対距離ってだけでnodeのローカル座標系ではないので、xyzの方向はワールド座標系のものです。

```swift
let action = SCNAction.move(by: delta, duration: 1)
node.runAction(action)
```

https://developer.apple.com/documentation/scenekit/scnaction/1522605-move

# 回転

![rotate.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/7950289c-c29c-a982-ab99-4337bf304a6a.gif)

上記のフラミンゴは以下のコードで回っています。

yに`π`を入れているので、y軸を中心に180度1秒間かけてアニメーションします。

```swift
let action = SCNAction.rotateBy(x: 0, y: .pi, z: 0, duration: 1)
flamingoNode.runAction(action)
```

### rotateBy(x:y:z:duration:)

byの場合は現在地から何度回転するかを指示します。

https://developer.apple.com/documentation/scenekit/scnaction/1523522-rotateby

### rotateTo(x:y:z:duration:)

toの場合は、現在の角度にかかわらず、絶対的な角度に向かって回転します。

https://developer.apple.com/documentation/scenekit/scnaction/1524044-rotateto

### rotate(by angle: CGFloat, around axis: SCNVector3, duration)

先程まではx,y,zに値を入れる形でしたが、SCNVector3を使って任意の軸の周りの回転を作れます。

https://developer.apple.com/documentation/scenekit/scnaction/1523805-rotate

### rotate(toAxisAngle axisAngle: SCNVector4, duration)

クオーターユニオンで指示する方法です。

https://developer.apple.com/documentation/scenekit/scnaction/1524191-rotate

# 拡大縮小

![scale.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/95fcbeb3-ebdc-47f9-fe2b-96ad4aedbf2c.gif)

上記のフラミンゴちゃんの拡大は以下のように書いて実現しています。

```swift
flamingoNode.scale = SCNVector3(0.01, 0.01, 0.01)
let action = SCNAction.scale(by: 100, duration: 0.4)
flamingoNode.runAction(action)
```

### scale(by:duration:)

byは、nodeのscaleに対して何倍でかくするかです。

https://developer.apple.com/documentation/scenekit/scnaction/1523129-scale

### scale(to:duration:)

toは、指定したscaleに向かって変化します。現在のscaleは関係ありません。デフォルトでscaleはx, y, z全部1なので、例えば1を与えた場合は何も変化しません。

https://developer.apple.com/documentation/scenekit/scnaction/1523322-scale

# 合わせ技

![action.gif](https://qiita-image-store.s3.amazonaws.com/0/111366/dca04f3f-dfd7-ccdb-b941-4fc5e034c399.gif)

例えば上のフラミンゴちゃんは、回転しながらでかくなっています。コードは以下です。

```swift
// 小さくしとく
flamingoNode.scale = SCNVector3(0.01, 0.01, 0.01)

let scaleAction = SCNAction.scale(by: 100, duration: 0.4)
let rotateAction = SCNAction.rotateBy(x: 0, y: .pi/2, z: 0, duration: 1)
rotateAction.duration = 0.4
let action = SCNAction.group([scaleAction, rotateAction])
flamingoNode.runAction(action)
```

このようにSCNActionは同時に実行したり、順番に実行したりすることができます。


### group(_:)

複数のSCNActionを配列に入れて、**並列**に実行することができます。

```swift
let action = SCNAction.group([scaleAction, rotateAction])
```

https://developer.apple.com/documentation/scenekit/scnaction/1522779-group


### sequence(_:)

複数のSCNActionを配列に入れて、**直列**に実行することができます。以下の場合は大きくなったあとに回転します。

```swift
let action = SCNAction.sequence([scaleAction, rotateAction])
```

https://developer.apple.com/documentation/scenekit/scnaction/1522793-sequence

# まとめ
- 移動、回転、拡大縮小を紹介した
- toとbyの使い分けに注意
- 他にもいくつかアクションがあるので詳しくは公式ドキュメントで

# SCNActionドキュメント
https://developer.apple.com/documentation/scenekit/scnaction