アバターの物を出し入れできるようにするEditorを作る(Animator編)｜VRC用の拡張Editorを作ってみよう(6)

この記事は前回の続きになります
[VRC用の拡張Editorを作ってみよう(5)](https://qiita.com/Milcia/items/ff7d9e1dffa28004efb7)

#目次
1.準備
2.コードを書く
3.動作確認
4.次回

#1.準備
##usingを追加する
今回はアニメーターを扱うため

```c#
using UnityEditor.Animations;
```
を追加します
##メソッドを定義する
アニメーターを追加するためのメソッドを定義します
privateな戻り値無しのメソッドを定義します
今回の名前はAddLayerにします

```c#
private void AddLayer()
{

}
```
メソッドが定義できました

#2.コードを書く
##変数を宣言する
今回はAddLayerの中に変数を宣言していきます
AnimatorControllerの変数、AnimationClipの変数を二つ宣言します
AnimatorControllerの変数名はanimatorControllerにします
animatorControllerには、アバターのベースレイヤー(FXLayer)のアニメーションクリップを代入します
AnimationClipの変数名は、アニメーションオンの時、オフの時と、二つ作りたいので
onAnimation、offAnimationにします
onAnimation、offAnimationにはAddAnimationメソッドで作ったアニメーションをAssetsから取得して代入します

```cs
AnimatorController animatorController = avatar.baseAnimationLayers[4].animatorController as AnimatorController;
AnimationClip onAnimation = AssetDatabase.LoadAssetAtPath(animFolderPath + "/" + animationName + "On.anim", typeof(AnimationClip)) as AnimationClip;
AnimationClip offAnimation = AssetDatabase.LoadAssetAtPath(animFolderPath + "/" + animationName + "Off.anim", typeof(AnimationClip)) as AnimationClip;
```
これで宣言ができました
##レイヤー内を検索する
同じレイヤーが作成されていないか検索するためのコードを書いていきます
まずは、カウント用の変数を定義します
整数を扱う変数を定義します
今回の名前はsameLayerCountにします
変数は初期化しておきましょう(変数に0を代入します)

```c#
int sameLayerCount = 0;
```
変数はできたので、検索するコードを書いていきます
繰り返し処理をするため、for文を使って書きます
まずは、繰り返し回数をカウントする整数型の変数layerCountを定義して、layerCountに初期化のための0を代入します
次に、セミコロンで区切って、繰り返される条件を書きます
layerCountがanimatorControllerのレイヤーの最大に達したらループをやめるようにします
最後に、セミコロンで区切って、カウントアップされる条件を書きます
今回はlayerCountに+1します

```c#
for (int layerCount = 0; layerCount < animatorController.layers.Length; layerCount++)
{
	
}
```
繰り返し処理ができました
繰り返す内容を書いていきます
animatorController.layer[layerCount]でアニメーターコントローラーのレイヤーを繰り返し検索します
今回は、その中にAnimatorEditorの名前があったらカウントするコードを書きます
ですが、AnimatorEditorのままではかぶってしまうので、AnimatorEditorの後にsameLayerCountを追加します

```c#
if (animatorController.layers[layerCount].name == "AnimatorEditor" + sameLayerCount) sameLayerCount++;
```
繰り返し処理ができました
##レイヤーを追加する
カウントした値を元に、新しくレイヤーを追加します
AnimatotControllerLayer型の変数newLayerを作り、インスタンスを作成します
今回の値の代入はオブジェクト初期化子を使います
AnimatorControllerLayerに代入するのは
レイヤーの名前、ウェイトの値、インスタンス化したAnimatorStateMachineです
(なぜインスタンス化したAnimatorStateMachineが必要だったのかは覚えてないし今見返してもなんでかわからない。だれかわかる人教えて)
はい、追加していきます...

```c#
AnimatorControllerLayer newlayer = new AnimatorControllerLayer
{
	name = "AnimatorEditor" + sameLayerCount,
	defaultWeight = 1,
	stateMachine = new AnimatorStateMachine()
};
```
これで新しいレイヤーはできましたが、まだ追加ができていないので追加します
追加はAnimatorController.AddLayer(追加するレイヤー)で追加できます
今回はnewLayerを追加します

```c#
animatorController.AddLayer(newlayer);
```
これでレイヤーの追加ができました...?
このままレイヤーの追加ができてほしかったんですけど、このままではなぜかレイヤーに名前がはいってない...ので、追加します

```c#
//なぜかLayerの中に名前が入らないため追加
newlayer.stateMachine.name = "AnimatorEditor" + sameLayerCount;
```
これでやっと完成です
##アニメーターパラメーターを追加する
アニメーターを操作するためのパラメーターを追加します
animatorController.AddParameterで追加できます
追加する内容は、名前とパラメータータイプです
名前はAnimatorEditor + sameLayerCountにして、
アニメーションタイプはboolにします

```c#
animatorController.AddParameter("AnimatorEditor" + sameLayerCount, AnimatorControllerParameterType.Bool);
```
これでパラメーターの追加ができました
##StateとTransitionとConditionを追加する
アニメーションを設定するためのState、アニメーションを移動するためのTransition、移動する条件のConditionを追加していきます
ここでは面倒なので一度で全部説明します

```c#
1.  newlayer.stateMachine.AddState(offAnimation.name);
2.  newlayer.stateMachine.AddState(onAnimation.name);
3.  newlayer.stateMachine.states[0].state.motion = offAnimation;
4.  newlayer.stateMachine.states[1].state.motion = onAnimation;
5.  newlayer.stateMachine.states[0].state.AddTransition(newlayer.stateMachine.states[1].state);
6.  newlayer.stateMachine.states[1].state.AddTransition(newlayer.stateMachine.states[0].state);
7.  newlayer.stateMachine.states[0].state.transitions[0].hasExitTime = false;
8.  newlayer.stateMachine.states[1].state.transitions[0].hasExitTime = false;
9.  newlayer.stateMachine.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, "AnimatorEditor" + sameLayerCount);
10. newlayer.stateMachine.states[1].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, "AnimatorEditor" + sameLayerCount);
```

###1.
newLayerのstateMachineに、offAnimationのステートを追加する
###2.
newLayerのstateMachineに、onAnimationのステートを追加する
###3.
states\[0](offAnimation)のstateのmotionに、offAnimationを代入する
###4.
states\[1](onAnimation)のstateのmotionに、onAnimationを代入する
###5.
states\[0]からstate\[1]へ遷移する
###6.
states\[1]からstate\[0]へ遷移する
###7.
States\[0]のtransitions\[0](上で追加したやつ)のhasExitTimeを無効にする
###8.
States\[1]のtransitions\[0](上で追加したやつ)のhasExitTimeを無効にする
###9.
States\[0]のTransitions\[0]に条件を追加する
###10.
States\[1]のTransitions\[0]に条件を追加する

これらを追加すると、StateとTransitionとConditionを追加できます
##Layerを保存する
このままでは、Unityを閉じたときに全て消えてしまうので、消えないように保存します
保存するにはAssetDatabaseのAddObjectToAssetを使います
追加する内容は、新しく作ったレイヤーのステートマシーンです
保存先はanimatorControllerにします

```c#
AssetDatabase.AddObjectToAsset(newlayer.stateMachine, animatorController);
```
これで保存ができるようになりました

##ボタンからメソッドを呼び出す
前作ったボタンにメソッドを追加します

```c#
if (GUILayout.Button("Animation作成"))
{
	AddAnimation();
	AddLayer();
}
```
追加ができました

#3.動作確認
保存してEditorを開いて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/e9edc438-837f-9a78-322d-17bee2f969cf.png)
新しくアニメーションを作ります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/55f574a9-e924-c1da-3738-c0bb415be6f8.png)
追加されていますね
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/f4b2c5fe-0579-e668-6c5a-f5c6e614c2db.png)
パラメーターも大丈夫そうです
次は、複数作ってみましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/41a3969f-3607-bf37-745a-dbeebedb4c6b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/aaf70218-5a6a-8fef-8ac6-fbecd00b490a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286080/b9a2b1e0-f95e-6656-498b-3759510b9cb1.png)
問題なさそうです
今回はこれでおわりです
お疲れさまでした

#4.次回
次回はExpression編です

VRC用の拡張Editorを作ってみよう(7)
coming soon