VCIで複数オブジェクトを同期させて動かす3つの方法

#はじめに
この記事は、[VCI Advent Calendar 2019](https://qiita.com/advent-calendar/2019/vci)の20日目の記事です。
今回は複数のアイテムを一緒に動かしたいときのやり方を３通りで紹介します

#概要
以下のような、複数オブジェクトをひとかたまりとして動かす方法の紹介です。
以下の画像のようなイメージのものです。
![Parent1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/efca8c44-05fa-42f1-02b4-c09e29894b63.gif)
主にばらばらで作ったオブジェクトをくっつけたり、操作用のボタンを取り付けたりするのに使うことが多いかと思います。
この方法を3パターン紹介します。


#① Unity上でオブジェクトを親子にする
最も簡単な方法です。以下のようにUnity上で親子関係を作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/afc1ba8a-4d1c-7297-9fef-60d171b3e0ae.png)
Parent1にのみVCISubItemがセットされています
親を空オブジェクトにしてその下に複数の子、というような構成でも問題ありません。


### メリット
**1. ノーコーディング**
**2. 拡縮が扱いやすい**

### デメリット
**1. どのオブジェクトがUseされたか見分けることが出来ない**
アイテムをuseした場合、onUse系の関数の引数には子をuseしても親をuseしても親のオブジェクト名が入って来るようになっており、どのオブジェクトがuseされたか見分ける事はできません。
そのため、別の役割を持ったボタンなどをもたせることは出来ません。
(onCollision・onTrigger系の関数のtargetには子の情報も入ってくるため、以下のペンのように別のクリック用のオブジェクトを組み込むことで回避することは可能です。)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/ac89b0c6-703b-ec4d-55af-9cd4f10cb035.jpeg" width=50%>


#② Jointでつなげる
UnityのFixedJointでまとめて動かしたいオブジェクトをつなげる方法です
Unity上の構成は以下のとおりです。ChildそれぞれにFixedJointを付け、ConnectedBodyの項目にParentを指定しています
(VCIでのJointの設定については[VirtualCastのwiki](https://virtualcast.jp/wiki/doku.php?id=vci:unitycomponent:joint)を御覧ください)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/2f2560bb-7d47-1621-3574-836b6e7e258c.png)
**※ChildのRigidbodyのIs Kinematicにチェックが入っているとただしく動かないので注意です**




### メリット
**1. どのオブジェクトがuseされたか見分けることができる**
この構成であれば子にもVCISubItemをつけることが出来るため、useの引数で子と親を見分ける事ができます
**2. ノンコーディング**

### デメリット
**1. 拡大・縮小が同期されない**
FixedJointでオブジェクトを繋いだ場合距離が固定されるらしく、拡大してもオブジェクトの幅は広くならず固定のままとなります
**2. ちょっと遅れて動く・プルプル震える**
以下の画像参照。なんかたゆんたゆんしてます。
![Parent2-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/07a79002-9636-8be2-f62d-7a57227d3b90.gif)


ちなみに他人の視点から見るともう少しマシに見えます。
![Parent2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/853df46f-3fe9-3e1c-0cb5-698421d9880e.gif)


#③ スクリプトで同期させる
最後に紹介する方法はスクリプトで位置・回転・拡大率を同期させる方法です。
実現方法は何パターンかありますが、今回は同期用のダミーオブジェクトを使用する方法を取ります。
少し複雑なため、詳しく説明します。

まず、Unity上の構成は以下のとおりとなります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/3faaec93-96f1-f8f4-51cc-aca0d8a1c4ec.png)
ポイントとしては2つです
　・Childオブジェクトが同期するためのダミーオブジェクト(空オブジェクト)をParentの配下に設置する。
　　その際、ダミーオブジェクトはChildと同じ座標に設置する
　・ParentとChildのルートは空オブジェクトとし、Sizeは1にする
　　(この構成にしておくとサイズの同期が少し楽になります)


次に、同期させるコードは以下のとおりです。
(望ましくない書き方がありますが一旦無視してください。)

```lua
--利用しやすいようにGetSubItemして変数に格納しておく
local ITEMS ={
  PARENT = vci.assets.GetSubItem("Parent 3"),  
  CLILD_X = vci.assets.GetSubItem("ChildX 3"),
  CLILD_Y = vci.assets.GetSubItem("ChildY 3"),
  CLILD_Z = vci.assets.GetSubItem("ChildZ 3"),
  CLILD_X_DUMMY = vci.assets.GetSubItem("ChildX 3_dummy"),
  CLILD_Y_DUMMY = vci.assets.GetSubItem("ChildY 3_dummy"),
  CLILD_Z_DUMMY = vci.assets.GetSubItem("ChildZ 3_dummy"),
}
---毎フレーム位置同期を行う
function updateAll()
  moveChild(ITEMS.CLILD_X,ITEMS.CLILD_X_DUMMY)
  moveChild(ITEMS.CLILD_Y,ITEMS.CLILD_Y_DUMMY)
  moveChild(ITEMS.CLILD_Z,ITEMS.CLILD_Z_DUMMY)
end
--childの要素の位置・回転・拡縮をtargetに同期させる
function moveChild(child,target)
  child.SetPosition(target.GetPosition())
  child.SetRotation(target.GetRotation())
  child.SetLocalScale(ITEMS.PARENT.GetLocalScale()) --ココだけ参照しているオブジェクトが異なる
end
```
先程unityで作成したダミーオブジェクトの位置に子オブジェクトを移動しています。


### メリット
**1. まとめて動かす・動かさないの切り替えが可能**
状態によって位置を同期させる部分の呼び出しをON・OFFすることで、同期したりしなかったりを切り替えられます。
工夫すれば「親を動かした場合は子が一緒に動くが、子を動かしたときは親は動かない」といったことも実現可能です
**1. どのオブジェクトがuseされたか見分けることができる**
Jointと同様にChildもVCISubItemが付けられるため、useの引数で子と親を見分ける事ができます

### デメリット
**1. コードを書く必要がある**
工夫すれば色々できるこの方法ですが、その分コードを書く必要があります。
特に拡縮に関しては少し工夫がいります。
また、コードの書き方によっては重くなる可能性もあります

**2. ちょっと遅れて動く**
以下の画像参照。JOINTよりはましに見えます。
![Parent3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/001021c4-944c-79e0-d0ee-fb776d9d7e9e.gif)




#結局どうすればいいの？
やりたいことのパターン別に以下の表の様になるかと思います

| 同期ON/OFF<br>切り替え       |       useで見分ける | 拡大・縮小     | |   おすすめ方法    |
|:--------------------:|:-----------------:|:------------------:|:-:|:------------------|
| ○           |        － |       －     |⇒|        ③ スクリプト    |
| ×           |        ◯ |       ◯     |⇒|        ③ スクリプト    |
| ×           |        ◯ |       ✕     |⇒|        ② Joint        |
| ×           |        － |       ◯     |⇒|        ① 親子関係      |




#いかがでしたか？
今回は複数オブジェクトをひとかたまりにして動かしたい場合の実現方法について紹介しました。
パフォーマンスについては確かな情報がわからなかったため、詳しく記載しませんでしたが、
③の方法でもそんなに重いと感じる事はありませんでした
Let's enjoy hitokatamari！٩( 'ω' )و