[VRChat]初学者向けAnimatorの使い方

# はじめに
スクリプトが使用できないVRChatでギミックを作る際にAnimatorが重要となってくるので
VRChatでの使用を目的としたAnimatorの使い方についてまとめることにしました。
初学者を対象としてギミック作成に必要な基本的な部分をメインで書いていきます。

内容量が多いですが、大事なポイントは**太字**で強調しているので
そこを中心に見ていただけるといいかと思います。

Unity 5.6.3p1
VRCSDK-2018.10.15.18.21_Public

# Animatorとは

[Animatorコンポーネントの公式マニュアル](https://docs.unity3d.com/ja/current/Manual/class-Animator.html)

> Mecanim のアニメーションシステムをコントロールするためのインターフェースです。
([Unity公式マニュアル](https://docs.unity3d.com/ja/2017.4/ScriptReference/Animator.html)より)

簡単にいればUnityでアニメーションを管理するものです。

似たものに**[Animationコンポーネント](https://docs.unity3d.com/ja/2018.2/Manual/class-Animation.html)**もありますが、
これは旧アニメーションシステムとして現在では**非推奨**になっています。
VRChatでもアバターでは[2018.3.2バージョンからレガシーアニメーションが廃止され、使えなくなりました。](https://docs.vrchat.com/v2018.3.3/docs/vrchat-201832)
(ワールドでは現在でもAnimationコンポーネントおよびLegacyAnimationは使用可能です)

## VRChatでできたこと

- ガイスター(ボードゲーム) <br>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">あやりラボ新作【ガイスター】完成しました<br><br>機能<br>・VRもデスクトップも出来るようなUI操作<br>・当たり判定による自動取得<br>・盤面リセット<br><br>頑張ったから褒めて！！！！！<br>デバック班と素材提供の人もありがとう！！！<a href="https://twitter.com/hashtag/VRChat?src=hash&amp;ref_src=twsrc%5Etfw">#VRChat</a> <a href="https://twitter.com/hashtag/ayari_labo?src=hash&amp;ref_src=twsrc%5Etfw">#ayari_labo</a> <a href="https://t.co/mrcuqyE8F8">pic.twitter.com/mrcuqyE8F8</a></p>&mdash; あやり (@ayr_suzu) <a href="https://twitter.com/ayr_suzu/status/1006505678649753600?ref_src=twsrc%5Etfw">2018年6月12日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

- カウンタ
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">呼び出された回数をカウントする発想で数値表示を組んでみた<br>特徴：<br>・各桁が独立した部品<br>・間はカスタムトリガーでつないでいる。桁数を増やすのが容易<br>・呼び出し回数として値を取り出せる<br>・表示進数切り替え<br>・各桁は直接代入可<br>以上を組み合わせた、数を加算し別の進数で表示できる。というデモ <a href="https://t.co/6ojbFeiuZK">pic.twitter.com/6ojbFeiuZK</a></p>&mdash; naqtn(なくとん) (@naqtn) <a href="https://twitter.com/naqtn/status/1049420471584714752?ref_src=twsrc%5Etfw">2018年10月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

- 変形する武器<br>
<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://t.co/7qbthEErJd">pic.twitter.com/7qbthEErJd</a></p>&mdash; Shiaru (@AcysShiaruReus) <a href="https://twitter.com/AcysShiaruReus/status/1021328836867194880?ref_src=twsrc%5Etfw">2018年7月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## Animator Controller
![.controllerのファイル](https://qiita-image-store.s3.amazonaws.com/0/203750/04625890-bb38-bfbc-71b6-4b49d3b711fe.png)

Animatorでは**[Animator Controller](https://docs.unity3d.com/ja/current/Manual/class-AnimatorController.html)を使って複数のAnimationを管理**します。
Animator ControllerではAnimationの切り替えの順番や切り換える条件など様々な設定ができます。
各Animationでオブジェクトの状態(主にパラメータの値)を表現し、
トリガーでAnimationを切り替えていくことで**オブジェクトの状態を変化させる**といったイメージです。

![AnimatorController](https://qiita-image-store.s3.amazonaws.com/0/203750/14b2cb6d-e7b7-894a-77c5-e407d53c21e4.png)


例えば, Animation1ではCubeオブジェクトが横向きに回転してるとします。
それがプレイヤーのある行動(OnInteractなど)がトリガーとなってAnimation2に切り替わると縦向きに回転するようになるというように特定のトリガーによってCubeオブジェクトの状態を変化させることができます。[イメージ動画](https://youtu.be/aYFuF12UZkY?t=1953)

### Animation Parameter
[Animation Parameter](https://docs.unity3d.com/ja/current/Manual/AnimationParameters.html)はAnimator Controllerで**Animationの切り替えを行う際などに使うパラメータ**です。
パラメータには実数型(Float), 整数型(Int), 真偽値(Bool), トリガー(Trigger)の4つの種類があります。

![Parameters](https://qiita-image-store.s3.amazonaws.com/0/203750/19ad6022-f86d-e540-c586-0ee8d82504d0.png)


AnimatorControllerでAnimation間に
「このパラメータが4.5より大きくなったら」や「このパラメータがtrueになったら」
というような**条件を事前に設定して**おいて、パラメータを変化させて**条件が満たされればAnimationが切り替わります。**
![Transition](https://qiita-image-store.s3.amazonaws.com/0/203750/b87ff0e0-ba85-9d46-9bb7-ba9ce9e59aee.png)

Animator Controllerは.controllerという拡張子のファイルで管理され, 
Projectタブで「右クリック>Create>AnimatorController」や
AnimationファイルをHierarchyのオブジェクトのD&Dすることなどで作ることができます。
![createanimatorcontroller](https://qiita-image-store.s3.amazonaws.com/0/203750/833f03e2-06d8-d91d-9b79-285cec7a8662.png)

編集はAnimatorウィンドウでおこないます。
上部のメニューからWindow>Animatorでウィンドウを表示できます

また、各AnimationはAnimatorウィンドウにD&Dすることで追加されます。
その際にそのAnimationに対応したオレンジや灰色の四角が出てきます。
![animation_add.png](https://qiita-image-store.s3.amazonaws.com/0/203750/e2caf449-9aaa-7ad6-91c8-b206d6524ad3.png)


### TransitionsとConditions
AnimatorでAnimationの切り替えをおこなうときの設定に必要な項目の一部です。
Animation間をつなぐ矢印を選択すると以下の図のようにInspectorに表示されます。
![transition_inspector.png](https://qiita-image-store.s3.amazonaws.com/0/203750/075f2650-3526-acf5-2940-52ff7c302fde.png)
Animatorで設定していくために重要なTransitionsとCondirionsについて説明します。


#### Transitions
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/8eeedd0c-8bd8-6cde-9fd8-fdc085429321.png)
**どのAnimationからどのAnimationに切り換えるか**を設定します
Animatorウィンドウの中でAnimation間に引かれている矢印1つにつきこれが1項目存在します。
(上図では矢印を1つ設定したので項目が1つ表示されています。)

矢印は切り替え前のAnimationに対応するオレンジや灰色の四角を右クリックして
MakeTransitionを選択することで出てきます。
そのあと、切り替え後のAnimationに対応するオレンジや灰色の四角をクリックすると矢印で繋がれます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/9ae8a0b1-5417-d912-33cb-36f3430181af.png)

同じAnimation間に複数の矢印を引くと以下の図のようになります。
(下図ではAnimation1からAnimation2に向かった矢印を2つ設定しました)
![transitions.png](https://qiita-image-store.s3.amazonaws.com/0/203750/ba6fe634-476a-b37f-418b-ed0d11c99f4a.png)
矢印1つにつきConditionsで切り替える条件を設定できます。
どれかの矢印の条件が満たされた場合に切り替わるので複数矢印を設定してORのように設定するときに使えます。

Animation1からAnimation2に向かう矢印を2つ設定した場合Transitionsは2項目になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/d0ec6b64-6776-2b2a-1a42-fee16de6c7c5.png)
項目(矢印)ごとに条件を設定でき、それぞれの項目を選択するとConditionsの表示が項目に対応した条件に切り替わります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/ccd7bdc2-412b-6c74-d1ac-290eafbc0441.png)

この場合はAnimation1を再生しているときに
「boolがtrueまたはfloatが0より大きな値になったら」 *Animation1からAnimation2に*切り替わります



#### Conditions
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/fc75e1d7-d0d6-dbc6-2c42-185ab952a470.png)
**Animationを切り替える条件**を設定します。
その矢印の方向に切り替わるときに設定する条件１つにつき1項目存在します
(上図では条件を1つだけ設定しています)

+を押すことで条件を増やすことができ、
Conditionsに条件が複数設定されている場合、その分だけ項目が表示されます
(下図では条件を2つ設定して2つ項目が表示されています)
![conditions_multi.png](https://qiita-image-store.s3.amazonaws.com/0/203750/150bcb6b-c108-52c5-583b-4bcbb5378900.png)
すべての条件が満たされた場合に切り替わるのでANDのように設定するときに使えます。

この場合はAnimation1を再生しているときに
「boolがtrueかつfloatが0より大きな値になったら」 *Animation1からAnimation2に*切り替わります

#### その他
詳しくは[こちらの記事](http://hiyotama.hatenablog.com/entry/2015/06/29/090000)に書いてあるので、特に重要なHasExitTimeのみ解説します

**Has Exit Time**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/462b4dca-e1fc-9a3d-0fbc-855b08a3aff7.png)
チェックをいれると条件が満たされても実行中のAnimationが終わる（最後のフレームにいく）まで切り替わるのを待ちます
Conditionsに条件を設定する場合には基本的にチェックを外しておいていいと思います

# ワールドで使う
VRCSDKに含まれる[VRC_Triggerコンポーネント](https://vrcworld.wiki.fc2.com/wiki/VRC_Trigger)からAnimatorに対して以下のようなActionをおこなえます。

- AnimationBool
- AnimationFloat
- AnimationInt
- AnimationIntAdd
- AnimationIntSubtract
- AnimationIntMultiply
- AnimationIntDivide
- AnimationTrigger

各ActionはActionsの右下の+ > Basic Events > 各Actionで追加できます
![animatorfloat.png](https://qiita-image-store.s3.amazonaws.com/0/203750/22313af2-af81-8d5f-648a-34f30b402bae.png)

どのActionもこんな感じの設定項目です。
* Receivers : 変化させるParameterを持つAnimatorを設定します
* Variable : 変化させるParameter名を設定します(**手打ちなので入力ミス注意**)
* Value/Operation : Variableに設定したParameterに対して計算するときに使う値を設定します


## AnimationBool
AnimationBoolはAnimationStateの管理に**真偽値(True/False(0/1のほうが分かりやすいかも))**を使う方式です。
![animationbool.png](https://qiita-image-store.s3.amazonaws.com/0/203750/a7bfc3dd-cf5b-adea-3f0e-ae67748498de.png)


Receiversに設定されたAnimatorのboolというParameterをOperationの値に変更します
OperationをToggleにした場合、現在のboolの値の反対の値に変更します(true->false, false->true)

状態が2つのときに使います
* ドアの開け閉め(空いている状態をtrue, 閉まっている状態をfalse)

## AnimationFloat
AnimationFloatはAnimationStateの管理に**実数型(0.0とか0.5とか2.3とか)**を使う方式です。
![animatorfloat.png](https://qiita-image-store.s3.amazonaws.com/0/203750/347df061-0850-d984-acdc-1c37c8fe7be7.png)

Receiversに設定されたAnimatorのfloatというParameterにValueの値を入力します

単純に状態管理として使う場合は同じことがAnimationIntやAnimationBoolでできるため、そちらを使ったほうがいいです。

限定的にfloatのパラメータを用いることでComponentの値を動的に変化させられるので
それを利用したスライダーがつくられています([TPCスライダー改](https://twitter.com/momoma_creative/status/1052900263453896704))

## AnimationInt系
AnimationIntはAnimationStateの管理に**整数型(0とか2とか10とか)**を使う方式です。
AnimationIntAdd/Substract/Multiply/DivideはそれぞれIntのパラメータをあらかじめ設定しておいた値で四則演算することができます。
![animatorint.png](https://qiita-image-store.s3.amazonaws.com/0/203750/0803887e-b01d-26b4-fe4a-c6c54916ef19.png)

- **AnimationInt**<br>
Receiversに設定されたAnimatorのintというParameterにValueの値を入力します
- **AnimationIntAdd**<br>
Receiversに設定されたAnimatorのintというParameterにValueの値を足します
- **AnimationIntSubtract**<br>
Receiversに設定されたAnimatorのintというParameterからValueの値を引きます
- **AnimationIntMultiply**<br>
Receiversに設定されたAnimatorのintというParameterにValueの値をかけます
- **AnimationIntDivide**<br>
Receiversに設定されたAnimatorのintというParameterをValueの値で割ります

状態が複数あるときに使います(各状態と数字を対応させる)
* カウンタ (各桁ごとに状態(Animation)を用意)
* ゲームの進行 (進行状態ごとに状態を用意)

## AnimationTrigger
AnimationTriggerは**トリガーを発生したということ**を管理する方式です。
![animationtrigger.png](https://qiita-image-store.s3.amazonaws.com/0/203750/ce3e49ef-d61b-9b87-420d-61a9487c1b6b.png)

ある行動を実施(OnInteractなど)するごとにAnimationが切り替わっていくというようなときに使えます。


## 状態を同期させる
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">VRC_ObjectSyncとAnimatorが同オブジェクトに入っていると、オブジェクトをPickupしている間、常にAnimatorの全変数を同期し続けます。<br>子のAnimator等がこの影響を受ける事はありません。</p>&mdash; hatsuca (@hatsuca_vr) <a href="https://twitter.com/hatsuca_vr/status/1030506808329138176?ref_src=twsrc%5Etfw">2018年8月17日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Animatorコンポーネントをつけたオブジェクトと同じオブジェクトに
**VRC_Pickup**と**VRC_ObjectSync**をつけることでAnimationParameterが同期します。
つまり, AnimatorはAnimationParameterによっていまのAnimationを管理しているので
オブジェクトの状態が全プレイヤーで同じになります。

しかし、triggerに関してはトリガーを押したという情報だけなので
triggerを使った機構の場合は後から来た人のことを特に考慮した設計にする必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/203750/78739bde-2681-b9a3-6d83-5577c10ec36f.png)
単純にAnimationParameterの同期のために使う場合は
* RigidbodyのisKinematicをfalse
* VRC_PickupのPickupableをfalse
* VRC_ObjectSyncの2つの項目をどちらもfalse
にすると良いでしょう。

# アバターで使う
アバターではParameterの値の変更はおこなうことができないので、
時間経過で自動的にAnimationを切り替えていくことになります。

![animator_avatar.png](https://qiita-image-store.s3.amazonaws.com/0/203750/d05a21a9-d020-7859-7eb8-f960aee55c84.png)
例えば、抜刀時に変形した後に一部分が回転したり動いているような状態を維持する武器アニメーションを設定する場合、
変形アニメーションと状態維持アニメーションを用意してその間を矢印でつなぎます。
HasExitTimeにチェックをいれることで変形後に状態維持するようなアニメーションを用意できます。

状態維持アニメーションが一部回転しつづけるなどのアニメーションを常に実行するために
LoopTimeにチェックをいれておきます。
このInspectorの表示にはAnimationファイルを選択するか、
Animatorウィンドウのオレンジや灰色の四角をダブルクリックすることで切り替えられます。



複雑なギミックを組むとなるとAnimatorの以下の性質を使っていくことになると思います。

- Animatorがついたオブジェクトを一度disnableにすることでEnableにしたときにEntryからAnimationが開始される
- Animatorコンポーネントをdisnableにすることでその状態でAnimationが停止する(enableにするとそこから再開する)
    - [こちらの記事](https://jellyfish-qrage.hatenablog.com/entry/2018/10/02/152316?utm_source=feed)の"アニメーションからanimatorの動作を停止させる方法"を参考に
- Write Defalutにチェックをいれると別のAnimationで設定されていて実行中のAnimationで設定されていない値は初期値に戻る

ここらへんは応用的なものなのでここでは詳細な解説は割愛します

#  最後に
VRCSDKでAnimatorに対してできることを中心に解説していきました。
Animatorでできることは限られていますが、発想次第でも多くのことは実現できると思います。
この記事では基本的な部分を端的に書いているので分かりづらかったり、説明不足な部分があると思います。
そんなときはここで使われている用語で検索したり、下部の参考ページ等を見ることでよりAnimatorと和解できるかと思います。
長々となりましたが、この記事が表現したいことを表現するための手助けになれば幸いです。

本記事は今後も更新して、より分かりやすい記事にしたいと思っているので
質問や間違いの訂正等はコメント欄や[Twitter](https://twitter.com/gatosyocora)のほうまでぜひ連絡ください。

# 参考ページ・動画・Prefab
Animatorを使う際に参考になりそうな情報が載ったページや動画、Prefabです。

### ページ
- [アニメーション関係 - VRChat技術メモ帳](https://vrcworld.wiki.fc2.com/wiki/%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%A2%E9%80%A3) : VRChatでのAnimatorの利用についてより詳細な情報が載ってます
- [アニメーターコントローラーの公式マニュアル](https://docs.unity3d.com/ja/2017.4/Manual/class-AnimatorController.html) : Unityの公式リファレンスが一番情報載ってると思います(載っててほしいです)
- [【Unity】Animatorの個人的な逆引きリファレンス](https://qiita.com/r-ngtm/items/c56a2884d09deda78f22) : 操作方法とか書いてあってわかりやすいです
- [【Unity開発】Animator Controllerの遷移設定(Duration等)【ひよこエッセンス】](http://hiyotama.hatenablog.com/entry/2015/06/29/090000) : HasExitTimeや紹介しきれなかったSettingsについて書いてあります
- [【Unity】知らないと面倒くさい事になるかもしれないAnimatorの「Write Defaults」の動作について](http://tsubakit1.hateblo.jp/entry/2017/01/15/233000) : 少し仕組みを解説した発展的な内容です
- [VRChatのワールドでの同期について](https://qiita.com/hatsuca_vr/items/63ee6ba04d2a785eed16) : hatsucaさんによる同期に関する記事です
- [ワールドギミックにおけるAnimator基礎](https://docs.google.com/presentation/d/1SAr69-wE3qPpd0HCC5RMJrsXLdZJJGUsrBa74gu4y3Y) : hatsucaさんによるVRChatのワールドで使うためのAnimatorの解説です。

### 動画
- [butadieneさんによるワールドの仕掛けの解説動画](https://youtu.be/aYFuF12UZkY?t=1170) : 初めてAnimatorを使った際にはお世話になりました
- [noribenさんによるVRChatでアニメーションを再生するボタンをつくる解説動画](https://www.youtube.com/watch?v=UZs6odSd-Sg&feature=youtu.be) : こちらもすごくわかりやすいです

### Prefab
- [同期関係の実用例](https://drive.google.com/open?id=1927gFc3JDWZjh-U2soV9BOB-dkz-D4SG) : hatsucaさんの作成されたギミック集です。Animatorを使った同期ドア、タイマー、銃弾再利用銃が入ってます。
- [数字表示システムと計算機システム](https://twitter.com/butadiene121/status/1001489400860037122) : AnimationIntを使ったブタジエンさん作のシステムです。
- [JetDogs-Prefabs](https://github.com/jetdog8808/JetDogs-Prefabs?files=1) : JetDogs氏の作成されたワールドギミックの詰め合わせ。ワールドで使える基本的なギミックが多く入っています。PrefabによってはStandardAssetsやFinalIKが必要なものがあります。
- [Null Space](https://twitter.com/momoma_creative/status/1029998964588695554) : ナルさんが作成されたワールドギミックの詰め合わせ。AnimatorだけでなくStandardAssetsも多く使用しており、非常に高度な内容です