【ARKit】社長が好きすぎて駆逐するアプリを作った話 その2. ゆらゆらモーション編

##これを解説します
###分解するとこう
![全体の流れ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/17eff80a-0f8d-af4c-cce9-119fbeb63bba.gif)
一番右の4コマ目が今回目指す完成形です。
###完成品
![ゆらゆら完成形.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/34a77cb6-00b0-2f38-be60-c3feb7d4eda2.gif)

##はじめに
どうも！再び登場B'z大好き芸人のウルトラ深瀬です！（またお前か）
当記事ではARKitを使ったFPS風ゲームの作り方を解説します。
今回は その2 ということで「ゆらゆらモーション」を解説していきます！

前回の記事はこちら[▶︎【ARKit】社長が好きすぎて駆逐するアプリを作った話 その1. FPS視点への固定編](https://qiita.com/Takamasa_Fukase/items/87f267bd0e3a952300ba)
続きはこちら[▶︎【ARKit】社長が好きすぎて駆逐するアプリを作った話 その3. 爆発の作り方編](https://qiita.com/Takamasa_Fukase/items/78ea8ea26bf0e40fd526)

##そもそもなぜ必要？
立体感とゲームらしさの演出の為です。
これをやらずにFPS視点に固定しただけだと、まるで静止画を貼り付けているようにも見えてしまいます。
もともと立体的でリアルな3Dモデルがそれでは勿体ないので、是非トライしてみましょう！

##SCNActionを使います
公式で用意されているSCNActionというものを使用します。↓
https://developer.apple.com/documentation/scenekit/scnaction

また、SCNActionについては[この方の記事](https://qiita.com/kboy/items/73a8ce28541966c7b20a)もとても参考になりますので是非ご覧ください。


##大まかな流れ
冒頭でも載せましたが、まさに下記の4コマの流れで作っていきます。
![全体の流れ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/17eff80a-0f8d-af4c-cce9-119fbeb63bba.gif)

###コード

```swift

        //【1コマ目】（上4コマでは往復1.6秒(片道0.8秒)にしていますが、4コマ目で最終的に下記の往復2.4秒(片道1.2秒)になります）
        //銃の先端が上に跳ね上がる回転のアニメーション
        let rotate = SCNAction.rotateBy(x: -0.1779697224, y: 0.0159312604, z: -0.1784194, duration: 1.2)
        //↑の逆（下に戻る回転）
        let rotateReverse = rotate.reversed()
        //上下のアニメーションを直列に実行するアニメーション
        let rotateAction = SCNAction.sequence([rotate, rotateReverse])

        
        //【2コマ目】（往復1.6秒(片道0.8秒)）
        //銃が垂直に持ち上がるアニメーション
        let moveUp = SCNAction.moveBy(x: 0, y: 0.01, z: 0, duration: 0.8)
        //↑の逆（垂直に下に下がる）
        let moveDown = moveUp.reversed()
        //上下のアニメーションを直列に実行するアニメーション
        let moveAction = SCNAction.sequence([moveUp, moveDown])
        
        
        //3コマ目を飛ばして【4コマ目】
        //回転と上下移動のアニメーションを並列に同時実行するアニメーション(それぞれのdurationをずらすことによって不規則な動き感を出している)
        let conbineAction = SCNAction.group([rotateAction, moveAction])
        

        //↑を永遠繰り返すアクション
        let gunnerShakeAction = SCNAction.repeatForever(conbineAction)
        

        //アクションをピストルに付与 ＆ 実行  （＊今回はピストルの親ノードではなくピストル本体に対して行います）
        sceneView.scene.rootNode.childNode(withName: "parentNode", recursively: false)?.childNode(withName: "M1911", recursively: false)?.runAction(gunnerShakeAction)

```

##ポイント
コードをみていていただくとわかりますが、今回はコンボ技を多用しています。

rotate(回転)、move(移動)、reverse(巻き戻し)などの単一アクションに加え、
・sequence([A, B])　→　ABを直列に（順番に）
・group([A, B])　→　ABを並列に（同時に）
の2種類の複数アクションを使い分けています。

また、
一番のポイントは　__AとBの実行時間をずらす__　ことで自然な動きに見せているところです。

###備考
1コマ目の銃口を跳ね上げる回転の指定値の計算方法については、今回かなり複雑な計算になってしまったため、別途整理ができてから追記しようと思います。
ピストル本体のeulerを前回の記事と全く同じに設定している方は、今回の回転指定値でそのままコピペで動くかと思います！

別のオブジェクトなどで試したい方は、まずscnファイルのエディタ上で銃口を跳ね上げた状態まで動かし、その前後のeulerの各値(x,y,z)との差分を求めます。
そしてコード上に取り込んだ実際のピストルの現在のeuler値を出力し、（エディタ上の設定値とコード上に取り込んだPistolのeuler値の単位がなぜか全然違うので）先ほど求めた差分をコード上の値の単位に変換してから設定するといいかと思います。

##応用
今回と同様の発想で次のような動きも実装可能ですので、是非色々試してみてください♪

①ユーザーの移動の速さに応じてピストルを左右に揺らす
![ひゅんひゅんGIF-min.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/869d9820-1000-bf77-4cfe-0bbf0abb68ec.gif)
②発砲時の反動を演出
![反動GIF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/407646ab-67a1-2efb-6615-293dcfd0ccb1.gif)

##駆逐アプリの続きはこちら
[__【ARKit】社長が好きすぎて駆逐するアプリを作ったはなし その3. 爆発編(特殊効果など)__]
(https://qiita.com/Takamasa_Fukase/items/78ea8ea26bf0e40fd526)
の解説は12/17（木）のアドベントカレンダーにて投稿予定です。
お楽しみに！

##さいごに
続きまして、アルサーガパートナーズ Advent Calendar 2020 15日目の記事は、我らが大先生 @ovama-koffee さんのご登場です :tada:

##おまけ
今回の駆逐アプリの元ネタになった個人ゲームアプリ「AR-GunMan」がAppStoreにて配信中です♪
https://apps.apple.com/jp/app/ar-gunman/id1542082005
![AR-GunMan_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521005/30270504-6914-9ad9-e03a-633870054e96.png)