(PACKAGING) Change the folder structure for package format
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad91af824b32bed4c8a08541bef67cfe
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f30100b4c328384b893342ed6dcdb02
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c745f3802e61ded458735b8e5cf42e16
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "AacEditModeTests",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"AnimatorAsCode.V1"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll",
|
||||
"VRCSDKBase.dll",
|
||||
"VRCSDK3A.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a8152e7670c1814abad041ff22b7994
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using AnimatorAsCode.V1;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1.EditMode
|
||||
{
|
||||
public abstract class AbstractSimpleSingleLayerAnimatorInternalEditModeAC
|
||||
{
|
||||
protected GameObject _root;
|
||||
private AnimatorController _container;
|
||||
private string _containerPath;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_root = new GameObject("Root");
|
||||
_container = new AnimatorController();
|
||||
_containerPath = $"Assets/temp_aac_test__{Guid.NewGuid()}.asset";
|
||||
AssetDatabase.CreateAsset(_container, _containerPath);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.DestroyImmediate(_root);
|
||||
AssetDatabase.DeleteAsset(_containerPath);
|
||||
_root = null;
|
||||
_container = null;
|
||||
_containerPath = null;
|
||||
}
|
||||
|
||||
protected AacFlBase TestAac()
|
||||
{
|
||||
return AacV1.Create(new AacConfiguration
|
||||
{
|
||||
AnimatorRoot = _root.transform,
|
||||
AssetContainer = _container,
|
||||
AssetKey = "None",
|
||||
DefaultsProvider = new AacDefaultsProvider(),
|
||||
SystemName = "Test",
|
||||
DefaultValueRoot = _root.transform
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16d5c7dc8b974daf8719f0d02f1e3fb3
|
||||
timeCreated: 1671470027
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4640dd95c9fe21e43b64f04e582c080d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d910756d511fe0b4996d2626cf6fd301
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Assert = UnityEngine.Assertions.Assert;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public class AIACAnimatorWideTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_should_override_bool()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBool = fx.BoolParameter("MyBool");
|
||||
first.TransitionsTo(second).When(myBool.IsTrue());
|
||||
fx.OverrideValue(myBool, true);
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_override_int()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myInt = fx.IntParameter("MyInt");
|
||||
first.TransitionsTo(second).When(myInt.IsGreaterThan(1));
|
||||
fx.OverrideValue(myInt, 2);
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_override_float()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myFloat = fx.FloatParameter("MyFloat");
|
||||
first.TransitionsTo(second).When(myFloat.IsGreaterThan(0.49f));
|
||||
fx.OverrideValue(myFloat, 0.5f);
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
private static AnimatorStateInfo Info0(Animator animator)
|
||||
{
|
||||
return animator.GetCurrentAnimatorStateInfo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b1c43dad69a46c697e2aa9ed5055e63
|
||||
timeCreated: 1671493684
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Assert = UnityEngine.Assertions.Assert;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public class AIACBoolTransitionTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_should_transition_when_bool_is_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBool = fx.BoolParameter("MyBool");
|
||||
first.TransitionsTo(second).When(myBool.IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBool", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_bool_is_false()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBool = fx.BoolParameter("MyBool");
|
||||
first.TransitionsTo(second).When(myBool.IsFalse());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBool", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBool", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_both_bools_are_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBoolOne = fx.BoolParameter("MyBoolOne");
|
||||
var myBoolTwo = fx.BoolParameter("MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBoolOne.IsTrue()).And(myBoolTwo.IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", false);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 3
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_second_bool_is_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBoolOne = fx.BoolParameter("MyBoolOne");
|
||||
var myBoolTwo = fx.BoolParameter("MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBoolOne.IsTrue()).Or().When(myBoolTwo.IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_group_of_bools_are_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBools.AreTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_group_of_bools_are_false()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBools.AreFalse());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", false);
|
||||
animator.SetBool("MyBoolTwo", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_group_of_bools_are_true_except_one_of_them()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo", "MyBoolThree");
|
||||
first.TransitionsTo(second).When(myBools.AreTrueExcept(fx.BoolParameter("MyBoolThree")));
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.SetBool("MyBoolThree", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.SetBool("MyBoolThree", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_group_of_bools_are_true_except_another_group_of_them()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo", "MyBoolThree", "MyBoolFour");
|
||||
first.TransitionsTo(second).When(myBools.AreTrueExcept(fx.BoolParameters("MyBoolThree", "MyBoolFour")));
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.SetBool("MyBoolThree", true);
|
||||
animator.SetBool("MyBoolFour", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.SetBool("MyBoolThree", false);
|
||||
animator.SetBool("MyBoolFour", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_any_of_group_of_bools_is_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBools.IsAnyTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_any_of_group_of_bools_is_false()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo");
|
||||
first.TransitionsTo(second).When(myBools.IsAnyFalse());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolTwo", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_when_any_of_group_of_bools_is_true_and_another_bool_is_also_true()
|
||||
{
|
||||
var controller = new AnimatorController();
|
||||
var aac = TestAac();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var myBools = fx.BoolParameters("MyBoolOne", "MyBoolTwo");
|
||||
var myMandatoryBool = fx.BoolParameter("MyBoolMandatory");
|
||||
first.TransitionsTo(second).When(myBools.IsAnyTrue()).And(myMandatoryBool.IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 2
|
||||
animator.SetBool("MyBoolOne", true);
|
||||
animator.SetBool("MyBoolTwo", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 3
|
||||
animator.SetBool("MyBoolOne", false);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 4
|
||||
animator.SetBool("MyBoolOne", false);
|
||||
animator.SetBool("MyBoolTwo", false);
|
||||
animator.SetBool("MyBoolMandatory", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 5
|
||||
animator.SetBool("MyBoolOne", false);
|
||||
animator.SetBool("MyBoolTwo", true);
|
||||
animator.SetBool("MyBoolMandatory", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
private static AnimatorStateInfo Info0(Animator animator)
|
||||
{
|
||||
return animator.GetCurrentAnimatorStateInfo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 922049111725f1a4ebdd237cddadd542
|
||||
timeCreated: 1671448209
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Assert = UnityEngine.Assertions.Assert;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public class AIACStateTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_should_create_layer_with_state()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var init = fx.NewState("Init");
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
|
||||
// Verify
|
||||
Assert.AreEqual(1, animator.layerCount);
|
||||
var info = animator.GetCurrentAnimatorStateInfo(0);
|
||||
Assert.IsTrue(info.IsName("Init"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_cause_write_defaults_OFF_to_preserve_animated_object_state()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var child = new GameObject
|
||||
{
|
||||
name = "Child",
|
||||
transform = { parent = _root.transform }
|
||||
};
|
||||
var first = fx.NewState("First")
|
||||
.WithWriteDefaultsSetTo(false)
|
||||
.WithAnimation(aac.NewClip().Toggling(child, false));
|
||||
var second = fx.NewState("Second")
|
||||
.WithWriteDefaultsSetTo(false);
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
animator.Update(0f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
Assert.IsFalse(child.gameObject.activeSelf);
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
Assert.IsFalse(child.gameObject.activeSelf);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_cause_write_defaults_ON_to_revert_animated_object_state()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var child = new GameObject
|
||||
{
|
||||
name = "Child",
|
||||
transform = { parent = _root.transform }
|
||||
};
|
||||
var first = fx.NewState("First")
|
||||
.WithWriteDefaultsSetTo(true)
|
||||
.WithAnimation(aac.NewClip().Toggling(child, false));
|
||||
var second = fx.NewState("Second")
|
||||
.WithWriteDefaultsSetTo(true);
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
animator.Update(0f);
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
Assert.IsFalse(child.gameObject.activeSelf);
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
Assert.IsTrue(child.gameObject.activeSelf); // The object turns back on
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_apply_motion_time()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var child = new GameObject
|
||||
{
|
||||
name = "Child",
|
||||
transform = { parent = _root.transform }
|
||||
};
|
||||
fx.NewState("First")
|
||||
.WithAnimation(aac.NewClip().Animating(clip =>
|
||||
{
|
||||
clip.Animates(child.transform, "m_LocalScale.x").WithSecondsUnit(keyframes => keyframes.Linear(0f, 0f).Linear(1f, 10f));
|
||||
}))
|
||||
.MotionTime(fx.FloatParameter("MyFloat"));
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
animator.SetFloat("MyFloat", 0.5f);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.AreEqual(5f, child.transform.localScale.x);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_apply_speed()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var child = new GameObject
|
||||
{
|
||||
name = "Child",
|
||||
transform = { parent = _root.transform }
|
||||
};
|
||||
fx.NewState("First")
|
||||
.WithAnimation(aac.NewClip().Animating(clip =>
|
||||
{
|
||||
clip.Animates(child.transform, "m_LocalScale.x").WithSecondsUnit(keyframes => keyframes.Linear(0f, 0f).Linear(1f, 10f));
|
||||
}))
|
||||
.WithSpeed(fx.FloatParameter("MyFloat"));
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
animator.SetFloat("MyFloat", 2f); // At double the speed
|
||||
animator.Update(15 / 60f); // Advance by a quarter of a second
|
||||
Assert.AreEqual(5f, child.transform.localScale.x);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_apply_speed_set_to_constant()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var child = new GameObject
|
||||
{
|
||||
name = "Child",
|
||||
transform = { parent = _root.transform }
|
||||
};
|
||||
fx.NewState("First")
|
||||
.WithAnimation(aac.NewClip().Animating(clip =>
|
||||
{
|
||||
clip.Animates(child.transform, "m_LocalScale.x").WithSecondsUnit(keyframes => keyframes.Linear(0f, 0f).Linear(1f, 10f));
|
||||
}))
|
||||
.WithSpeedSetTo(2f); // At double the speed
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
animator.Update(15 / 60f); // Advance by a quarter of a second
|
||||
Assert.AreEqual(5f, child.transform.localScale.x);
|
||||
}
|
||||
|
||||
private static AnimatorStateInfo Info0(Animator animator)
|
||||
{
|
||||
return animator.GetCurrentAnimatorStateInfo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82960f1d631a8964f8ae1d774c729625
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Assert = UnityEngine.Assertions.Assert;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public class AIACSubStateMachineTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_should_transition_to_a_SSM()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
ssm.NewState("SSM One");
|
||||
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM One"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_exit_out_of_a_SSM()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
var one = ssm.NewState("SSM One");
|
||||
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
one.Exits().AfterAnimationFinishes();
|
||||
ssm.TransitionsTo(second);
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM One"));
|
||||
|
||||
// Frame 2
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_restart_the_SSM()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
var one = ssm.NewState("SSM One");
|
||||
var two = ssm.NewState("SSM Two");
|
||||
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
one.TransitionsTo(two).AfterAnimationFinishes();
|
||||
two.Exits().AfterAnimationFinishes();
|
||||
ssm.Restarts();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM One"));
|
||||
|
||||
// Frame 2
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM Two"));
|
||||
|
||||
// Frame 3
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM One"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_enter_a_SSM_conditionally__Entry_created_through_SSM_instance()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
ssm.NewState("SSM One");
|
||||
|
||||
var two = ssm.NewState("SSM Two");
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
ssm.EntryTransitionsTo(two).When(fx.BoolParameter("MyBool").IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBool", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM Two"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_enter_a_SSM_conditionally__Entry_created_through_state_instance()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
ssm.NewState("SSM One");
|
||||
|
||||
var two = ssm.NewState("SSM Two");
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
two.TransitionsFromEntry().When(fx.BoolParameter("MyBool").IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBool", true);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM Two"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_enter_the_default_SSM_entry_state_when_conditions_do_not_pass()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var ssm = fx.NewSubStateMachine("SSM");
|
||||
ssm.NewState("SSM One");
|
||||
|
||||
var two = ssm.NewState("SSM Two");
|
||||
first.TransitionsTo(ssm).AfterAnimationFinishes();
|
||||
ssm.EntryTransitionsTo(two).When(fx.BoolParameter("MyBool").IsTrue());
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.SetBool("MyBool", false);
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("SSM One"));
|
||||
}
|
||||
|
||||
private static AnimatorStateInfo Info0(Animator animator)
|
||||
{
|
||||
return animator.GetCurrentAnimatorStateInfo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f4c7c62171d461fb2618bc0c52ba098
|
||||
timeCreated: 1671454674
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
using AnimatorAsCode.V1;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Assert = UnityEngine.Assertions.Assert;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public class AIACTransitionFunctionsTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_should_transition_after_animation_finishes()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var second = fx.NewState("Second");
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0
|
||||
Assert.IsTrue(Info0(animator).IsName("First"));
|
||||
|
||||
// Frame 1
|
||||
animator.Update(1 / 60f);
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_after_animation_finishes_in_2_frames()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.WithAnimation(aac.DummyClipLasting(2, AacFlUnit.Frames));
|
||||
var second = fx.NewState("Second");
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame 0 & 1
|
||||
for (var iter = 0; iter < 2; iter++)
|
||||
{
|
||||
Assert.IsTrue(Info0(animator).IsName("First"), $"In iteration {iter}");
|
||||
animator.Update(1 / 60f);
|
||||
}
|
||||
|
||||
// Frame 2
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_after_animation_finishes_in_3_frames()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.WithAnimation(aac.DummyClipLasting(3, AacFlUnit.Frames));
|
||||
var second = fx.NewState("Second");
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frames [0:2]
|
||||
for (var iter = 0; iter < 3; iter++)
|
||||
{
|
||||
Assert.IsTrue(Info0(animator).IsName("First"), $"In iteration {iter}");
|
||||
animator.Update(1 / 60f);
|
||||
}
|
||||
|
||||
// Frame 3
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_after_animation_finishes_in_59_frames()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.WithAnimation(aac.DummyClipLasting(59, AacFlUnit.Frames));
|
||||
var second = fx.NewState("Second");
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame [0:59]
|
||||
for (var iter = 0; iter < 59; iter++)
|
||||
{
|
||||
Assert.IsTrue(Info0(animator).IsName("First"), $"In iteration {iter}");
|
||||
animator.Update(1 / 60f);
|
||||
}
|
||||
|
||||
// Frame 60
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_should_transition_after_animation_finishes_in_60_frames_with_plus_one_error()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = new AnimatorController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.WithAnimation(aac.DummyClipLasting(60, AacFlUnit.Frames));
|
||||
var second = fx.NewState("Second");
|
||||
first.TransitionsTo(second).AfterAnimationFinishes();
|
||||
|
||||
var animator = _root.AddComponent<Animator>();
|
||||
animator.runtimeAnimatorController = controller;
|
||||
animator.enabled = false;
|
||||
|
||||
// Verify
|
||||
// Frame [0:61] (!!! !!!)
|
||||
var error = 1;
|
||||
for (var iter = 0; iter < 60 + error; iter++)
|
||||
{
|
||||
Assert.IsTrue(Info0(animator).IsName("First"), $"In iteration {iter}");
|
||||
animator.Update(1 / 60f);
|
||||
}
|
||||
|
||||
// Frame 62
|
||||
Assert.IsTrue(Info0(animator).IsName("Second"));
|
||||
}
|
||||
|
||||
private static AnimatorStateInfo Info0(Animator animator)
|
||||
{
|
||||
return animator.GetCurrentAnimatorStateInfo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cef528fbc6d417d8fa3514caf3ed5c1
|
||||
timeCreated: 1671447626
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "AacPlayModeTests",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"AnimatorAsCode.V1",
|
||||
"AnimatorAsCode.V1.VRC"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll",
|
||||
"VRCSDKBase.dll",
|
||||
"VRCSDK3A.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22f62403ac909d54983bb7a357420cfe
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using AnimatorAsCode.V1;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode
|
||||
{
|
||||
public abstract class AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
protected GameObject _root;
|
||||
private AnimatorController _container;
|
||||
private string _containerPath;
|
||||
private AnimatorController _controller;
|
||||
private string _controllerPath;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_root = new GameObject("Root");
|
||||
_container = new AnimatorController();
|
||||
_containerPath = $"Assets/temp_aac_test__container_{Guid.NewGuid()}.asset";
|
||||
AssetDatabase.CreateAsset(_container, _containerPath);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Object.Destroy(_root);
|
||||
AssetDatabase.DeleteAsset(_containerPath);
|
||||
if (_controllerPath != null) AssetDatabase.DeleteAsset(_controllerPath);
|
||||
_root = null;
|
||||
_container = null;
|
||||
_containerPath = null;
|
||||
_controller = null;
|
||||
_controllerPath = null;
|
||||
}
|
||||
|
||||
protected AnimatorController NewPersistentController()
|
||||
{
|
||||
_controller = new AnimatorController();
|
||||
_controllerPath = $"Assets/temp_aac_test__ctrl_{Guid.NewGuid()}.asset";
|
||||
AssetDatabase.CreateAsset(_controller, _controllerPath);
|
||||
return _controller;
|
||||
}
|
||||
|
||||
protected AacFlBase TestAac()
|
||||
{
|
||||
return AacV1.Create(new AacConfiguration
|
||||
{
|
||||
AnimatorRoot = _root.transform,
|
||||
AssetContainer = _container,
|
||||
AssetKey = "None",
|
||||
DefaultsProvider = new AacDefaultsProvider(),
|
||||
SystemName = "Test",
|
||||
DefaultValueRoot = _root.transform
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f1941d210754dfd911bed075ed1b01d
|
||||
timeCreated: 1671447669
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7156157f9fa4cb289a54f1b57f39f3f
|
||||
timeCreated: 1671471108
|
||||
+430
@@ -0,0 +1,430 @@
|
||||
using AnimatorAsCode.V1.VRC;
|
||||
using NUnit.Framework;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests
|
||||
{
|
||||
public class AIACVRCExtensionsDriverGenerationTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_sets_bool_to_true()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.Drives(fx.BoolParameter("MyBool"), true);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyBool", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Set, eParameter.type);
|
||||
Assert.AreEqual(1f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_sets_bool_to_false()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.Drives(fx.BoolParameter("MyBool"), false);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyBool", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Set, eParameter.type);
|
||||
Assert.AreEqual(0f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_sets_int_to_300()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.Drives(fx.IntParameter("MyInt"), 300);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyInt", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Set, eParameter.type);
|
||||
Assert.AreEqual(300f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_sets_float_to_400_point_56()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.Drives(fx.FloatParameter("MyFloat"), 400.56f);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloat", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Set, eParameter.type);
|
||||
Assert.AreEqual(400.56f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_increases_int_by_2()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingIncreases(fx.IntParameter("MyInt"), 2);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyInt", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Add, eParameter.type);
|
||||
Assert.AreEqual(2f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_decreases_int_by_2_through_adding_its_opposite()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingDecreases(fx.IntParameter("MyInt"), 2);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyInt", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Add, eParameter.type);
|
||||
Assert.AreEqual(-2f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_increases_float_by_3_point_4()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingIncreases(fx.FloatParameter("MyFloat"), 3.4f);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloat", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Add, eParameter.type);
|
||||
Assert.AreEqual(3.4f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_decreases_float_by_3_point_4_through_adding_its_opposite()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingDecreases(fx.FloatParameter("MyFloat"), 3.4f);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloat", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Add, eParameter.type);
|
||||
Assert.AreEqual(-3.4f, eParameter.value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_copies_a_bool_to_another_bool()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingCopies(fx.BoolParameter("MyBoolSource"), fx.BoolParameter("MyBoolDestination"));
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyBoolDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsFalse(eParameter.convertRange);
|
||||
Assert.AreEqual("MyBoolSource", eParameter.source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_copies_a_bool_to_an_int()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingCopies(fx.BoolParameter("MyBoolSource"), fx.IntParameter("MyIntDestination"));
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyIntDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsFalse(eParameter.convertRange);
|
||||
Assert.AreEqual("MyBoolSource", eParameter.source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_copies_a_bool_to_a_float()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingCopies(fx.BoolParameter("MyBoolSource"), fx.FloatParameter("MyFloatDestination"));
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloatDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsFalse(eParameter.convertRange);
|
||||
Assert.AreEqual("MyBoolSource", eParameter.source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_copies_an_int_to_another_int()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingCopies(fx.IntParameter("MyIntSource"), fx.IntParameter("MyIntDestination"));
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyIntDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsFalse(eParameter.convertRange);
|
||||
Assert.AreEqual("MyIntSource", eParameter.source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_copies_a_float_to_another_float()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingCopies(fx.FloatParameter("MyFloatSource"), fx.FloatParameter("MyFloatDestination"));
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloatDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsFalse(eParameter.convertRange);
|
||||
Assert.AreEqual("MyFloatSource", eParameter.source);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_remaps_a_bool_to_another_bool_to_invert_its_value()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingRemaps(fx.BoolParameter("MyBoolSource"), false, true, fx.BoolParameter("MyBoolDestination"), true, false);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyBoolDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsTrue(eParameter.convertRange);
|
||||
Assert.AreEqual("MyBoolSource", eParameter.source);
|
||||
Assert.AreEqual(0f, eParameter.sourceMin);
|
||||
Assert.AreEqual(1f, eParameter.sourceMax);
|
||||
Assert.AreEqual(1f, eParameter.destMin);
|
||||
Assert.AreEqual(0f, eParameter.destMax);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_remaps_an_int_percentage_to_a_joystick_float()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingRemaps(fx.IntParameter("MyIntSource"), 0, 100, fx.FloatParameter("MyFloatDestination"), -1f, 1f);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloatDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsTrue(eParameter.convertRange);
|
||||
Assert.AreEqual("MyIntSource", eParameter.source);
|
||||
Assert.AreEqual(0f, eParameter.sourceMin);
|
||||
Assert.AreEqual(100f, eParameter.sourceMax);
|
||||
Assert.AreEqual(-1f, eParameter.destMin);
|
||||
Assert.AreEqual(1f, eParameter.destMax);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_driver_that_remaps_an_analog_float_to_an_inverse_joystick_float()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.DrivingRemaps(fx.FloatParameter("MyFloatSource"), 0, 1f, fx.FloatParameter("MyFloatDestination"), 1f, -1f);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAvatarParameterDriver)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAvatarParameterDriver), eBehaviour.GetType());
|
||||
Assert.AreEqual(1, eBehaviour.parameters.Count);
|
||||
|
||||
var eParameter = eBehaviour.parameters[0];
|
||||
Assert.AreEqual("MyFloatDestination", eParameter.name);
|
||||
Assert.AreEqual(VRC_AvatarParameterDriver.ChangeType.Copy, eParameter.type);
|
||||
Assert.IsTrue(eParameter.convertRange);
|
||||
Assert.AreEqual("MyFloatSource", eParameter.source);
|
||||
Assert.AreEqual(0f, eParameter.sourceMin);
|
||||
Assert.AreEqual(1f, eParameter.sourceMax);
|
||||
Assert.AreEqual(1f, eParameter.destMin);
|
||||
Assert.AreEqual(-1f, eParameter.destMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1445919b64254b28a3330b2111691f7c
|
||||
timeCreated: 1671469798
|
||||
+431
@@ -0,0 +1,431 @@
|
||||
using AnimatorAsCode.V1.VRC;
|
||||
using NUnit.Framework;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests
|
||||
{
|
||||
public class AIACVRCExtensionsMiscGenerationTest : AbstractSimpleSingleLayerAIAC
|
||||
{
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_tracks_head()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Head;
|
||||
first.TrackingTracks(whichElement);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Tracking, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_animates_head()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Head;
|
||||
first.TrackingAnimates(whichElement);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_head_to_tracking()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Head;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Tracking);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Tracking, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_Head_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Head;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_LeftHand_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.LeftHand;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_RightHand_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.RightHand;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_Hip_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Hip;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_LeftFoot_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.LeftFoot;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_RightFoot_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.RightFoot;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_LeftFingers_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.LeftFingers;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_RightFingers_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.RightFingers;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_Eyes_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Eyes;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_Mouth_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
var whichElement = AacAv3.Av3TrackingElement.Mouth;
|
||||
first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingMouth);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void It_generates_a_tracking_that_sets_Head_and_Both_Hands_to_animation()
|
||||
{
|
||||
var aac = TestAac();
|
||||
var controller = NewPersistentController();
|
||||
var fx = aac.CreateMainArbitraryControllerLayer(controller);
|
||||
|
||||
// Exercise
|
||||
var first = fx.NewState("First");
|
||||
first.TrackingSets(AacAv3.Av3TrackingElement.Head, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
first.TrackingSets(AacAv3.Av3TrackingElement.LeftHand, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
first.TrackingSets(AacAv3.Av3TrackingElement.RightHand, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||
|
||||
// Verify
|
||||
var eState = controller.layers[0].stateMachine.states[0].state;
|
||||
Assert.AreEqual(1, eState.behaviours.Length);
|
||||
|
||||
var eBehaviour = (VRCAnimatorTrackingControl)eState.behaviours[0];
|
||||
Assert.AreEqual(typeof(VRCAnimatorTrackingControl), eBehaviour.GetType());
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingHead);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingLeftHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.Animation, eBehaviour.trackingRightHand);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingHip);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFoot);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingLeftFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingRightFingers);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingEyes);
|
||||
Assert.AreEqual(VRC_AnimatorTrackingControl.TrackingType.NoChange, eBehaviour.trackingMouth);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89d6538a829c478d894320a1b1830359
|
||||
timeCreated: 1671494253
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "dev.hai-vr.animator-as-code.v1.base.test",
|
||||
"displayName": "(DEV) Animator As Code - Tests",
|
||||
"version": "1.0.9901",
|
||||
"unity": "2019.4",
|
||||
"description": "dev.hai-vr.animator-as-code.v1.base.test",
|
||||
"vrchatVersion" : "2022.1.1",
|
||||
"author" : {
|
||||
"name" : "Haï~"
|
||||
},
|
||||
"url" : "https://docs.hai-vr.dev/docs/products/animator-as-code/functions/vrchat"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 549150a41d6f00941b76760d487cd9dd
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
.idea
|
||||
Library
|
||||
UnityPackageManager
|
||||
Temp
|
||||
Logs
|
||||
Packages
|
||||
ProjectSettings
|
||||
*.unitypackage
|
||||
Assets/Plugins
|
||||
Assets/Scenes
|
||||
Assets/SerializedUdonPrograms
|
||||
Assets/Udon
|
||||
Assets/VRChat Examples
|
||||
Assets/VRCSDK
|
||||
Assets/Plugins.meta
|
||||
Assets/Scenes.meta
|
||||
Assets/SerializedUdonPrograms.meta
|
||||
Assets/Udon.meta
|
||||
Assets/VRChat Examples.meta
|
||||
Assets/VRCSDK.meta
|
||||
obj
|
||||
cfe-project.sln
|
||||
UnityEditorTests.csproj
|
||||
VRC.Udon.csproj
|
||||
VRC.Udon.Editor.csproj
|
||||
VRC.Udon.Serialization.OdinSerializer.csproj
|
||||
VRCSDK.ShaderStripping.csproj
|
||||
Assembly-CSharp.csproj
|
||||
Assembly-CSharp-Editor.csproj
|
||||
cfe-project.sln.DotSettings.user
|
||||
VRC.SDKBase.Editor.BuildPipeline.csproj
|
||||
VRC.SDKBase.Editor.ShaderStripping.csproj
|
||||
LICENSE.meta
|
||||
README.md.meta
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 539be11e3681218498838a8042383938
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 992235b871999e74492779c2bfe8f958
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,627 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public static class AacV1
|
||||
{
|
||||
/// Create an Animator As Code (AAC) base.
|
||||
public static AacFlBase Create(AacConfiguration configuration)
|
||||
{
|
||||
return new AacFlBase(configuration);
|
||||
}
|
||||
}
|
||||
|
||||
public struct AacConfiguration
|
||||
{
|
||||
public string SystemName;
|
||||
// Please consult "https://docs.hai-vr.dev/docs/products/animator-as-code/migrating-v0-to-v1" on how to migrate this property
|
||||
// public VRCAvatarDescriptor AvatarDescriptor;
|
||||
public Transform AnimatorRoot;
|
||||
public Transform DefaultValueRoot;
|
||||
public AnimatorController AssetContainer;
|
||||
public string AssetKey;
|
||||
public IAacDefaultsProvider DefaultsProvider;
|
||||
public Dictionary<Type, object> AdditionalData; // Nullable
|
||||
|
||||
public AacConfiguration WithAdditonalData(Type key, object value)
|
||||
{
|
||||
var conf = this;
|
||||
if (AdditionalData == null) conf.AdditionalData = new Dictionary<Type, object>();
|
||||
conf.AdditionalData[key] = value;
|
||||
return conf;
|
||||
}
|
||||
|
||||
public bool TryGetAdditionalData(Type key, out object value)
|
||||
{
|
||||
if (AdditionalData != null && AdditionalData.TryGetValue(key, out var result))
|
||||
{
|
||||
value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlLayer
|
||||
{
|
||||
private readonly AnimatorController _animatorController;
|
||||
private readonly AacConfiguration _configuration;
|
||||
private readonly string _fullLayerName;
|
||||
private readonly AacFlStateMachine _stateMachine;
|
||||
|
||||
internal AacFlLayer(AnimatorController animatorController, AacConfiguration configuration, AacFlStateMachine stateMachine, string fullLayerName)
|
||||
{
|
||||
_animatorController = animatorController;
|
||||
_configuration = configuration;
|
||||
_fullLayerName = fullLayerName;
|
||||
_stateMachine = stateMachine;
|
||||
}
|
||||
|
||||
/// Create a new state, initially positioned below the last generated state of this layer.
|
||||
public AacFlState NewState(string name)
|
||||
{
|
||||
var lastState = _stateMachine.LastNodePosition();
|
||||
var state = _stateMachine.NewState(name, 0, 0).Shift(lastState, 0, 1);
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Create a new state at a specific position x and y, in grid units. The grid size is defined in the DefaultsProvider of the AacConfiguration of AAC. x positive goes right, y positive goes down.
|
||||
public AacFlState NewState(string name, int x, int y)
|
||||
{
|
||||
return _stateMachine.NewState(name, x, y);
|
||||
}
|
||||
|
||||
/// Create a new SSM, initially positioned below the last generated state of this layer.
|
||||
public AacFlStateMachine NewSubStateMachine(string name)
|
||||
{
|
||||
return _stateMachine.NewSubStateMachine(name);
|
||||
}
|
||||
|
||||
/// Create a new SSM at a specific position `x` and `y`, in grid units. The grid size is defined in the DefaultsProvider of the AacConfiguration of AAC. `x` positive goes right, `y` positive goes down.
|
||||
public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
|
||||
{
|
||||
return _stateMachine.NewSubStateMachine(name, x, y);
|
||||
}
|
||||
|
||||
/// Create a transition from Any to the `destination` state.
|
||||
public AacFlTransition AnyTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return _stateMachine.AnyTransitionsTo(destination);
|
||||
}
|
||||
|
||||
/// Create a transition from Any to the `destination` SSM.
|
||||
public AacFlTransition AnyTransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return _stateMachine.AnyTransitionsTo(destination);
|
||||
}
|
||||
|
||||
// Create a transition from the Entry to the `destination` state.
|
||||
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return _stateMachine.EntryTransitionsTo(destination);
|
||||
}
|
||||
|
||||
// Create a transition from the Entry to the `destination` state machine.
|
||||
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return _stateMachine.EntryTransitionsTo(destination);
|
||||
}
|
||||
|
||||
/// Create a Bool parameter in the animator.
|
||||
public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.InternalBackingAnimator().BoolParameter(parameterName);
|
||||
|
||||
/// Create a Trigger parameter in the animator, but returns a Bool parameter for use in AAC.
|
||||
public AacFlBoolParameter TriggerParameterAsBool(string parameterName) => _stateMachine.InternalBackingAnimator().TriggerParameter(parameterName);
|
||||
|
||||
/// Create a Float parameter in the animator.
|
||||
public AacFlFloatParameter FloatParameter(string parameterName) => _stateMachine.InternalBackingAnimator().FloatParameter(parameterName);
|
||||
|
||||
/// Create an Int parameter in the animator.
|
||||
public AacFlIntParameter IntParameter(string parameterName) => _stateMachine.InternalBackingAnimator().IntParameter(parameterName);
|
||||
|
||||
/// Create multiple Bool parameters in the animator, and returns a group of multiple Bools.
|
||||
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().BoolParameters(parameterNames);
|
||||
|
||||
/// Create multiple Trigger parameters in the animator, but returns a group of multiple Bools for use in AAC.
|
||||
public AacFlBoolParameterGroup TriggerParametersAsBools(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameterNames);
|
||||
|
||||
/// Create multiple Float parameters in the animator, and returns a group of multiple Floats.
|
||||
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().FloatParameters(parameterNames);
|
||||
|
||||
/// Create multiple Int parameters in the animator, and returns a group of multiple Ints.
|
||||
public AacFlIntParameterGroup IntParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().IntParameters(parameterNames);
|
||||
|
||||
/// Combine multiple Bool parameters into a group.
|
||||
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().BoolParameters(parameters);
|
||||
|
||||
/// Combine multiple Bool parameters into a group. There is no difference with BoolParameters(...) and is provided only for semantic purposes.
|
||||
public AacFlBoolParameterGroup TriggerParametersAsBools(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameters);
|
||||
|
||||
/// Combine multiple Float parameters into a group.
|
||||
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters) => _stateMachine.InternalBackingAnimator().FloatParameters(parameters);
|
||||
|
||||
/// Combine multiple Int parameters into a group.
|
||||
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters) => _stateMachine.InternalBackingAnimator().IntParameters(parameters);
|
||||
|
||||
/// Set the Bool value of `toBeForced` parameter to `value` in the animator.
|
||||
public AacFlLayer OverrideValue(AacFlBoolParameter toBeForced, bool value)
|
||||
{
|
||||
var parameters = _animatorController.parameters;
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.name == toBeForced.Name)
|
||||
{
|
||||
param.defaultBool = value;
|
||||
}
|
||||
}
|
||||
|
||||
_animatorController.parameters = parameters;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Float value of `toBeForced` parameter to `value` in the animator.
|
||||
public AacFlLayer OverrideValue(AacFlFloatParameter toBeForced, float value)
|
||||
{
|
||||
var parameters = _animatorController.parameters;
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.name == toBeForced.Name)
|
||||
{
|
||||
param.defaultFloat = value;
|
||||
}
|
||||
}
|
||||
|
||||
_animatorController.parameters = parameters;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Int value of `toBeForced` parameter to `value` in the animator.
|
||||
public AacFlLayer OverrideValue(AacFlIntParameter toBeForced, int value)
|
||||
{
|
||||
var parameters = _animatorController.parameters;
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
if (param.name == toBeForced.Name)
|
||||
{
|
||||
param.defaultInt = value;
|
||||
}
|
||||
}
|
||||
|
||||
_animatorController.parameters = parameters;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Avatar Mask of the layer.
|
||||
public AacFlLayer WithAvatarMask(AvatarMask avatarMask)
|
||||
{
|
||||
var finalFullLayerName = _fullLayerName;
|
||||
_animatorController.layers = _animatorController.layers
|
||||
.Select(layer =>
|
||||
{
|
||||
if (layer.name == finalFullLayerName)
|
||||
{
|
||||
layer.avatarMask = avatarMask;
|
||||
}
|
||||
|
||||
return layer;
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Avatar Mask of the layer to be an Avatar Mask which denies all transforms. The asset is generated into the container.
|
||||
public AacFlLayer WithAvatarMaskNoTransforms()
|
||||
{
|
||||
ResolveAvatarMask(new Transform[0]);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Avatar Mask of the layer to be an Avatar Mask that allows the specified transforms. If `paths` is an empty array, all transforms are denied, which is effectively the same as calling `.WithAvatarMaskNoTransforms()`. The asset is generated into the container.
|
||||
public AacFlLayer ResolveAvatarMask(Transform[] paths)
|
||||
{
|
||||
// FIXME: Fragile
|
||||
var avatarMask = new AvatarMask();
|
||||
avatarMask.name = "zAutogenerated__" + _configuration.AssetKey + "_" + _fullLayerName + "__AvatarMask";
|
||||
avatarMask.hideFlags = HideFlags.None;
|
||||
|
||||
if (paths.Length == 0)
|
||||
{
|
||||
avatarMask.transformCount = 1;
|
||||
avatarMask.SetTransformActive(0, false);
|
||||
avatarMask.SetTransformPath(0, "_ignored");
|
||||
}
|
||||
else
|
||||
{
|
||||
avatarMask.transformCount = paths.Length;
|
||||
for (var index = 0; index < paths.Length; index++)
|
||||
{
|
||||
var transform = paths[index];
|
||||
avatarMask.SetTransformActive(index, true);
|
||||
avatarMask.SetTransformPath(index, AacInternals.ResolveRelativePath(_configuration.AnimatorRoot, transform));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int) AvatarMaskBodyPart.LastBodyPart; i++)
|
||||
{
|
||||
avatarMask.SetHumanoidBodyPartActive((AvatarMaskBodyPart) i, false);
|
||||
}
|
||||
|
||||
AssetDatabase.AddObjectToAsset(avatarMask, _animatorController);
|
||||
|
||||
WithAvatarMask(avatarMask);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the Default State of the layer.
|
||||
public AacFlLayer WithDefaultState(AacFlState newDefaultState)
|
||||
{
|
||||
_stateMachine.WithDefaultState(newDefaultState);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// NON-PUBLIC: Internal use only so that extensions can access this. Maybe this can be improved
|
||||
public AacFlStateMachine InternalStateMachine()
|
||||
{
|
||||
return _stateMachine;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlBase
|
||||
{
|
||||
private readonly AacConfiguration _configuration;
|
||||
|
||||
/// NON-PUBLIC: Internal use only so that destructive workflow can access this. Maybe this can be improved
|
||||
public AacConfiguration InternalConfiguration()
|
||||
{
|
||||
return _configuration;
|
||||
}
|
||||
|
||||
internal AacFlBase(AacConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
/// Create a new clip. The asset is generated into the container.
|
||||
public AacFlClip NewClip()
|
||||
{
|
||||
var clip = AacInternals.NewClip(_configuration, Guid.NewGuid().ToString());
|
||||
return new AacFlClip(_configuration, clip);
|
||||
}
|
||||
|
||||
/// Create a new clip that is a copy of `originalClip`. The asset is generated into the container.
|
||||
public AacFlClip CopyClip(AnimationClip originalClip)
|
||||
{
|
||||
var newClip = UnityEngine.Object.Instantiate(originalClip);
|
||||
var clip = AacInternals.RegisterClip(_configuration, Guid.NewGuid().ToString(), newClip);
|
||||
return new AacFlClip(_configuration, clip);
|
||||
}
|
||||
|
||||
/// Create a new BlendTree asset. The asset is generated into the container.
|
||||
public AacFlNonInitializedBlendTree NewBlendTree()
|
||||
{
|
||||
return new AacFlNonInitializedBlendTree(AacInternals.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString()));
|
||||
}
|
||||
|
||||
/// Create a new BlendTree asset and returns a native BlendTree object. The asset is generated into the container. You may use NewBlendTree() instead to obtain a fluent interface.
|
||||
public BlendTree NewBlendTreeAsRaw()
|
||||
{
|
||||
return AacInternals.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
/// Create a new clip with a name. However, the name is only used as a suffix for the asset. The asset is generated into the container.
|
||||
public AacFlClip NewClip(string name)
|
||||
{
|
||||
var clip = AacInternals.NewClip(_configuration, name);
|
||||
return new AacFlClip(_configuration, clip);
|
||||
}
|
||||
|
||||
/// Create a new clip which animates a dummy transform for a specific duration specified in an unit (Frames or Seconds).
|
||||
public AacFlClip DummyClipLasting(float numberOf, AacFlUnit unit)
|
||||
{
|
||||
var dummyClip = AacInternals.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})");
|
||||
|
||||
return new AacFlClip(_configuration, dummyClip)
|
||||
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
|
||||
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(numberOf, 0f)));
|
||||
}
|
||||
|
||||
/// Duplicate a new asset into the container and return it. For example, use this to create modified material variants. This asset will be removed the same way as other generated assets.
|
||||
public T DuplicateAsset<T>(T assetToDuplicate) where T : Object
|
||||
{
|
||||
return AacInternals.DuplicateAssetIntoContainer(_configuration, assetToDuplicate);
|
||||
}
|
||||
|
||||
// For backwards compatibility, generates an animation with 2 keyframes that are at a distance of 1 / 60 of 1 frame,
|
||||
// that is 1 / 3600 seconds.
|
||||
// This was due to DummyClipLasting returning a clip with unit conversion applied twice,
|
||||
// resulting in an "undesired" animation which was functional anyways.
|
||||
// Since this dummy clip is used internally on all uninitalized states,
|
||||
// preserve this behaviour so that existing animators don't break due to this change.
|
||||
private AacFlClip AnomalousSingleKeyframeClip()
|
||||
{
|
||||
var numberOf = 1f;
|
||||
var unit = AacFlUnit.Frames;
|
||||
|
||||
var dummyClip = AacInternals.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})");
|
||||
|
||||
var duration = unit == AacFlUnit.Frames ? numberOf / 60f : numberOf;
|
||||
return new AacFlClip(_configuration, dummyClip)
|
||||
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
|
||||
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(duration, 0f)));
|
||||
}
|
||||
|
||||
/// Create a new animator controller. The asset is generated into the container.
|
||||
public AacFlController NewAnimatorController()
|
||||
{
|
||||
var animatorController = AacInternals.NewAnimatorController(_configuration, Guid.NewGuid().ToString());
|
||||
return new AacFlController(_configuration, animatorController, this);
|
||||
}
|
||||
|
||||
/// Create a new animator controller with a name. However, the name is only used as a suffix for the asset. The asset is generated into the container.
|
||||
public AacFlController NewAnimatorController(string name)
|
||||
{
|
||||
var animatorController = AacInternals.NewAnimatorController(_configuration, name);
|
||||
return new AacFlController(_configuration, animatorController, this);
|
||||
}
|
||||
|
||||
//---- ## Destructive workflow
|
||||
|
||||
/// Destructive workflow: Create a main layer for an arbitrary AnimatorController, clearing the previous one of the same system. You are not obligated to have a main layer.
|
||||
public AacFlLayer CreateMainArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName));
|
||||
|
||||
/// Destructive workflow: Create a supporting layer for an arbitrary AnimatorController, clearing the previous one of the same system and suffix. You can create multiple supporting layers with different suffixes, and you are not obligated to have a main layer to create a supporting layer.
|
||||
public AacFlLayer CreateSupportingArbitraryControllerLayer(AnimatorController controller, string suffix) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
|
||||
|
||||
/// Destructive workflow: Clears the topmost layer of an arbitrary AnimatorController, and returns it.
|
||||
public AacFlLayer CreateFirstArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, controller.layers[0].name);
|
||||
|
||||
/// NON-PUBLIC: Internal use only so that destructive workflow can access this. Maybe this can be improved
|
||||
public AacFlLayer InternalDoCreateLayer(AnimatorController animator, string layerName)
|
||||
{
|
||||
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
|
||||
var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f);
|
||||
|
||||
return new AacFlLayer(animator, _configuration, machine, layerName);
|
||||
}
|
||||
|
||||
internal AacFlLayer DoCreateLayerWithoutDeleting(AnimatorController animator, string layerName)
|
||||
{
|
||||
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
|
||||
var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f, null, false);
|
||||
|
||||
return new AacFlLayer(animator, _configuration, machine, layerName);
|
||||
}
|
||||
|
||||
private AacFlClip CreateEmptyClip()
|
||||
{
|
||||
var emptyClip = AnomalousSingleKeyframeClip();
|
||||
return emptyClip;
|
||||
}
|
||||
|
||||
/// Removes all assets from the asset container matching the specified asset key.
|
||||
public void ClearPreviousAssets()
|
||||
{
|
||||
var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer));
|
||||
foreach (var subAsset in allSubAssets)
|
||||
{
|
||||
if (subAsset.name.StartsWith($"zAutogenerated__{_configuration.AssetKey}__")
|
||||
&& (subAsset is AnimationClip || subAsset is BlendTree || subAsset is AvatarMask))
|
||||
{
|
||||
AssetDatabase.RemoveObjectFromAsset(subAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// If you are not creating an animator, this returns an object from which you can obtain animator parameter objects. You should use this class if you are creating BlendTree assets without any animator controllers to back it. Otherwise, it is strongly recommended to obtain animator parameter objects directly from the layer objects instead of using NoAnimator(), as the use of NoAnimator() will not result in the registration of any parameters inside the animator controller.
|
||||
public AacFlNoAnimator NoAnimator()
|
||||
{
|
||||
return new AacFlNoAnimator();
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlNoAnimator
|
||||
{
|
||||
/// Create a Float parameter, for use without a backing animator.
|
||||
public AacFlFloatParameter FloatParameter(string parameterName) => AacFlFloatParameter.Internally(parameterName);
|
||||
|
||||
/// Create a Int parameter, for use without a backing animator.
|
||||
public AacFlIntParameter IntParameter(string parameterName) => AacFlIntParameter.Internally(parameterName);
|
||||
|
||||
/// Create a Bool parameter, for use without a backing animator.
|
||||
public AacFlBoolParameter BoolParameter(string parameterName) => AacFlBoolParameter.Internally(parameterName);
|
||||
}
|
||||
|
||||
public class AacFlController
|
||||
{
|
||||
public AnimatorController AnimatorController;
|
||||
|
||||
private readonly AacConfiguration _configuration;
|
||||
private readonly AacFlBase _base;
|
||||
|
||||
public AacFlController(AacConfiguration configuration, AnimatorController animatorController, AacFlBase originalBase)
|
||||
{
|
||||
AnimatorController = animatorController;
|
||||
_configuration = configuration;
|
||||
_base = originalBase;
|
||||
}
|
||||
|
||||
public AacFlLayer NewLayer(string suffix) => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
|
||||
public AacFlLayer NewLayer() => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.SystemName);
|
||||
}
|
||||
|
||||
public class AacAnimatorRemoval
|
||||
{
|
||||
private readonly AnimatorController _animatorController;
|
||||
|
||||
public AacAnimatorRemoval(AnimatorController animatorController)
|
||||
{
|
||||
_animatorController = animatorController;
|
||||
}
|
||||
|
||||
public void RemoveLayer(string layerName)
|
||||
{
|
||||
var index = FindIndexOf(layerName);
|
||||
if (index == -1) return;
|
||||
|
||||
AacInternals.NoUndo(_animatorController, () => _animatorController.RemoveLayer(index));
|
||||
}
|
||||
|
||||
private int FindIndexOf(string layerName)
|
||||
{
|
||||
return _animatorController.layers.ToList().FindIndex(layer => layer.name == layerName);
|
||||
}
|
||||
}
|
||||
|
||||
public class AacAnimatorGenerator
|
||||
{
|
||||
private readonly AnimatorController _animatorController;
|
||||
private readonly AnimationClip _emptyClip;
|
||||
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||
|
||||
internal AacAnimatorGenerator(AnimatorController animatorController, AnimationClip emptyClip, IAacDefaultsProvider defaultsProvider)
|
||||
{
|
||||
_animatorController = animatorController;
|
||||
_emptyClip = emptyClip;
|
||||
_defaultsProvider = defaultsProvider;
|
||||
}
|
||||
|
||||
internal void CreateParamsAsNeeded(params AacFlParameter[] parameters)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
switch (parameter)
|
||||
{
|
||||
case AacFlIntParameter _:
|
||||
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Int);
|
||||
break;
|
||||
case AacFlFloatParameter _:
|
||||
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Float);
|
||||
break;
|
||||
case AacFlBoolParameter _:
|
||||
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Bool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal void CreateTriggerParamsAsNeeded(params AacFlBoolParameter[] parameters)
|
||||
{
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Trigger);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateParamIfNotExists(string paramName, AnimatorControllerParameterType type)
|
||||
{
|
||||
if (_animatorController.parameters.FirstOrDefault(param => param.name == paramName) == null)
|
||||
{
|
||||
AacInternals.NoUndo(_animatorController, () => _animatorController.AddParameter(paramName, type));
|
||||
}
|
||||
}
|
||||
|
||||
// DEPRECATED: This causes the editor window to glitch by deselecting, which is jarring for experimentation
|
||||
internal AacFlStateMachine CreateOrRemakeLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
|
||||
{
|
||||
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
|
||||
if (originalIndexToPreserveOrdering != -1)
|
||||
{
|
||||
AacInternals.NoUndo(_animatorController, () => _animatorController.RemoveLayer(originalIndexToPreserveOrdering));
|
||||
}
|
||||
|
||||
AddLayerWithWeight(layerName, weightWhenCreating, maskWhenCreating);
|
||||
if (originalIndexToPreserveOrdering != -1)
|
||||
{
|
||||
var items = _animatorController.layers.ToList();
|
||||
var last = items[items.Count - 1];
|
||||
items.RemoveAt(items.Count - 1);
|
||||
items.Insert(originalIndexToPreserveOrdering, last);
|
||||
_animatorController.layers = items.ToArray();
|
||||
}
|
||||
|
||||
var layer = TryGetLayer(layerName);
|
||||
var machinist = new AacFlStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
|
||||
return machinist
|
||||
.WithAnyStatePosition(0, 7)
|
||||
.WithEntryPosition(0, -1)
|
||||
.WithExitPosition(7, -1);
|
||||
}
|
||||
|
||||
internal AacFlStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null, bool allowDeletion = true)
|
||||
{
|
||||
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
|
||||
if (originalIndexToPreserveOrdering != -1)
|
||||
{
|
||||
if (!allowDeletion)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot create layer with name {layerName} as it already exists. When creating layers using NewAnimatorController, you may only use unique names.");
|
||||
}
|
||||
RecursivelyClearChildrenMachines(_animatorController.layers[originalIndexToPreserveOrdering].stateMachine);
|
||||
|
||||
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines = new ChildAnimatorStateMachine[0];
|
||||
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.states = new ChildAnimatorState[0];
|
||||
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.entryTransitions = new AnimatorTransition[0];
|
||||
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.anyStateTransitions = new AnimatorStateTransition[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
AacInternals.NoUndo(_animatorController, () => _animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName)));
|
||||
originalIndexToPreserveOrdering = _animatorController.layers.Length - 1;
|
||||
}
|
||||
|
||||
var layers = _animatorController.layers;
|
||||
layers[originalIndexToPreserveOrdering].avatarMask = maskWhenCreating;
|
||||
layers[originalIndexToPreserveOrdering].defaultWeight = weightWhenCreating;
|
||||
_animatorController.layers = layers;
|
||||
|
||||
var layer = TryGetLayer(layerName);
|
||||
var machinist = new AacFlStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
|
||||
_defaultsProvider.ConfigureStateMachine(layer.stateMachine);
|
||||
return machinist;
|
||||
}
|
||||
|
||||
private void RecursivelyClearChildrenMachines(AnimatorStateMachine parentMachine)
|
||||
{
|
||||
// TODO: RemoveStateMachine might already be recursive
|
||||
foreach (var childStateMachineHolder in parentMachine.stateMachines)
|
||||
{
|
||||
RecursivelyClearChildrenMachines(childStateMachineHolder.stateMachine);
|
||||
AacInternals.NoUndo(parentMachine, () => parentMachine.RemoveStateMachine(childStateMachineHolder.stateMachine));
|
||||
}
|
||||
}
|
||||
|
||||
private int FindIndexOf(string layerName)
|
||||
{
|
||||
return _animatorController.layers.ToList().FindIndex(layer1 => layer1.name == layerName);
|
||||
}
|
||||
|
||||
private AnimatorControllerLayer TryGetLayer(string layerName)
|
||||
{
|
||||
return _animatorController.layers.FirstOrDefault(it => it.name == layerName);
|
||||
}
|
||||
|
||||
private void AddLayerWithWeight(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating)
|
||||
{
|
||||
AacInternals.NoUndo(_animatorController, () => _animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName)));
|
||||
|
||||
var mutatedLayers = _animatorController.layers;
|
||||
mutatedLayers[mutatedLayers.Length - 1].defaultWeight = weightWhenCreating;
|
||||
mutatedLayers[mutatedLayers.Length - 1].avatarMask = maskWhenCreating;
|
||||
_animatorController.layers = mutatedLayers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32d38102c095fd942b9ec14bb5f85bb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public abstract class AacAnimatorNode
|
||||
{
|
||||
protected internal abstract Vector3 GetPosition();
|
||||
protected internal abstract void SetPosition(Vector3 position);
|
||||
}
|
||||
|
||||
public abstract class AacAnimatorNode<TNode> : AacAnimatorNode where TNode : AacAnimatorNode<TNode>
|
||||
{
|
||||
protected readonly AacFlStateMachine ParentMachine;
|
||||
protected readonly IAacDefaultsProvider DefaultsProvider;
|
||||
|
||||
protected AacAnimatorNode(AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider)
|
||||
{
|
||||
ParentMachine = parentMachine;
|
||||
DefaultsProvider = defaultsProvider;
|
||||
}
|
||||
|
||||
public TNode LeftOf(AacAnimatorNode otherNode) => MoveNextTo(otherNode, -1, 0);
|
||||
public TNode RightOf(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 1, 0);
|
||||
public TNode Over(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 0, -1);
|
||||
public TNode Under(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 0, 1);
|
||||
|
||||
public TNode LeftOf() => MoveNextTo(null, -1, 0);
|
||||
public TNode RightOf() => MoveNextTo(null, 1, 0);
|
||||
public TNode Over() => MoveNextTo(null, 0, -1);
|
||||
public TNode Under() => MoveNextTo(null, 0, 1);
|
||||
|
||||
public TNode Shift(AacAnimatorNode otherState, int shiftX, int shiftY) => MoveNextTo(otherState, shiftX, shiftY);
|
||||
|
||||
private TNode MoveNextTo(AacAnimatorNode otherStateOrSecondToLastWhenNull, int x, int y)
|
||||
{
|
||||
if (otherStateOrSecondToLastWhenNull == null)
|
||||
{
|
||||
var siblings = ParentMachine.GetChildNodes();
|
||||
var other = siblings[siblings.Count - 2];
|
||||
Shift(other.GetPosition(), x, y);
|
||||
|
||||
return (TNode) this;
|
||||
}
|
||||
|
||||
Shift(otherStateOrSecondToLastWhenNull.GetPosition(), x, y);
|
||||
|
||||
return (TNode) this;
|
||||
}
|
||||
|
||||
public TNode Shift(Vector3 otherPosition, int shiftX, int shiftY)
|
||||
{
|
||||
SetPosition(otherPosition + new Vector3(shiftX * DefaultsProvider.Grid().x, shiftY * DefaultsProvider.Grid().y, 0));
|
||||
return (TNode) this;
|
||||
}
|
||||
|
||||
public abstract TBehaviour EnsureBehaviour<TBehaviour>() where TBehaviour : StateMachineBehaviour;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f18060d238ee5549aac66b09f36e9e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public interface IAacDefaultsProvider
|
||||
{
|
||||
void ConfigureState(AnimatorState state, AnimationClip emptyClip);
|
||||
void ConfigureTransition(AnimatorStateTransition transition);
|
||||
string ConvertLayerName(string systemName);
|
||||
string ConvertLayerNameWithSuffix(string systemName, string suffix);
|
||||
Vector2 Grid();
|
||||
void ConfigureStateMachine(AnimatorStateMachine stateMachine);
|
||||
}
|
||||
|
||||
public class AacDefaultsProvider : IAacDefaultsProvider
|
||||
{
|
||||
private readonly bool _writeDefaults;
|
||||
|
||||
public AacDefaultsProvider(bool writeDefaults = false)
|
||||
{
|
||||
_writeDefaults = writeDefaults;
|
||||
}
|
||||
|
||||
public virtual void ConfigureState(AnimatorState state, AnimationClip emptyClip)
|
||||
{
|
||||
state.motion = emptyClip;
|
||||
state.writeDefaultValues = _writeDefaults;
|
||||
}
|
||||
|
||||
public virtual void ConfigureTransition(AnimatorStateTransition transition)
|
||||
{
|
||||
transition.duration = 0;
|
||||
transition.hasExitTime = false;
|
||||
transition.exitTime = 0;
|
||||
transition.hasFixedDuration = true;
|
||||
transition.offset = 0;
|
||||
transition.interruptionSource = TransitionInterruptionSource.None;
|
||||
transition.orderedInterruption = true;
|
||||
transition.canTransitionToSelf = false;
|
||||
}
|
||||
|
||||
public virtual string ConvertLayerName(string systemName)
|
||||
{
|
||||
return systemName;
|
||||
}
|
||||
|
||||
public virtual string ConvertLayerNameWithSuffix(string systemName, string suffix)
|
||||
{
|
||||
return $"{systemName}__{suffix}";
|
||||
}
|
||||
|
||||
public Vector2 Grid()
|
||||
{
|
||||
return new Vector2(250, 70);
|
||||
}
|
||||
|
||||
public void ConfigureStateMachine(AnimatorStateMachine stateMachine)
|
||||
{
|
||||
var grid = Grid();
|
||||
stateMachine.anyStatePosition = grid * new Vector2(0, 7);
|
||||
stateMachine.entryPosition = grid * new Vector2(0, -1);
|
||||
stateMachine.exitPosition = grid * new Vector2(7, -1);
|
||||
stateMachine.parentStateMachinePosition = grid * new Vector2(3, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50ded138f79d4ba4cacd0e924a60f40b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,498 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public class AacFlClip
|
||||
{
|
||||
private readonly AacConfiguration _component;
|
||||
public AnimationClip Clip { get; }
|
||||
|
||||
public AacFlClip(AacConfiguration component, AnimationClip clip)
|
||||
{
|
||||
_component = component;
|
||||
Clip = clip;
|
||||
}
|
||||
|
||||
public AacFlClip Looping()
|
||||
{
|
||||
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
|
||||
settings.loopTime = true;
|
||||
AnimationUtility.SetAnimationClipSettings(Clip, settings);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip NonLooping()
|
||||
{
|
||||
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
|
||||
settings.loopTime = false;
|
||||
AnimationUtility.SetAnimationClipSettings(Clip, settings);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip Animating(Action<AacFlEditClip> action)
|
||||
{
|
||||
action.Invoke(new AacFlEditClip(_component, Clip));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip Toggling(GameObject[] gameObjectsWithNulls, bool value)
|
||||
{
|
||||
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||
foreach (var component in defensiveObjects)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(GameObject), component.transform, "m_IsActive");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip BlendShape(SkinnedMeshRenderer renderer, string blendShapeName, float value)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(SkinnedMeshRenderer), renderer.transform, $"blendShape.{blendShapeName}");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip BlendShape(SkinnedMeshRenderer[] rendererWithNulls, string blendShapeName, float value)
|
||||
{
|
||||
var defensiveObjects = rendererWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||
foreach (var component in defensiveObjects)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(SkinnedMeshRenderer), component.transform, $"blendShape.{blendShapeName}");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip Scaling(GameObject[] gameObjectsWithNulls, Vector3 scale)
|
||||
{
|
||||
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||
foreach (var component in defensiveObjects)
|
||||
{
|
||||
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.x"), AacInternals.OneFrame(scale.x));
|
||||
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.y"), AacInternals.OneFrame(scale.y));
|
||||
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.z"), AacInternals.OneFrame(scale.z));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip Toggling(GameObject gameObject, bool value)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip TogglingComponent(Component[] componentsWithNulls, bool value)
|
||||
{
|
||||
var defensiveComponents = componentsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||
foreach (var component in defensiveComponents)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, component.GetType(), component.transform, "m_Enabled");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip TogglingComponent(Component component, bool value)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, component.GetType(), component.transform, "m_Enabled");
|
||||
|
||||
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip SwappingMaterial(Renderer renderer, int slot, Material material)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, renderer.GetType(), renderer.transform, $"m_Materials.Array.data[{slot}]");
|
||||
|
||||
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
|
||||
new ObjectReferenceKeyframe { time = 0f, value = material },
|
||||
new ObjectReferenceKeyframe { time = 1/60f, value = material }
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlClip SwappingMaterial(ParticleSystem particleSystem, int slot, Material material)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(ParticleSystemRenderer), particleSystem.transform, $"m_Materials.Array.data[{slot}]");
|
||||
|
||||
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
|
||||
new ObjectReferenceKeyframe { time = 0f, value = material },
|
||||
new ObjectReferenceKeyframe { time = 1/60f, value = material }
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlEditClip
|
||||
{
|
||||
private readonly AacConfiguration _component;
|
||||
public AnimationClip Clip { get; }
|
||||
|
||||
public AacFlEditClip(AacConfiguration component, AnimationClip clip)
|
||||
{
|
||||
_component = component;
|
||||
Clip = clip;
|
||||
}
|
||||
|
||||
public AacFlSettingCurve Animates(string path, Type type, string propertyName)
|
||||
{
|
||||
var binding = new EditorCurveBinding
|
||||
{
|
||||
path = path,
|
||||
type = type,
|
||||
propertyName = propertyName
|
||||
};
|
||||
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurve Animates(Transform transform, Type type, string propertyName)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, type, transform, propertyName);
|
||||
|
||||
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurve Animates(GameObject gameObject)
|
||||
{
|
||||
var binding = AacInternals.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
|
||||
|
||||
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurve Animates(Component anyComponent, string property)
|
||||
{
|
||||
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||
|
||||
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurve Animates(Component[] anyComponents, string property)
|
||||
{
|
||||
var that = this;
|
||||
var bindings = anyComponents
|
||||
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
|
||||
.ToArray();
|
||||
|
||||
return new AacFlSettingCurve(Clip, bindings);
|
||||
}
|
||||
|
||||
public AacFlSettingCurve AnimatesAnimator(AacFlParameter floatParameter)
|
||||
{
|
||||
var binding = new EditorCurveBinding
|
||||
{
|
||||
path = "",
|
||||
type = typeof(Animator),
|
||||
propertyName = floatParameter.Name
|
||||
};
|
||||
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurveColor AnimatesColor(Component anyComponent, string property)
|
||||
{
|
||||
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||
return new AacFlSettingCurveColor(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public AacFlSettingCurveColor AnimatesColor(Component[] anyComponents, string property)
|
||||
{
|
||||
var that = this;
|
||||
var bindings = anyComponents
|
||||
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
|
||||
.ToArray();
|
||||
|
||||
return new AacFlSettingCurveColor(Clip, bindings);
|
||||
}
|
||||
|
||||
public AacFlSettingCurveColor AnimatesHDRColor(Component anyComponent, string property)
|
||||
{
|
||||
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||
return new AacFlSettingCurveColor(Clip, new[] {binding}, true);
|
||||
}
|
||||
|
||||
public AacFlSettingCurveObjectReference AnimatesObjectReference(Component anyComponent, string property)
|
||||
{
|
||||
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||
return new AacFlSettingCurveObjectReference(Clip, new[] {binding});
|
||||
}
|
||||
|
||||
public EditorCurveBinding BindingFromComponent(Component anyComponent, string propertyName)
|
||||
{
|
||||
return Internal_BindingFromComponent(anyComponent, propertyName);
|
||||
}
|
||||
|
||||
private EditorCurveBinding Internal_BindingFromComponent(Component anyComponent, string propertyName)
|
||||
{
|
||||
return AacInternals.Binding(_component, anyComponent.GetType(), anyComponent.transform, propertyName);
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlSettingCurve
|
||||
{
|
||||
private readonly AnimationClip _clip;
|
||||
private readonly EditorCurveBinding[] _bindings;
|
||||
|
||||
public AacFlSettingCurve(AnimationClip clip, EditorCurveBinding[] bindings)
|
||||
{
|
||||
_clip = clip;
|
||||
_bindings = bindings;
|
||||
}
|
||||
|
||||
public void WithOneFrame(float desiredValue)
|
||||
{
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, binding, AacInternals.OneFrame(desiredValue));
|
||||
}
|
||||
}
|
||||
|
||||
public void WithFixedSeconds(float seconds, float desiredValue)
|
||||
{
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, binding, AacInternals.ConstantSeconds(seconds, desiredValue));
|
||||
}
|
||||
}
|
||||
|
||||
public void WithSecondsUnit(Action<AacFlSettingKeyframes> action)
|
||||
{
|
||||
InternalWithUnit(AacFlUnit.Seconds, action);
|
||||
}
|
||||
|
||||
public void WithFrameCountUnit(Action<AacFlSettingKeyframes> action)
|
||||
{
|
||||
InternalWithUnit(AacFlUnit.Frames, action);
|
||||
}
|
||||
|
||||
public void WithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
|
||||
{
|
||||
InternalWithUnit(unit, action);
|
||||
}
|
||||
|
||||
private void InternalWithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
|
||||
{
|
||||
var mutatedKeyframes = new List<Keyframe>();
|
||||
var builder = new AacFlSettingKeyframes(unit, mutatedKeyframes);
|
||||
action.Invoke(builder);
|
||||
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, binding, new AnimationCurve(mutatedKeyframes.ToArray()));
|
||||
}
|
||||
}
|
||||
|
||||
public void WithAnimationCurve(AnimationCurve animationCurve)
|
||||
{
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, binding, animationCurve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlSettingCurveObjectReference
|
||||
{
|
||||
private readonly AnimationClip _clip;
|
||||
private readonly EditorCurveBinding[] _bindings;
|
||||
|
||||
public AacFlSettingCurveObjectReference(AnimationClip clip, EditorCurveBinding[] bindings)
|
||||
{
|
||||
_clip = clip;
|
||||
_bindings = bindings;
|
||||
}
|
||||
|
||||
public void WithOneFrame(Object objectReference)
|
||||
{
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AnimationUtility.SetObjectReferenceCurve(_clip, binding, new[]
|
||||
{
|
||||
new ObjectReferenceKeyframe { time = 0f, value = objectReference },
|
||||
new ObjectReferenceKeyframe { time = 1/60f, value = objectReference }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlSettingCurveColor
|
||||
{
|
||||
private readonly AnimationClip _clip;
|
||||
private readonly EditorCurveBinding[] _bindings;
|
||||
private readonly bool _hdr;
|
||||
|
||||
public AacFlSettingCurveColor(AnimationClip clip, EditorCurveBinding[] bindings, bool hdr = false)
|
||||
{
|
||||
_clip = clip;
|
||||
_bindings = bindings;
|
||||
_hdr = hdr;
|
||||
}
|
||||
|
||||
public void WithOneFrame(Color desiredValue)
|
||||
{
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "x" : "r"), AacInternals.OneFrame(desiredValue.r));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "y" : "g"), AacInternals.OneFrame(desiredValue.g));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "z" : "b"), AacInternals.OneFrame(desiredValue.b));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "w" : "a"), AacInternals.OneFrame(desiredValue.a));
|
||||
}
|
||||
}
|
||||
|
||||
public void WithKeyframes(AacFlUnit unit, Action<AacFlSettingKeyframesColor> action)
|
||||
{
|
||||
var mutatedKeyframesR = new List<Keyframe>();
|
||||
var mutatedKeyframesG = new List<Keyframe>();
|
||||
var mutatedKeyframesB = new List<Keyframe>();
|
||||
var mutatedKeyframesA = new List<Keyframe>();
|
||||
var builder = new AacFlSettingKeyframesColor(unit, mutatedKeyframesR, mutatedKeyframesG, mutatedKeyframesB, mutatedKeyframesA);
|
||||
action.Invoke(builder);
|
||||
|
||||
foreach (var binding in _bindings)
|
||||
{
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "x" : "r"), new AnimationCurve(mutatedKeyframesR.ToArray()));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "y" : "g"), new AnimationCurve(mutatedKeyframesG.ToArray()));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "z" : "b"), new AnimationCurve(mutatedKeyframesB.ToArray()));
|
||||
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "w" : "a"), new AnimationCurve(mutatedKeyframesA.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlSettingKeyframes
|
||||
{
|
||||
private readonly AacFlUnit _unit;
|
||||
private readonly List<Keyframe> _mutatedKeyframes;
|
||||
|
||||
public AacFlSettingKeyframes(AacFlUnit unit, List<Keyframe> mutatedKeyframes)
|
||||
{
|
||||
_unit = unit;
|
||||
_mutatedKeyframes = mutatedKeyframes;
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframes Easing(float timeInUnit, float value)
|
||||
{
|
||||
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, 0, 0));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframes Constant(float timeInUnit, float value)
|
||||
{
|
||||
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, 0, float.PositiveInfinity));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframes Linear(float timeInUnit, float value)
|
||||
{
|
||||
float valueEnd = value;
|
||||
float valueStart = _mutatedKeyframes.Count == 0 ? value : _mutatedKeyframes.Last().value;
|
||||
float timeEnd = AsSeconds(timeInUnit);
|
||||
float timeStart = _mutatedKeyframes.Count == 0 ? value : _mutatedKeyframes.Last().time;
|
||||
float num = (float) (((double) valueEnd - (double) valueStart) / ((double) timeEnd - (double) timeStart));
|
||||
// FIXME: This can cause NaN tangents which messes everything
|
||||
|
||||
// return new AnimationCurve(new Keyframe[2]
|
||||
// {
|
||||
// new Keyframe(timeStart, valueStart, 0.0f, num),
|
||||
// new Keyframe(timeEnd, valueEnd, num, 0.0f)
|
||||
// });
|
||||
|
||||
if (_mutatedKeyframes.Count > 0)
|
||||
{
|
||||
var lastKeyframe = _mutatedKeyframes.Last();
|
||||
lastKeyframe.outTangent = num;
|
||||
_mutatedKeyframes[_mutatedKeyframes.Count - 1] = lastKeyframe;
|
||||
}
|
||||
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, num, 0.0f));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private float AsSeconds(float timeInUnit)
|
||||
{
|
||||
switch (_unit)
|
||||
{
|
||||
case AacFlUnit.Frames:
|
||||
return timeInUnit / 60f;
|
||||
case AacFlUnit.Seconds:
|
||||
return timeInUnit;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlSettingKeyframesColor
|
||||
{
|
||||
private AacFlSettingKeyframes _r;
|
||||
private AacFlSettingKeyframes _g;
|
||||
private AacFlSettingKeyframes _b;
|
||||
private AacFlSettingKeyframes _a;
|
||||
|
||||
public AacFlSettingKeyframesColor(AacFlUnit unit, List<Keyframe> mutatedKeyframesR, List<Keyframe> mutatedKeyframesG, List<Keyframe> mutatedKeyframesB, List<Keyframe> mutatedKeyframesA)
|
||||
{
|
||||
_r = new AacFlSettingKeyframes(unit, mutatedKeyframesR);
|
||||
_g = new AacFlSettingKeyframes(unit, mutatedKeyframesG);
|
||||
_b = new AacFlSettingKeyframes(unit, mutatedKeyframesB);
|
||||
_a = new AacFlSettingKeyframes(unit, mutatedKeyframesA);
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframesColor Easing(int frame, Color value)
|
||||
{
|
||||
_r.Easing(frame, value.r);
|
||||
_g.Easing(frame, value.g);
|
||||
_b.Easing(frame, value.b);
|
||||
_a.Easing(frame, value.a);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframesColor Linear(float frame, Color value)
|
||||
{
|
||||
_r.Linear(frame, value.r);
|
||||
_g.Linear(frame, value.g);
|
||||
_b.Linear(frame, value.b);
|
||||
_a.Linear(frame, value.a);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlSettingKeyframesColor Constant(int frame, Color value)
|
||||
{
|
||||
_r.Constant(frame, value.r);
|
||||
_g.Constant(frame, value.g);
|
||||
_b.Constant(frame, value.b);
|
||||
_a.Constant(frame, value.a);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AacFlUnit
|
||||
{
|
||||
Frames, Seconds
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3422c7eab85fed543b3ccc3384e55679
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public class AacFlBlendTree
|
||||
{
|
||||
protected AacFlBlendTree(BlendTree blendTree)
|
||||
{
|
||||
BlendTree = blendTree;
|
||||
}
|
||||
|
||||
public BlendTree BlendTree { get; }
|
||||
}
|
||||
|
||||
public class AacFlNonInitializedBlendTree : AacFlBlendTree
|
||||
{
|
||||
public AacFlNonInitializedBlendTree(BlendTree blendTree) : base(blendTree)
|
||||
{
|
||||
}
|
||||
|
||||
// Define this BlendTree as being FreeformCartesian2D.
|
||||
public AacFlBlendTree2D FreeformCartesian2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
|
||||
{
|
||||
return New2DBlendTree(parameterX, parameterY, BlendTreeType.FreeformCartesian2D);
|
||||
}
|
||||
|
||||
// Define this BlendTree as being FreeformDirectional2D.
|
||||
public AacFlBlendTree2D FreeformDirectional2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
|
||||
{
|
||||
return New2DBlendTree(parameterX, parameterY, BlendTreeType.FreeformDirectional2D);
|
||||
}
|
||||
|
||||
// Define this BlendTree as being SimpleDirectional2D.
|
||||
public AacFlBlendTree2D SimpleDirectional2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
|
||||
{
|
||||
return New2DBlendTree(parameterX, parameterY, BlendTreeType.SimpleDirectional2D);
|
||||
}
|
||||
|
||||
// Define this BlendTree as being Simple1D.
|
||||
public AacFlBlendTree1D Simple1D(AacFlFloatParameter parameter)
|
||||
{
|
||||
BlendTree.blendType = BlendTreeType.Simple1D;
|
||||
BlendTree.blendParameter = parameter.Name;
|
||||
BlendTree.useAutomaticThresholds = false;
|
||||
|
||||
return new AacFlBlendTree1D(BlendTree);
|
||||
}
|
||||
|
||||
// Define this BlendTree as being Direct.
|
||||
public AacFlBlendTreeDirect Direct()
|
||||
{
|
||||
BlendTree.blendType = BlendTreeType.Direct;
|
||||
|
||||
return new AacFlBlendTreeDirect(BlendTree);
|
||||
}
|
||||
|
||||
private AacFlBlendTree2D New2DBlendTree(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY, BlendTreeType blendTreeType)
|
||||
{
|
||||
BlendTree.blendType = blendTreeType;
|
||||
BlendTree.blendParameter = parameterX.Name;
|
||||
BlendTree.blendParameterY = parameterY.Name;
|
||||
|
||||
return new AacFlBlendTree2D(BlendTree);
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlBlendTree2D : AacFlBlendTree
|
||||
{
|
||||
public AacFlBlendTree2D(BlendTree blendTree) : base(blendTree)
|
||||
{
|
||||
}
|
||||
|
||||
// Add a BlendTree in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(blendTree.BlendTree, pos, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a BlendTree in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(blendTree.BlendTree, x, y, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a Clip in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(AacFlClip clip, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(clip.Clip, pos, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a Clip in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(AacFlClip clip, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(clip.Clip, x, y, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a raw motion in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(Motion motion, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(motion, pos.x, pos.y, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a raw motion in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree2D WithAnimation(Motion motion, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
var children = BlendTree.children ?? new ChildMotion[0];
|
||||
var childrenList = children.ToList();
|
||||
|
||||
|
||||
var childMotionModifier = new AacFlBlendTreeChildMotion();
|
||||
furtherDefiningChild?.Invoke(childMotionModifier);
|
||||
var newChildMotion = new ChildMotion
|
||||
{
|
||||
motion = motion,
|
||||
position = new Vector2(x, y),
|
||||
timeScale = childMotionModifier.TimeScale,
|
||||
mirror = childMotionModifier.Mirror,
|
||||
cycleOffset = childMotionModifier.CycleOffset
|
||||
};
|
||||
|
||||
childrenList.Add(newChildMotion);
|
||||
BlendTree.children = childrenList.ToArray();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlBlendTree1D : AacFlBlendTree
|
||||
{
|
||||
public AacFlBlendTree1D(BlendTree blendTree) : base(blendTree)
|
||||
{
|
||||
}
|
||||
|
||||
// Add a BlendTree in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(blendTree.BlendTree, threshold, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a Clip in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(clip.Clip, threshold, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a raw motion in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
var children = BlendTree.children ?? new ChildMotion[0];
|
||||
var childrenList = children.ToList();
|
||||
|
||||
var childMotionModifier = new AacFlBlendTreeChildMotion();
|
||||
furtherDefiningChild?.Invoke(childMotionModifier);
|
||||
childrenList.Add(new ChildMotion
|
||||
{
|
||||
motion = motion,
|
||||
threshold = threshold,
|
||||
timeScale = childMotionModifier.TimeScale,
|
||||
mirror = childMotionModifier.Mirror,
|
||||
cycleOffset = childMotionModifier.CycleOffset
|
||||
});
|
||||
BlendTree.children = childrenList.ToArray();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlBlendTreeDirect : AacFlBlendTree
|
||||
{
|
||||
public AacFlBlendTreeDirect(BlendTree blendTree) : base(blendTree)
|
||||
{
|
||||
}
|
||||
|
||||
// Add a BlendTree driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTreeDirect WithAnimation(AacFlBlendTree blendTree, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(blendTree.BlendTree, parameter, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a Clip driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTreeDirect WithAnimation(AacFlClip clip, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
return WithAnimation(clip.Clip, parameter, furtherDefiningChild);
|
||||
}
|
||||
|
||||
// Add a raw motion driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
|
||||
public AacFlBlendTreeDirect WithAnimation(Motion motion, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
|
||||
{
|
||||
var children = BlendTree.children ?? new ChildMotion[0];
|
||||
var childrenList = children.ToList();
|
||||
|
||||
var childMotionModifier = new AacFlBlendTreeChildMotion();
|
||||
furtherDefiningChild?.Invoke(childMotionModifier);
|
||||
childrenList.Add(new ChildMotion
|
||||
{
|
||||
motion = motion,
|
||||
directBlendParameter = parameter.Name,
|
||||
timeScale = childMotionModifier.TimeScale,
|
||||
mirror = childMotionModifier.Mirror,
|
||||
cycleOffset = childMotionModifier.CycleOffset
|
||||
});
|
||||
BlendTree.children = childrenList.ToArray();
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlBlendTreeChildMotion
|
||||
{
|
||||
internal float TimeScale { get; set; } = 1f;
|
||||
internal bool Mirror { get; set; }
|
||||
internal float CycleOffset { get; set; }
|
||||
|
||||
/// Set the time scale. The time scale value is 1 by default.
|
||||
public AacFlBlendTreeChildMotion WithTimeScaleSetTo(float timeScale)
|
||||
{
|
||||
TimeScale = timeScale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the mirror option. The mirror option value is false by default.
|
||||
public AacFlBlendTreeChildMotion WithMirrorSetTo(bool mirror)
|
||||
{
|
||||
Mirror = mirror;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Set the cycle offset. The cycle offset value is 0 by default.
|
||||
public AacFlBlendTreeChildMotion WithCycleOffsetSetTo(float cycleOffset)
|
||||
{
|
||||
CycleOffset = cycleOffset;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80c6ca79d93446f088d6e7b1bfee5daa
|
||||
timeCreated: 1694177157
|
||||
@@ -0,0 +1,256 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Animations;
|
||||
using static AnimatorAsCode.V1.AacFlConditionSimple;
|
||||
using static UnityEditor.Animations.AnimatorConditionMode;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
class AacFlConditionSimple : IAacFlCondition
|
||||
{
|
||||
private readonly Action<AacFlCondition> _action;
|
||||
|
||||
public AacFlConditionSimple(Action<AacFlCondition> action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public static AacFlConditionSimple Just(Action<AacFlCondition> action)
|
||||
{
|
||||
return new AacFlConditionSimple(action);
|
||||
}
|
||||
|
||||
public static AacFlConditionSimple ForEach(string[] subjects, Action<string, AacFlCondition> action)
|
||||
{
|
||||
return new AacFlConditionSimple(condition =>
|
||||
{
|
||||
foreach (var subject in subjects)
|
||||
{
|
||||
action.Invoke(subject, condition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void ApplyTo(AacFlCondition appender)
|
||||
{
|
||||
_action.Invoke(appender);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AacFlParameter
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
protected AacFlParameter(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AacFlParameter<TParam> : AacFlParameter
|
||||
{
|
||||
protected AacFlParameter(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract float ValueToFloat(TParam value);
|
||||
}
|
||||
|
||||
public abstract class AacFlNumericParameter<TParam> : AacFlParameter<TParam>
|
||||
{
|
||||
protected AacFlNumericParameter(string name) : base(name)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlFloatParameter : AacFlNumericParameter<float>
|
||||
{
|
||||
internal static AacFlFloatParameter Internally(string name) => new AacFlFloatParameter(name);
|
||||
protected AacFlFloatParameter(string name) : base(name) { }
|
||||
public IAacFlCondition IsGreaterThan(float other) => Just(condition => condition.Add(Name, Greater, other));
|
||||
public IAacFlCondition IsLessThan(float other) => Just(condition => condition.Add(Name, Less, other));
|
||||
|
||||
public override float ValueToFloat(float value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlIntParameter : AacFlNumericParameter<int>
|
||||
{
|
||||
internal static AacFlIntParameter Internally(string name) => new AacFlIntParameter(name);
|
||||
protected AacFlIntParameter(string name) : base(name) { }
|
||||
public IAacFlCondition IsGreaterThan(int other) => Just(condition => condition.Add(Name, Greater, other));
|
||||
public IAacFlCondition IsLessThan(int other) => Just(condition => condition.Add(Name, Less, other));
|
||||
public IAacFlCondition IsEqualTo(int other) => Just(condition => condition.Add(Name, AnimatorConditionMode.Equals, other));
|
||||
public IAacFlCondition IsNotEqualTo(int other) => Just(condition => condition.Add(Name, NotEqual, other));
|
||||
|
||||
public override float ValueToFloat(int value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlEnumIntParameter<TEnum> : AacFlIntParameter where TEnum : Enum
|
||||
{
|
||||
internal static AacFlEnumIntParameter<TInEnum> Internally<TInEnum>(string name) where TInEnum : Enum => new AacFlEnumIntParameter<TInEnum>(name);
|
||||
protected AacFlEnumIntParameter(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public IAacFlCondition IsEqualTo(TEnum other) => IsEqualTo((int)(object)other);
|
||||
public IAacFlCondition IsNotEqualTo(TEnum other) => IsNotEqualTo((int)(object)other);
|
||||
}
|
||||
|
||||
public class AacFlBoolParameter : AacFlParameter<bool>
|
||||
{
|
||||
internal static AacFlBoolParameter Internally(string name) => new AacFlBoolParameter(name);
|
||||
protected AacFlBoolParameter(string name) : base(name) { }
|
||||
public IAacFlCondition IsTrue() => Just(condition => condition.Add(Name, If, 0));
|
||||
public IAacFlCondition IsFalse() => Just(condition => condition.Add(Name, IfNot, 0));
|
||||
public IAacFlCondition IsEqualTo(bool other) => Just(condition => condition.Add(Name, other ? If : IfNot, 0));
|
||||
public IAacFlCondition IsNotEqualTo(bool other) => Just(condition => condition.Add(Name, other ? IfNot : If, 0));
|
||||
|
||||
public override float ValueToFloat(bool value)
|
||||
{
|
||||
return value ? 1f : 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlFloatParameterGroup
|
||||
{
|
||||
internal static AacFlFloatParameterGroup Internally(params string[] names) => new AacFlFloatParameterGroup(names);
|
||||
private readonly string[] _names;
|
||||
private AacFlFloatParameterGroup(params string[] names) { _names = names; }
|
||||
public List<AacFlFloatParameter> ToList() => _names.Select(AacFlFloatParameter.Internally).ToList();
|
||||
|
||||
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
|
||||
public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other));
|
||||
}
|
||||
|
||||
public class AacFlIntParameterGroup
|
||||
{
|
||||
internal static AacFlIntParameterGroup Internally(params string[] names) => new AacFlIntParameterGroup(names);
|
||||
private readonly string[] _names;
|
||||
private AacFlIntParameterGroup(params string[] names) { _names = names; }
|
||||
public List<AacFlIntParameter> ToList() => _names.Select(AacFlIntParameter.Internally).ToList();
|
||||
|
||||
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
|
||||
public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other));
|
||||
public IAacFlCondition AreEqualTo(float other) => ForEach(_names, (name, condition) => condition.Add(name, AnimatorConditionMode.Equals, other));
|
||||
public IAacFlCondition AreNotEqualTo(float other) => ForEach(_names, (name, condition) => condition.Add(name, NotEqual, other));
|
||||
}
|
||||
|
||||
public class AacFlBoolParameterGroup
|
||||
{
|
||||
internal static AacFlBoolParameterGroup Internally(params string[] names) => new AacFlBoolParameterGroup(names);
|
||||
private readonly string[] _names;
|
||||
private AacFlBoolParameterGroup(params string[] names) { _names = names; }
|
||||
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.Internally).ToList();
|
||||
|
||||
public IAacFlCondition AreTrue() => ForEach(_names, (name, condition) => condition.Add(name, If, 0));
|
||||
public IAacFlCondition AreFalse() => ForEach(_names, (name, condition) => condition.Add(name, IfNot, 0));
|
||||
public IAacFlCondition AreEqualTo(bool other) => ForEach(_names, (name, condition) => condition.Add(name, other ? If : IfNot, 0));
|
||||
|
||||
/// is true when all of the following conditions are met:
|
||||
/// <ul>
|
||||
/// <li>all of the parameters in the group must be false except for the parameter defined in exceptThisMustBeTrue if it is present in the group.</li>
|
||||
/// <li>the parameter defined in exceptThisMustBeTrue must be true.</li>
|
||||
/// </ul>
|
||||
public IAacFlCondition AreFalseExcept(AacFlBoolParameter exceptThisMustBeTrue)
|
||||
{
|
||||
var group = new AacFlBoolParameterGroup(exceptThisMustBeTrue.Name);
|
||||
return AreFalseExcept(group);
|
||||
}
|
||||
|
||||
public IAacFlCondition AreFalseExcept(params AacFlBoolParameter[] exceptTheseMustBeTrue)
|
||||
{
|
||||
var group = new AacFlBoolParameterGroup(exceptTheseMustBeTrue.Select(parameter => parameter.Name).ToArray());
|
||||
return AreFalseExcept(group);
|
||||
}
|
||||
|
||||
public IAacFlCondition AreFalseExcept(AacFlBoolParameterGroup exceptTheseMustBeTrue) => Just(condition =>
|
||||
{
|
||||
foreach (var name in _names.Where(name => !exceptTheseMustBeTrue._names.Contains(name)))
|
||||
{
|
||||
condition.Add(name, IfNot, 0);
|
||||
}
|
||||
foreach (var name in exceptTheseMustBeTrue._names)
|
||||
{
|
||||
condition.Add(name, If, 0);
|
||||
}
|
||||
});
|
||||
|
||||
public IAacFlCondition AreTrueExcept(AacFlBoolParameter exceptThisMustBeFalse)
|
||||
{
|
||||
var group = new AacFlBoolParameterGroup(exceptThisMustBeFalse.Name);
|
||||
return AreTrueExcept(group);
|
||||
}
|
||||
|
||||
public IAacFlCondition AreTrueExcept(params AacFlBoolParameter[] exceptTheseMustBeFalse)
|
||||
{
|
||||
var group = new AacFlBoolParameterGroup(exceptTheseMustBeFalse.Select(parameter => parameter.Name).ToArray());
|
||||
return AreTrueExcept(group);
|
||||
}
|
||||
|
||||
public IAacFlCondition AreTrueExcept(AacFlBoolParameterGroup exceptTheseMustBeFalse) => Just(condition =>
|
||||
{
|
||||
foreach (var name in _names.Where(name => !exceptTheseMustBeFalse._names.Contains(name)))
|
||||
{
|
||||
condition.Add(name, If, 0);
|
||||
}
|
||||
foreach (var name in exceptTheseMustBeFalse._names)
|
||||
{
|
||||
condition.Add(name, IfNot, 0);
|
||||
}
|
||||
});
|
||||
|
||||
public IAacFlOrCondition IsAnyTrue()
|
||||
{
|
||||
return IsAnyEqualTo(true);
|
||||
}
|
||||
|
||||
public IAacFlOrCondition IsAnyFalse()
|
||||
{
|
||||
return IsAnyEqualTo(false);
|
||||
}
|
||||
|
||||
private IAacFlOrCondition IsAnyEqualTo(bool value)
|
||||
{
|
||||
return new AacFlBoolParameterIsAnyOrCondition(_names, value);
|
||||
}
|
||||
}
|
||||
|
||||
internal class AacFlBoolParameterIsAnyOrCondition : IAacFlOrCondition
|
||||
{
|
||||
private readonly string[] _names;
|
||||
private readonly bool _value;
|
||||
|
||||
public AacFlBoolParameterIsAnyOrCondition(string[] names, bool value)
|
||||
{
|
||||
_names = names;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public List<AacFlTransitionContinuation> ApplyTo(AacFlNewTransitionContinuation firstContinuation)
|
||||
{
|
||||
var pendingContinuations = new List<AacFlTransitionContinuation>();
|
||||
|
||||
var newContinuation = firstContinuation;
|
||||
for (var index = 0; index < _names.Length; index++)
|
||||
{
|
||||
var name = _names[index];
|
||||
var pendingContinuation = newContinuation.When(AacFlBoolParameter.Internally(name).IsEqualTo(_value));
|
||||
pendingContinuations.Add(pendingContinuation);
|
||||
if (index < _names.Length - 1)
|
||||
{
|
||||
newContinuation = pendingContinuation.Or();
|
||||
}
|
||||
}
|
||||
|
||||
return pendingContinuations;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13c07dbf6f2170f40ba96e7d47a7f706
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,950 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
public class AacBackingAnimator
|
||||
{
|
||||
private readonly AacAnimatorGenerator _generator;
|
||||
|
||||
public AacBackingAnimator(AacAnimatorGenerator animatorGenerator)
|
||||
{
|
||||
_generator = animatorGenerator;
|
||||
}
|
||||
|
||||
public AacFlBoolParameter BoolParameter(string parameterName)
|
||||
{
|
||||
var result = AacFlBoolParameter.Internally(parameterName);
|
||||
_generator.CreateParamsAsNeeded(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlBoolParameter TriggerParameter(string parameterName)
|
||||
{
|
||||
var result = AacFlBoolParameter.Internally(parameterName);
|
||||
_generator.CreateTriggerParamsAsNeeded(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlFloatParameter FloatParameter(string parameterName)
|
||||
{
|
||||
var result = AacFlFloatParameter.Internally(parameterName);
|
||||
_generator.CreateParamsAsNeeded(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlIntParameter IntParameter(string parameterName)
|
||||
{
|
||||
var result = AacFlIntParameter.Internally(parameterName);
|
||||
_generator.CreateParamsAsNeeded(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlEnumIntParameter<TEnum> EnumParameter<TEnum>(string parameterName) where TEnum : Enum
|
||||
{
|
||||
var result = AacFlEnumIntParameter<TEnum>.Internally<TEnum>(parameterName);
|
||||
_generator.CreateParamsAsNeeded(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames)
|
||||
{
|
||||
var result = AacFlBoolParameterGroup.Internally(parameterNames);
|
||||
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlBoolParameterGroup TriggerParameters(params string[] parameterNames)
|
||||
{
|
||||
var result = AacFlBoolParameterGroup.Internally(parameterNames);
|
||||
_generator.CreateTriggerParamsAsNeeded(result.ToList().ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames)
|
||||
{
|
||||
var result = AacFlFloatParameterGroup.Internally(parameterNames);
|
||||
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlIntParameterGroup IntParameters(params string[] parameterNames)
|
||||
{
|
||||
var result = AacFlIntParameterGroup.Internally(parameterNames);
|
||||
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters)
|
||||
{
|
||||
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||
_generator.CreateParamsAsNeeded(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlBoolParameterGroup TriggerParameters(params AacFlBoolParameter[] parameters)
|
||||
{
|
||||
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||
_generator.CreateTriggerParamsAsNeeded(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters)
|
||||
{
|
||||
var result = AacFlFloatParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||
_generator.CreateParamsAsNeeded(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters)
|
||||
{
|
||||
var result = AacFlIntParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||
_generator.CreateParamsAsNeeded(parameters);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlStateMachine : AacAnimatorNode<AacFlStateMachine>
|
||||
{
|
||||
public readonly AnimatorStateMachine Machine;
|
||||
private readonly AnimationClip _emptyClip;
|
||||
private readonly AacBackingAnimator _backingAnimator;
|
||||
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||
private readonly float _gridShiftX;
|
||||
private readonly float _gridShiftY;
|
||||
|
||||
private readonly List<AacAnimatorNode> _childNodes;
|
||||
|
||||
internal AacFlStateMachine(AnimatorStateMachine machine, AnimationClip emptyClip, AacBackingAnimator backingAnimator, IAacDefaultsProvider defaultsProvider, AacFlStateMachine parent = null)
|
||||
: base(parent, defaultsProvider)
|
||||
{
|
||||
Machine = machine;
|
||||
_emptyClip = emptyClip;
|
||||
_backingAnimator = backingAnimator;
|
||||
_defaultsProvider = defaultsProvider;
|
||||
|
||||
var grid = defaultsProvider.Grid();
|
||||
_gridShiftX = grid.x;
|
||||
_gridShiftY = grid.y;
|
||||
|
||||
_childNodes = new List<AacAnimatorNode>();
|
||||
}
|
||||
|
||||
public AacBackingAnimator InternalBackingAnimator()
|
||||
{
|
||||
return _backingAnimator;
|
||||
}
|
||||
|
||||
public AacFlStateMachine NewSubStateMachine(string name)
|
||||
{
|
||||
var lastState = LastNodePosition();
|
||||
return NewSubStateMachine(name, 0, 0).Shift(lastState, 0, 1);
|
||||
}
|
||||
|
||||
public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
|
||||
{
|
||||
var stateMachine = AacInternals.NoUndo(Machine, () => Machine.AddStateMachine(name, GridPosition(x, y)));
|
||||
var aacMachine = new AacFlStateMachine(stateMachine, _emptyClip, _backingAnimator, DefaultsProvider, this);
|
||||
_defaultsProvider.ConfigureStateMachine(stateMachine);
|
||||
_childNodes.Add(aacMachine);
|
||||
return aacMachine;
|
||||
}
|
||||
|
||||
public AacFlStateMachine WithEntryPosition(int x, int y)
|
||||
{
|
||||
Machine.entryPosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlStateMachine WithExitPosition(int x, int y)
|
||||
{
|
||||
Machine.exitPosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlStateMachine WithAnyStatePosition(int x, int y)
|
||||
{
|
||||
Machine.anyStatePosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlStateMachine WithParentStateMachinePosition(int x, int y)
|
||||
{
|
||||
Machine.parentStateMachinePosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState NewState(string name)
|
||||
{
|
||||
var lastState = LastNodePosition();
|
||||
return NewState(name, 0, 0).Shift(lastState, 0, 1);
|
||||
}
|
||||
|
||||
public AacFlState NewState(string name, int x, int y)
|
||||
{
|
||||
var state = AacInternals.NoUndo(Machine, () => Machine.AddState(name, GridPosition(x, y)));
|
||||
DefaultsProvider.ConfigureState(state, _emptyClip);
|
||||
var aacState = new AacFlState(state, this, DefaultsProvider);
|
||||
_childNodes.Add(aacState);
|
||||
return aacState;
|
||||
}
|
||||
|
||||
public AacFlTransition AnyTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return AnyTransition(destination, Machine);
|
||||
}
|
||||
|
||||
public AacFlTransition AnyTransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return AnyTransition(destination, Machine);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return EntryTransition(destination, Machine);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return EntryTransition(destination, Machine);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition TransitionsFromEntry()
|
||||
{
|
||||
return EntryTransition(this, ParentMachine.Machine);
|
||||
}
|
||||
|
||||
public AacFlNewTransitionContinuation TransitionsTo(AacFlState destination)
|
||||
{
|
||||
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, destination.State)), ParentMachine.Machine, Machine, destination.State);
|
||||
}
|
||||
|
||||
public AacFlNewTransitionContinuation TransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, destination.Machine)), ParentMachine.Machine, Machine, destination.Machine);
|
||||
}
|
||||
|
||||
public AacFlNewTransitionContinuation Restarts()
|
||||
{
|
||||
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, Machine)), ParentMachine.Machine, Machine, Machine);
|
||||
}
|
||||
|
||||
public AacFlNewTransitionContinuation Exits()
|
||||
{
|
||||
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineExitTransition(Machine)), ParentMachine.Machine, Machine, null);
|
||||
}
|
||||
|
||||
private AacFlTransition AnyTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddAnyStateTransition(destination.State))), animatorStateMachine, null, destination.State);
|
||||
}
|
||||
|
||||
private AacFlTransition AnyTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddAnyStateTransition(destination.Machine))), animatorStateMachine, null, destination.Machine);
|
||||
}
|
||||
|
||||
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||
{
|
||||
DefaultsProvider.ConfigureTransition(transition);
|
||||
return transition;
|
||||
}
|
||||
|
||||
private AacFlEntryTransition EntryTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlEntryTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddEntryTransition(destination.State)), animatorStateMachine, null, destination.State);
|
||||
}
|
||||
|
||||
private AacFlEntryTransition EntryTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlEntryTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddEntryTransition(destination.Machine)), animatorStateMachine, null, destination.Machine);
|
||||
}
|
||||
|
||||
internal Vector3 LastNodePosition()
|
||||
{
|
||||
return _childNodes.LastOrDefault()?.GetPosition() ?? Vector3.right * _gridShiftX * 2;
|
||||
}
|
||||
|
||||
private Vector3 GridPosition(int x, int y)
|
||||
{
|
||||
return new Vector3(x * _gridShiftX, y * _gridShiftY, 0);
|
||||
}
|
||||
|
||||
internal IReadOnlyList<AacAnimatorNode> GetChildNodes()
|
||||
{
|
||||
return _childNodes;
|
||||
}
|
||||
|
||||
protected internal override Vector3 GetPosition()
|
||||
{
|
||||
return ParentMachine.Machine.stateMachines.First(x => x.stateMachine == Machine).position;
|
||||
}
|
||||
|
||||
protected internal override void SetPosition(Vector3 position)
|
||||
{
|
||||
var stateMachines = ParentMachine.Machine.stateMachines;
|
||||
for (var i = 0; i < stateMachines.Length; i++)
|
||||
{
|
||||
var m = stateMachines[i];
|
||||
if (m.stateMachine == Machine)
|
||||
{
|
||||
m.position = position;
|
||||
stateMachines[i] = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ParentMachine.Machine.stateMachines = stateMachines;
|
||||
}
|
||||
|
||||
public AacFlStateMachine WithDefaultState(AacFlState newDefaultState)
|
||||
{
|
||||
Machine.defaultState = newDefaultState.State;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override TBehaviour EnsureBehaviour<TBehaviour>()
|
||||
{
|
||||
foreach (var behaviour in Machine.behaviours)
|
||||
if (behaviour is TBehaviour myBehaviour)
|
||||
return myBehaviour;
|
||||
|
||||
return AacInternals.NoUndo(Machine, () => Machine.AddStateMachineBehaviour<TBehaviour>());
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlState : AacAnimatorNode<AacFlState>
|
||||
{
|
||||
public readonly AnimatorState State;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
|
||||
public AacFlState(AnimatorState state, AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider) : base(parentMachine, defaultsProvider)
|
||||
{
|
||||
State = state;
|
||||
_machine = parentMachine.Machine;
|
||||
}
|
||||
|
||||
public AacFlState WithAnimation(Motion clip)
|
||||
{
|
||||
State.motion = clip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithAnimation(AacFlClip clip)
|
||||
{
|
||||
State.motion = clip.Clip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithAnimation(AacFlBlendTree blendTree)
|
||||
{
|
||||
State.motion = blendTree.BlendTree;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition TransitionsTo(AacFlState destination)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.State))), _machine, State, destination.State);
|
||||
}
|
||||
|
||||
public AacFlTransition TransitionsTo(AacFlStateMachine destination)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.Machine))), _machine, State, destination.Machine);
|
||||
}
|
||||
|
||||
public AacFlTransition TransitionsFromAny()
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => _machine.AddAnyStateTransition(State))), _machine, null, State);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition TransitionsFromEntry()
|
||||
{
|
||||
return new AacFlEntryTransition(AacInternals.NoUndo(State, () => _machine.AddEntryTransition(State)), _machine, null, State);
|
||||
}
|
||||
|
||||
public AacFlState AutomaticallyMovesTo(AacFlState destination)
|
||||
{
|
||||
var transition = ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.State)));
|
||||
transition.hasExitTime = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState AutomaticallyMovesTo(AacFlStateMachine destination)
|
||||
{
|
||||
var transition = ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.Machine)));
|
||||
transition.hasExitTime = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition Exits()
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => State.AddExitTransition())), _machine, State, null);
|
||||
}
|
||||
|
||||
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||
{
|
||||
DefaultsProvider.ConfigureTransition(transition);
|
||||
return transition;
|
||||
}
|
||||
|
||||
public AacFlState WithWriteDefaultsSetTo(bool shouldWriteDefaults)
|
||||
{
|
||||
State.writeDefaultValues = shouldWriteDefaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState MotionTime(AacFlFloatParameter floatParam)
|
||||
{
|
||||
State.timeParameterActive = true;
|
||||
State.timeParameter = floatParam.Name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithCycleOffset(AacFlFloatParameter floatParam)
|
||||
{
|
||||
State.cycleOffsetParameterActive = false;
|
||||
State.cycleOffsetParameter = floatParam.Name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithCycleOffsetSetTo(float cycleOffset)
|
||||
{
|
||||
State.cycleOffsetParameterActive = false;
|
||||
State.cycleOffset = cycleOffset;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithSpeed(AacFlFloatParameter parameter)
|
||||
{
|
||||
State.speedParameterActive = true;
|
||||
State.speedParameter = parameter.Name;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithSpeedSetTo(float speed)
|
||||
{
|
||||
State.speedParameterActive = false;
|
||||
State.speed = speed;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected internal override Vector3 GetPosition()
|
||||
{
|
||||
return _machine.states.First(x => x.state == State).position;
|
||||
}
|
||||
|
||||
protected internal override void SetPosition(Vector3 position)
|
||||
{
|
||||
var states = _machine.states;
|
||||
for (var i = 0; i < states.Length; i++)
|
||||
{
|
||||
var m = states[i];
|
||||
if (m.state == State)
|
||||
{
|
||||
m.position = position;
|
||||
states[i] = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_machine.states = states;
|
||||
}
|
||||
|
||||
public override TBehaviour EnsureBehaviour<TBehaviour>()
|
||||
{
|
||||
foreach (var behaviour in State.behaviours)
|
||||
if (behaviour is TBehaviour myBehaviour)
|
||||
return myBehaviour;
|
||||
|
||||
return AacInternals.NoUndo(State, () => State.AddStateMachineBehaviour<TBehaviour>());
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlTransition : AacFlNewTransitionContinuation
|
||||
{
|
||||
private readonly AnimatorStateTransition _transition;
|
||||
|
||||
public AacFlTransition(AnimatorStateTransition transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
_transition = transition;
|
||||
}
|
||||
|
||||
public AacFlTransition WithSourceInterruption()
|
||||
{
|
||||
_transition.interruptionSource = TransitionInterruptionSource.Source;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithInterruption(TransitionInterruptionSource interruptionSource)
|
||||
{
|
||||
_transition.interruptionSource = interruptionSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithTransitionDurationSeconds(float transitionDuration)
|
||||
{
|
||||
_transition.duration = transitionDuration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithOrderedInterruption()
|
||||
{
|
||||
_transition.orderedInterruption = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithNoOrderedInterruption()
|
||||
{
|
||||
_transition.orderedInterruption = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithTransitionToSelf()
|
||||
{
|
||||
_transition.canTransitionToSelf = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithNoTransitionToSelf()
|
||||
{
|
||||
_transition.canTransitionToSelf = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition AfterAnimationFinishes()
|
||||
{
|
||||
_transition.hasExitTime = true;
|
||||
_transition.exitTime = 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition Automatically()
|
||||
{
|
||||
_transition.hasExitTime = true;
|
||||
_transition.exitTime = 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition AfterAnimationIsAtLeastAtPercent(float exitTimeNormalized)
|
||||
{
|
||||
_transition.hasExitTime = true;
|
||||
_transition.exitTime = exitTimeNormalized;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition WithTransitionDurationPercent(float transitionDurationNormalized)
|
||||
{
|
||||
_transition.hasFixedDuration = false;
|
||||
_transition.duration = transitionDurationNormalized;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlEntryTransition : AacFlNewTransitionContinuation
|
||||
{
|
||||
public AacFlEntryTransition(AnimatorTransition transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAacFlCondition
|
||||
{
|
||||
void ApplyTo(AacFlCondition appender);
|
||||
}
|
||||
|
||||
public interface IAacFlOrCondition
|
||||
{
|
||||
List<AacFlTransitionContinuation> ApplyTo(AacFlNewTransitionContinuation firstContinuation);
|
||||
}
|
||||
|
||||
public class AacFlCondition
|
||||
{
|
||||
private readonly AnimatorTransitionBase _transition;
|
||||
|
||||
public AacFlCondition(AnimatorTransitionBase transition)
|
||||
{
|
||||
_transition = transition;
|
||||
}
|
||||
|
||||
public AacFlCondition Add(string parameter, AnimatorConditionMode mode, float threshold)
|
||||
{
|
||||
AacInternals.NoUndo(_transition, () => _transition.AddCondition(mode, threshold, parameter));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlNewTransitionContinuation
|
||||
{
|
||||
public readonly AnimatorTransitionBase Transition;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly AacTransitionEndpoint _sourceNullableIfAny;
|
||||
private readonly AacTransitionEndpoint _destinationNullableIfExits;
|
||||
|
||||
public AacFlNewTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits)
|
||||
{
|
||||
Transition = transition;
|
||||
_machine = machine;
|
||||
_sourceNullableIfAny = sourceNullableIfAny;
|
||||
_destinationNullableIfExits = destinationNullableIfExits;
|
||||
}
|
||||
|
||||
/// Adds a condition to the transition.
|
||||
///
|
||||
/// The settings of the transition can no longer be modified after this point.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
|
||||
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
|
||||
/// .And(AacAv3.ItIsLocal())
|
||||
/// .Or()
|
||||
/// .When(_aac.BoolParameters(
|
||||
/// my.myBoolParameterName,
|
||||
/// my.myOtherBoolParameterName
|
||||
/// ).AreTrue())
|
||||
/// .And(AacAv3.ItIsRemote());
|
||||
/// </code>
|
||||
/// </example>
|
||||
public AacFlTransitionContinuation When(IAacFlCondition action)
|
||||
{
|
||||
action.ApplyTo(new AacFlCondition(Transition));
|
||||
return AsContinuationWithOr();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions to this transition, but this series of conditions cannot include an Or operator.
|
||||
/// </summary>
|
||||
/// <param name="actionsWithoutOr"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlTransitionContinuation When(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
|
||||
{
|
||||
actionsWithoutOr(new AacFlTransitionContinuationWithoutOr(Transition));
|
||||
return AsContinuationWithOr();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions, and this series may contain Or operators. However, the result can not be followed by an And operator. It can only be an Or operator.
|
||||
/// </summary>
|
||||
/// <param name="actionsWithOr"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlTransitionContinuationOnlyOr When(Action<AacFlNewTransitionContinuation> actionsWithOr)
|
||||
{
|
||||
actionsWithOr(this);
|
||||
return AsContinuationOnlyOr();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions, and this series may contain Or operators. All And operators that follow will apply to all the conditions generated by this series, until the next Or operator.
|
||||
/// </summary>
|
||||
/// <param name="actionsWithOr"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlMultiTransitionContinuation When(IAacFlOrCondition actionsWithOr)
|
||||
{
|
||||
var pendingContinuations = actionsWithOr.ApplyTo(this);
|
||||
return new AacFlMultiTransitionContinuation(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits, pendingContinuations);
|
||||
}
|
||||
|
||||
public AacFlTransitionContinuation WhenConditions()
|
||||
{
|
||||
return AsContinuationWithOr();
|
||||
}
|
||||
|
||||
private AacFlTransitionContinuation AsContinuationWithOr()
|
||||
{
|
||||
return new AacFlTransitionContinuation(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits);
|
||||
}
|
||||
|
||||
private AacFlTransitionContinuationOnlyOr AsContinuationOnlyOr()
|
||||
{
|
||||
return new AacFlTransitionContinuationOnlyOr(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits);
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlTransitionContinuation : AacFlTransitionContinuationAbstractWithOr
|
||||
{
|
||||
public AacFlTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
}
|
||||
|
||||
/// Adds an additional condition to the transition that requires all preceding conditions to be true.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
|
||||
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
|
||||
/// .And(AacAv3.ItIsLocal())
|
||||
/// .Or()
|
||||
/// .When(_aac.BoolParameters(
|
||||
/// my.myBoolParameterName,
|
||||
/// my.myOtherBoolParameterName
|
||||
/// ).AreTrue())
|
||||
/// .And(AacAv3.ItIsRemote());
|
||||
/// </code>
|
||||
/// </example>
|
||||
public AacFlTransitionContinuation And(IAacFlCondition action)
|
||||
{
|
||||
action.ApplyTo(new AacFlCondition(Transition));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions to this transition. The conditions cannot include an Or operator.
|
||||
/// </summary>
|
||||
/// <param name="actionsWithoutOr"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlTransitionContinuation And(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
|
||||
{
|
||||
actionsWithoutOr(new AacFlTransitionContinuationWithoutOr(Transition));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlMultiTransitionContinuation : AacFlTransitionContinuationAbstractWithOr
|
||||
{
|
||||
private readonly List<AacFlTransitionContinuation> _pendingContinuations;
|
||||
|
||||
public AacFlMultiTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits, List<AacFlTransitionContinuation> pendingContinuations) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
_pendingContinuations = pendingContinuations;
|
||||
}
|
||||
|
||||
/// Adds an additional condition to these transitions that requires all preceding conditions to be true.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
|
||||
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
|
||||
/// .And(AacAv3.ItIsLocal())
|
||||
/// .Or()
|
||||
/// .When(_aac.BoolParameters(
|
||||
/// my.myBoolParameterName,
|
||||
/// my.myOtherBoolParameterName
|
||||
/// ).AreTrue())
|
||||
/// .And(AacAv3.ItIsRemote());
|
||||
/// </code>
|
||||
/// </example>
|
||||
public AacFlMultiTransitionContinuation And(IAacFlCondition action)
|
||||
{
|
||||
foreach (var pendingContinuation in _pendingContinuations)
|
||||
{
|
||||
pendingContinuation.And(action);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions to these transitions. The conditions cannot include an Or operator.
|
||||
/// </summary>
|
||||
/// <param name="actionsWithoutOr"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlMultiTransitionContinuation And(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
|
||||
{
|
||||
foreach (var pendingContinuation in _pendingContinuations)
|
||||
{
|
||||
pendingContinuation.And(actionsWithoutOr);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlTransitionContinuationOnlyOr : AacFlTransitionContinuationAbstractWithOr
|
||||
{
|
||||
public AacFlTransitionContinuationOnlyOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AacFlTransitionContinuationAbstractWithOr
|
||||
{
|
||||
protected readonly AnimatorTransitionBase Transition;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly AacTransitionEndpoint _sourceNullableIfAny;
|
||||
private readonly AacTransitionEndpoint _destinationNullableIfExits;
|
||||
|
||||
public AacFlTransitionContinuationAbstractWithOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits)
|
||||
{
|
||||
Transition = transition;
|
||||
_machine = machine;
|
||||
_sourceNullableIfAny = sourceNullableIfAny;
|
||||
_destinationNullableIfExits = destinationNullableIfExits;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new transition with identical settings but having no conditions defined yet.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
|
||||
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
|
||||
/// .And(AacAv3.ItIsLocal())
|
||||
/// .Or()
|
||||
/// .When(_aac.BoolParameters(
|
||||
/// my.myBoolParameterName,
|
||||
/// my.myOtherBoolParameterName
|
||||
/// ).AreTrue())
|
||||
/// .And(AacAv3.ItIsRemote());
|
||||
/// </code>
|
||||
/// </example>
|
||||
public AacFlNewTransitionContinuation Or()
|
||||
{
|
||||
return new AacFlNewTransitionContinuation(NewTransitionFromTemplate(), _machine, _sourceNullableIfAny, _destinationNullableIfExits);
|
||||
}
|
||||
|
||||
private AnimatorTransitionBase NewTransitionFromTemplate()
|
||||
{
|
||||
AnimatorTransitionBase newTransition;
|
||||
if (Transition is AnimatorStateTransition templateStateTransition)
|
||||
{
|
||||
var stateTransition = NewTransition();
|
||||
stateTransition.duration = templateStateTransition.duration;
|
||||
stateTransition.offset = templateStateTransition.offset;
|
||||
stateTransition.interruptionSource = templateStateTransition.interruptionSource;
|
||||
stateTransition.orderedInterruption = templateStateTransition.orderedInterruption;
|
||||
stateTransition.exitTime = templateStateTransition.exitTime;
|
||||
stateTransition.hasExitTime = templateStateTransition.hasExitTime;
|
||||
stateTransition.hasFixedDuration = templateStateTransition.hasFixedDuration;
|
||||
stateTransition.canTransitionToSelf = templateStateTransition.canTransitionToSelf;
|
||||
newTransition = stateTransition;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_sourceNullableIfAny == null)
|
||||
{
|
||||
if (_destinationNullableIfExits.TryGetState(out var state))
|
||||
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddEntryTransition(state));
|
||||
else if (_destinationNullableIfExits.TryGetStateMachine(out var stateMachine))
|
||||
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddEntryTransition(stateMachine));
|
||||
else
|
||||
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
|
||||
}
|
||||
// source will never be a state if we're cloning an AnimatorTransition
|
||||
else if (_sourceNullableIfAny.TryGetStateMachine(out var stateMachine))
|
||||
{
|
||||
if (_destinationNullableIfExits == null)
|
||||
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddStateMachineExitTransition(stateMachine));
|
||||
else if (_destinationNullableIfExits.TryGetState(out var destinationState))
|
||||
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddStateMachineTransition(stateMachine, destinationState));
|
||||
else if (_destinationNullableIfExits.TryGetStateMachine(out var destinationStateMachine))
|
||||
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddStateMachineTransition(stateMachine, destinationStateMachine));
|
||||
else
|
||||
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException("_sourceNullableIfAny is not null but does not contain an AnimatorStateMachine");
|
||||
}
|
||||
return newTransition;
|
||||
}
|
||||
|
||||
private AnimatorStateTransition NewTransition()
|
||||
{
|
||||
AnimatorState state;
|
||||
AnimatorStateMachine stateMachine;
|
||||
|
||||
if (_sourceNullableIfAny == null)
|
||||
{
|
||||
if (_destinationNullableIfExits.TryGetState(out state))
|
||||
return AacInternals.NoUndo(_machine, () => _machine.AddAnyStateTransition(state));
|
||||
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
|
||||
return AacInternals.NoUndo(_machine, () => _machine.AddAnyStateTransition(stateMachine));
|
||||
throw new InvalidOperationException("Transition has no source nor destination.");
|
||||
}
|
||||
|
||||
// source will never be a state machine if we're cloning an AnimatorStateTransition
|
||||
if (_sourceNullableIfAny.TryGetState(out var sourceState))
|
||||
{
|
||||
if (_destinationNullableIfExits == null)
|
||||
{
|
||||
return AacInternals.NoUndo(sourceState, () => sourceState.AddExitTransition());
|
||||
}
|
||||
|
||||
if (_destinationNullableIfExits.TryGetState(out state))
|
||||
{
|
||||
return AacInternals.NoUndo(sourceState, () => sourceState.AddTransition(state));
|
||||
}
|
||||
|
||||
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
|
||||
{
|
||||
return AacInternals.NoUndo(sourceState, () => sourceState.AddTransition(stateMachine));
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
|
||||
}
|
||||
throw new InvalidOperationException("_sourceNullableIfAny is not null but does not contain an AnimatorState");
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlTransitionContinuationWithoutOr
|
||||
{
|
||||
private readonly AnimatorTransitionBase _transition;
|
||||
|
||||
public AacFlTransitionContinuationWithoutOr(AnimatorTransitionBase transition)
|
||||
{
|
||||
_transition = transition;
|
||||
}
|
||||
|
||||
public AacFlTransitionContinuationWithoutOr And(IAacFlCondition action)
|
||||
{
|
||||
action.ApplyTo(new AacFlCondition(_transition));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a series of conditions to this transition. The conditions cannot include an Or operator.
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
public AacFlTransitionContinuationWithoutOr AndWhenever(Action<AacFlTransitionContinuationWithoutOr> action)
|
||||
{
|
||||
action(this);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacTransitionEndpoint
|
||||
{
|
||||
private readonly AnimatorState _state;
|
||||
private readonly AnimatorStateMachine _stateMachine;
|
||||
|
||||
public AacTransitionEndpoint(AnimatorState state)
|
||||
{
|
||||
_state = state;
|
||||
}
|
||||
|
||||
public AacTransitionEndpoint(AnimatorStateMachine stateMachine)
|
||||
{
|
||||
_stateMachine = stateMachine;
|
||||
}
|
||||
|
||||
public static implicit operator AacTransitionEndpoint(AnimatorState state)
|
||||
{
|
||||
return new AacTransitionEndpoint(state);
|
||||
}
|
||||
|
||||
public static implicit operator AacTransitionEndpoint(AnimatorStateMachine stateMachine)
|
||||
{
|
||||
return new AacTransitionEndpoint(stateMachine);
|
||||
}
|
||||
|
||||
public bool TryGetState(out AnimatorState state)
|
||||
{
|
||||
state = _state;
|
||||
return _state != null;
|
||||
}
|
||||
|
||||
public bool TryGetStateMachine(out AnimatorStateMachine stateMachine)
|
||||
{
|
||||
stateMachine = _stateMachine;
|
||||
return _stateMachine != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 783d30e64e795b14f899955b9535ecf3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace AnimatorAsCode.V1
|
||||
{
|
||||
internal static class AacInternals
|
||||
{
|
||||
internal static AnimatorController NewAnimatorController(AacConfiguration component, string suffix)
|
||||
{
|
||||
var animatorController = new AnimatorController();
|
||||
animatorController.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||
animatorController.hideFlags = HideFlags.None;
|
||||
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(animatorController, component.AssetContainer);
|
||||
return animatorController;
|
||||
}
|
||||
|
||||
internal static AnimationClip NewClip(AacConfiguration component, string suffix)
|
||||
{
|
||||
return RegisterClip(component, suffix, new AnimationClip());
|
||||
}
|
||||
|
||||
internal static AnimationClip RegisterClip(AacConfiguration component, string suffix, AnimationClip clip)
|
||||
{
|
||||
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||
clip.hideFlags = HideFlags.None;
|
||||
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
|
||||
return clip;
|
||||
}
|
||||
|
||||
internal static BlendTree NewBlendTreeAsRaw(AacConfiguration component, string suffix)
|
||||
{
|
||||
var clip = new BlendTree();
|
||||
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||
clip.hideFlags = HideFlags.None;
|
||||
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
|
||||
return clip;
|
||||
}
|
||||
|
||||
internal static T DuplicateAssetIntoContainer<T>(AacConfiguration component, T assetToDuplicate) where T : Object
|
||||
{
|
||||
var duplicated = (T)Object.Instantiate(assetToDuplicate);
|
||||
duplicated.name = "zAutogenerated__" + component.AssetKey + "__" + assetToDuplicate.name + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||
duplicated.hideFlags = HideFlags.None;
|
||||
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(duplicated, component.AssetContainer);
|
||||
return duplicated;
|
||||
}
|
||||
|
||||
internal static EditorCurveBinding Binding(AacConfiguration component, Type type, Transform transform, string propertyName)
|
||||
{
|
||||
return new EditorCurveBinding
|
||||
{
|
||||
path = ResolveRelativePath(component.AnimatorRoot, transform),
|
||||
type = type,
|
||||
propertyName = propertyName
|
||||
};
|
||||
}
|
||||
|
||||
internal static void SetCurve(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
|
||||
{
|
||||
// https://forum.unity.com/threads/new-animationclip-property-names.367288/#post-2384172
|
||||
clip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
|
||||
}
|
||||
|
||||
internal static AnimationCurve OneFrame(float desiredValue)
|
||||
{
|
||||
return AnimationCurve.Constant(0f, 1 / 60f, desiredValue);
|
||||
}
|
||||
|
||||
internal static AnimationCurve ConstantSeconds(float seconds, float desiredValue)
|
||||
{
|
||||
return AnimationCurve.Constant(0f, seconds, desiredValue);
|
||||
}
|
||||
|
||||
internal static string ResolveRelativePath(Transform avatar, Transform item)
|
||||
{
|
||||
if (avatar == item)
|
||||
{
|
||||
// TODO: Is this correct??
|
||||
return "";
|
||||
}
|
||||
|
||||
if (item.parent != avatar && item.parent != null)
|
||||
{
|
||||
return ResolveRelativePath(avatar, item.parent) + "/" + item.name;
|
||||
}
|
||||
|
||||
return item.name;
|
||||
}
|
||||
|
||||
internal static EditorCurveBinding ToSubBinding(EditorCurveBinding binding, string suffix)
|
||||
{
|
||||
return new EditorCurveBinding {path = binding.path, type = binding.type, propertyName = binding.propertyName + "." + suffix};
|
||||
}
|
||||
|
||||
internal static void NoUndo<T>(T obj, Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
UndoDisable(obj);
|
||||
action.Invoke();
|
||||
}
|
||||
finally
|
||||
{
|
||||
UndoEnable(obj);
|
||||
}
|
||||
}
|
||||
|
||||
internal static TResult NoUndo<T, TResult>(T obj, Func<TResult> action)
|
||||
{
|
||||
try
|
||||
{
|
||||
UndoDisable(obj);
|
||||
return action.Invoke();
|
||||
}
|
||||
finally
|
||||
{
|
||||
UndoEnable(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UndoDisable<T>(T state)
|
||||
{
|
||||
typeof(T)
|
||||
.GetProperty("pushUndo", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
.SetValue(state, false);
|
||||
}
|
||||
|
||||
private static void UndoEnable<T>(T state)
|
||||
{
|
||||
typeof(T)
|
||||
.GetProperty("pushUndo", BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
.SetValue(state, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fffa37ca11924062a8cf4a76d0f607ba
|
||||
timeCreated: 1694285975
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "AnimatorAsCode.V1",
|
||||
"references": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b32145194168e0409534fc5052b85ce
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "dev.hai-vr.animator-as-code.v1",
|
||||
"displayName": "Animator As Code",
|
||||
"version": "1.0.9906",
|
||||
"unity": "2019.4",
|
||||
"description": "Animator As Code",
|
||||
"vrchatVersion" : "2022.1.1",
|
||||
"author" : {
|
||||
"name" : "Haï~"
|
||||
},
|
||||
"url" : "https://docs.hai-vr.dev/docs/products/animator-as-code/functions/vrchat"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9b555d14a3fa1f40ac2ff1a4f6fc407
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user