主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2020/07/20
元は VRChat 関連だけど、アバターの GameObject のツリー構造に依存せず、
自由にギミックを仕込む為の仕組みを作りたかった。
ただ、そのまま anim
を配布しただけだと対応できないので、動的に生成してみました。
Animation を動的に生成するには、以下のファイルをエディター拡張から作成できれば良さそうです。
ということで、まずは Animation Clip を作成してみます。
Animation Clip の作成は簡単で、以下のようにやっていくことで作成できます。
var animation = new AnimationClip();
// Offset/GameObject を無効→有効にする
AnimatorUtility.SetEditorCurve(
animation,
EditorCurveBinding.FloatCurve("Offset/GameObject", typeof(GameObject), "m_IsActive"),
AnimationCurve.Linear(0, 0, 1 / 60f, 1)
);
AssetDatabase.CreateAsset(animation, "path/to/anim.anim");
m_Active
の部分とかは実際に作成してみて、 anim
ファイルを覗いてみると書いてあります。 Offset/GameObject
の部分は、 Animator をセットする GameObject からの、
相対パスを設定してあげればよいです。
ちなみに相対パスは以下のコードで求められます。
private static string GetPathBetweenGameObjects(GameObject root, GameObject child)
{
var paths = new List<string>();
var current = child.transform;
while (current != null && current != root.transform)
{
paths.Add(current.name);
current = current.parent;
}
paths.Reverse();
return string.Join("/", paths);
}
Animation Clip を生成できたら、次は Animator Controller を作成します。
こちらは、コードで作るのが面倒だったので、予め作ってあるものをいじるようにしました。
まずは、テンプレートととなる Animator Controller をコピーし、それを読み込みます。
AssetDatabase.CopyAsset("/path/to/template.controller", "/path/to/dest.controller");
var controller = AssetDatabase.LoadAssetAtPath<AnimatorController>("/path/to/dest.controller");
次に、元となる State Machine を読み込み、 Animation Clip を設定していきます。
foreach (var state in stateMachine.states)
{
// your code here...
state.state.motion = animation;
}
次に、パラメータを追加します。
これはどうやら Remove してから Add しないと反応しないらしい?
foreach (var value in controller.parameters.Select((w, i) => (Index: i, Parameter: w)))
{
controller.RemoveParameter(value.Index);
// Key 部分はお好きに
controller.AddParameter("Key", value.Parameter.type);
}
最後に条件を設定してあげます。
// Any -> Others
foreach (var transition in stateMachine.anyStateTransitions)
{
if (transition.coditions.Length == 0)
continue;
// お好きに...
}
とまあ、こんな感じで、ある程度コードから animation を動的生成することが出来ました。
ということで、メモでした。