Add AacFlBase.NewBlendTree

This commit is contained in:
Haï~
2023-10-02 04:53:27 +02:00
parent d22d73cc82
commit 53da87438e
7 changed files with 353 additions and 175 deletions
+72 -174
View File
@@ -11,6 +11,7 @@ namespace AnimatorAsCode.V1
{ {
public static class AacV1 public static class AacV1
{ {
/// Create an Animator As Code (AAC) base.
public static AacFlBase Create(AacConfiguration configuration) public static AacFlBase Create(AacConfiguration configuration)
{ {
return new AacFlBase(configuration); return new AacFlBase(configuration);
@@ -21,7 +22,7 @@ namespace AnimatorAsCode.V1
return RegisterAnimatorController(component, suffix, new AnimatorController()); return RegisterAnimatorController(component, suffix, new AnimatorController());
} }
internal static AnimatorController RegisterAnimatorController(AacConfiguration component, string suffix, AnimatorController animatorController) private static AnimatorController RegisterAnimatorController(AacConfiguration component, string suffix, AnimatorController animatorController)
{ {
animatorController.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict animatorController.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
animatorController.hideFlags = HideFlags.None; animatorController.hideFlags = HideFlags.None;
@@ -135,6 +136,7 @@ namespace AnimatorAsCode.V1
_stateMachine = stateMachine; _stateMachine = stateMachine;
} }
/// Create a new state, initially positioned below the last generated state of this layer.
public AacFlState NewState(string name) public AacFlState NewState(string name)
{ {
var lastState = _stateMachine.LastNodePosition(); var lastState = _stateMachine.LastNodePosition();
@@ -142,49 +144,85 @@ namespace AnimatorAsCode.V1
return state; 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) public AacFlState NewState(string name, int x, int y)
{ {
return _stateMachine.NewState(name, x, 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) public AacFlStateMachine NewSubStateMachine(string name)
{ {
return _stateMachine.NewSubStateMachine(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) public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
{ {
return _stateMachine.NewSubStateMachine(name, x, y); return _stateMachine.NewSubStateMachine(name, x, y);
} }
/// Create a transition from Any to the `destination` state.
public AacFlTransition AnyTransitionsTo(AacFlState destination) public AacFlTransition AnyTransitionsTo(AacFlState destination)
{ {
return _stateMachine.AnyTransitionsTo(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) public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{ {
return _stateMachine.EntryTransitionsTo(destination); return _stateMachine.EntryTransitionsTo(destination);
} }
// Create a transition from the Entry to the `destination` state machine.
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination) public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination)
{ {
return _stateMachine.EntryTransitionsTo(destination); return _stateMachine.EntryTransitionsTo(destination);
} }
/// Create a Bool parameter in the animator.
public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.InternalBackingAnimator().BoolParameter(parameterName); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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) public AacFlLayer OverrideValue(AacFlBoolParameter toBeForced, bool value)
{ {
var parameters = _animatorController.parameters; var parameters = _animatorController.parameters;
@@ -201,6 +239,7 @@ namespace AnimatorAsCode.V1
return this; return this;
} }
/// Set the Float value of `toBeForced` parameter to `value` in the animator.
public AacFlLayer OverrideValue(AacFlFloatParameter toBeForced, float value) public AacFlLayer OverrideValue(AacFlFloatParameter toBeForced, float value)
{ {
var parameters = _animatorController.parameters; var parameters = _animatorController.parameters;
@@ -217,6 +256,7 @@ namespace AnimatorAsCode.V1
return this; return this;
} }
/// Set the Int value of `toBeForced` parameter to `value` in the animator.
public AacFlLayer OverrideValue(AacFlIntParameter toBeForced, int value) public AacFlLayer OverrideValue(AacFlIntParameter toBeForced, int value)
{ {
var parameters = _animatorController.parameters; var parameters = _animatorController.parameters;
@@ -233,6 +273,7 @@ namespace AnimatorAsCode.V1
return this; return this;
} }
/// Set the Avatar Mask of the layer.
public AacFlLayer WithAvatarMask(AvatarMask avatarMask) public AacFlLayer WithAvatarMask(AvatarMask avatarMask)
{ {
var finalFullLayerName = _fullLayerName; var finalFullLayerName = _fullLayerName;
@@ -251,6 +292,7 @@ namespace AnimatorAsCode.V1
return this; 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() public AacFlLayer WithAvatarMaskNoTransforms()
{ {
ResolveAvatarMask(new Transform[0]); ResolveAvatarMask(new Transform[0]);
@@ -258,6 +300,7 @@ namespace AnimatorAsCode.V1
return this; 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) public AacFlLayer ResolveAvatarMask(Transform[] paths)
{ {
// FIXME: Fragile // FIXME: Fragile
@@ -294,12 +337,14 @@ namespace AnimatorAsCode.V1
return this; return this;
} }
/// Set the Default State of the layer.
public AacFlLayer WithDefaultState(AacFlState newDefaultState) public AacFlLayer WithDefaultState(AacFlState newDefaultState)
{ {
_stateMachine.WithDefaultState(newDefaultState); _stateMachine.WithDefaultState(newDefaultState);
return this; return this;
} }
/// NON-PUBLIC: Internal use only so that extensions can access this. Maybe this can be improved
public AacFlStateMachine InternalStateMachine() public AacFlStateMachine InternalStateMachine()
{ {
return _stateMachine; return _stateMachine;
@@ -310,6 +355,7 @@ namespace AnimatorAsCode.V1
{ {
private readonly AacConfiguration _configuration; private readonly AacConfiguration _configuration;
/// NON-PUBLIC: Internal use only so that destructive workflow can access this. Maybe this can be improved
public AacConfiguration InternalConfiguration() public AacConfiguration InternalConfiguration()
{ {
return _configuration; return _configuration;
@@ -320,12 +366,14 @@ namespace AnimatorAsCode.V1
_configuration = configuration; _configuration = configuration;
} }
/// Create a new clip. The asset is generated into the container.
public AacFlClip NewClip() public AacFlClip NewClip()
{ {
var clip = AacV1.NewClip(_configuration, Guid.NewGuid().ToString()); var clip = AacV1.NewClip(_configuration, Guid.NewGuid().ToString());
return new AacFlClip(_configuration, clip); 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) public AacFlClip CopyClip(AnimationClip originalClip)
{ {
var newClip = UnityEngine.Object.Instantiate(originalClip); var newClip = UnityEngine.Object.Instantiate(originalClip);
@@ -333,22 +381,26 @@ namespace AnimatorAsCode.V1
return new AacFlClip(_configuration, clip); return new AacFlClip(_configuration, clip);
} }
/// Create a new BlendTree asset. The asset is generated into the container.
public AacFlNonInitializedBlendTree NewBlendTree() public AacFlNonInitializedBlendTree NewBlendTree()
{ {
return new AacFlNonInitializedBlendTree(AacV1.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString())); return new AacFlNonInitializedBlendTree(AacV1.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() public BlendTree NewBlendTreeAsRaw()
{ {
return AacV1.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString()); return AacV1.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) public AacFlClip NewClip(string name)
{ {
var clip = AacV1.NewClip(_configuration, name); var clip = AacV1.NewClip(_configuration, name);
return new AacFlClip(_configuration, clip); 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) public AacFlClip DummyClipLasting(float numberOf, AacFlUnit unit)
{ {
var dummyClip = AacV1.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})"); var dummyClip = AacV1.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})");
@@ -364,7 +416,7 @@ namespace AnimatorAsCode.V1
// resulting in an "undesired" animation which was functional anyways. // resulting in an "undesired" animation which was functional anyways.
// Since this dummy clip is used internally on all uninitalized states, // 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. // preserve this behaviour so that existing animators don't break due to this change.
protected AacFlClip AnomalousSingleKeyframeClip() private AacFlClip AnomalousSingleKeyframeClip()
{ {
var numberOf = 1f; var numberOf = 1f;
var unit = AacFlUnit.Frames; var unit = AacFlUnit.Frames;
@@ -376,23 +428,33 @@ namespace AnimatorAsCode.V1
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive") .Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(duration, 0f))); .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() public AacFlController NewAnimatorController()
{ {
var animatorController = AacV1.NewAnimatorController(_configuration, Guid.NewGuid().ToString()); var animatorController = AacV1.NewAnimatorController(_configuration, Guid.NewGuid().ToString());
return new AacFlController(_configuration, animatorController, this); 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) public AacFlController NewAnimatorController(string name)
{ {
var animatorController = AacV1.NewAnimatorController(_configuration, name); var animatorController = AacV1.NewAnimatorController(_configuration, name);
return new AacFlController(_configuration, animatorController, this); 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)); 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)); 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); 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) public AacFlLayer InternalDoCreateLayer(AnimatorController animator, string layerName)
{ {
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider); var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
@@ -415,6 +477,7 @@ namespace AnimatorAsCode.V1
return emptyClip; return emptyClip;
} }
/// Removes all assets from the asset container matching the specified asset key.
public void ClearPreviousAssets() public void ClearPreviousAssets()
{ {
var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer)); var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer));
@@ -428,6 +491,7 @@ namespace AnimatorAsCode.V1
} }
} }
/// 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() public AacFlNoAnimator NoAnimator()
{ {
return new AacFlNoAnimator(); return new AacFlNoAnimator();
@@ -436,182 +500,16 @@ namespace AnimatorAsCode.V1
public class AacFlNoAnimator public class AacFlNoAnimator
{ {
/// Create a Float parameter, for use without a backing animator.
public AacFlFloatParameter FloatParameter(string parameterName) => AacFlFloatParameter.Internally(parameterName); 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); 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 AacFlBoolParameter BoolParameter(string parameterName) => AacFlBoolParameter.Internally(parameterName);
} }
public class AacFlBlendTree
{
protected AacFlBlendTree(BlendTree blendTree)
{
BlendTree = blendTree;
}
public BlendTree BlendTree { get; }
}
public class AacFlNonInitializedBlendTree : AacFlBlendTree
{
public AacFlNonInitializedBlendTree(BlendTree blendTree) : base(blendTree)
{
}
public AacFlBlendTree2D FreeformCartesian(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
BlendTree.blendType = BlendTreeType.FreeformCartesian2D;
BlendTree.blendParameter = parameterX.Name;
BlendTree.blendParameterY = parameterY.Name;
return new AacFlBlendTree2D(BlendTree);
}
public AacFlBlendTree2D FreeformDirectional(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
BlendTree.blendType = BlendTreeType.FreeformDirectional2D;
BlendTree.blendParameter = parameterX.Name;
BlendTree.blendParameterY = parameterY.Name;
return new AacFlBlendTree2D(BlendTree);
}
public AacFlBlendTree2D SimpleDirectional(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
BlendTree.blendType = BlendTreeType.SimpleDirectional2D;
BlendTree.blendParameter = parameterX.Name;
BlendTree.blendParameterY = parameterY.Name;
return new AacFlBlendTree2D(BlendTree);
}
public AacFlBlendTree1D Simple(AacFlFloatParameter parameter)
{
BlendTree.blendType = BlendTreeType.Simple1D;
BlendTree.blendParameter = parameter.Name;
BlendTree.useAutomaticThresholds = false;
return new AacFlBlendTree1D(BlendTree);
}
public AacFlBlendTreeDirect Direct()
{
BlendTree.blendType = BlendTreeType.Direct;
return new AacFlBlendTreeDirect(BlendTree);
}
}
public class AacFlBlendTree2D : AacFlBlendTree
{
public AacFlBlendTree2D(BlendTree blendTree) : base(blendTree)
{
}
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, Vector2 pos)
{
return WithAnimation(blendTree.BlendTree, pos);
}
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, float x, float y)
{
return WithAnimation(blendTree.BlendTree, x, y);
}
public AacFlBlendTree2D WithAnimation(AacFlClip clip, Vector2 pos)
{
return WithAnimation(clip.Clip, pos);
}
public AacFlBlendTree2D WithAnimation(AacFlClip clip, float x, float y)
{
return WithAnimation(clip.Clip, x, y);
}
public AacFlBlendTree2D WithAnimation(Motion motion, Vector2 pos)
{
return WithAnimation(motion, pos.x, pos.y);
}
public AacFlBlendTree2D WithAnimation(Motion motion, float x, float y)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
childrenList.Add(new ChildMotion
{
motion = motion,
position = new Vector2(x, y),
timeScale = 1f
});
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlBlendTree1D : AacFlBlendTree
{
public AacFlBlendTree1D(BlendTree blendTree) : base(blendTree)
{
}
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold)
{
return WithAnimation(clip.Clip, threshold);
}
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold)
{
return WithAnimation(blendTree.BlendTree, threshold);
}
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
childrenList.Add(new ChildMotion
{
motion = motion,
threshold = threshold,
timeScale = 1f
});
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlBlendTreeDirect : AacFlBlendTree
{
public AacFlBlendTreeDirect(BlendTree blendTree) : base(blendTree)
{
}
public AacFlBlendTreeDirect WithAnimation(AacFlClip clip, AacFlFloatParameter parameter)
{
return WithAnimation(clip.Clip, parameter);
}
public AacFlBlendTreeDirect WithAnimation(AacFlBlendTree blendTree, AacFlFloatParameter parameter)
{
return WithAnimation(blendTree.BlendTree, parameter);
}
public AacFlBlendTreeDirect WithAnimation(Motion motion, AacFlFloatParameter parameter)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
childrenList.Add(new ChildMotion
{
motion = motion,
directBlendParameter = parameter.Name,
timeScale = 1f
});
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlController public class AacFlController
{ {
public AnimatorController AnimatorController; public AnimatorController AnimatorController;
+239
View File
@@ -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
+10
View File
@@ -198,6 +198,11 @@ namespace AnimatorAsCode.V1
return AnyTransition(destination, Machine); return AnyTransition(destination, Machine);
} }
public AacFlTransition AnyTransitionsTo(AacFlStateMachine destination)
{
return AnyTransition(destination, Machine);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination) public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{ {
return EntryTransition(destination, Machine); return EntryTransition(destination, Machine);
@@ -238,6 +243,11 @@ namespace AnimatorAsCode.V1
return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.State)), animatorStateMachine, null, destination.State); return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.State)), animatorStateMachine, null, destination.State);
} }
private AacFlTransition AnyTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.Machine)), animatorStateMachine, null, destination.Machine);
}
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition) private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
{ {
DefaultsProvider.ConfigureTransition(transition); DefaultsProvider.ConfigureTransition(transition);
@@ -9,6 +9,7 @@ namespace AnimatorAsCode.V1.VRC
{ {
public static class AacVRCExtensions public static class AacVRCExtensions
{ {
/// Return an AacVrcAssetLibrary, which lets you select various assets from VRChat.
public static AacVrcAssetLibrary VrcAssets(this AacFlBase that) public static AacVrcAssetLibrary VrcAssets(this AacFlBase that)
{ {
return new AacVrcAssetLibrary(); return new AacVrcAssetLibrary();
@@ -16,18 +16,40 @@ namespace AnimatorAsCode.V1.VRCDestructiveWorkflow
return that.WithAdditonalData(typeof(IAdditionalDataAvatarDescriptor), avatarDescriptor); return that.WithAdditonalData(typeof(IAdditionalDataAvatarDescriptor), avatarDescriptor);
} }
/// Create the main Fx layer of that system, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainFxLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.FX); public static AacFlLayer CreateMainFxLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.FX);
/// Create the main Gesture layer of that system, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainGestureLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Gesture); public static AacFlLayer CreateMainGestureLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Gesture);
/// Create the main Action layer of that system, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainActionLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Action); public static AacFlLayer CreateMainActionLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Action);
/// Create the main Idle layer of that system, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainIdleLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Additive); public static AacFlLayer CreateMainIdleLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Additive);
/// Create the main Locomotion layer of that system, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainLocomotionLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Base); public static AacFlLayer CreateMainLocomotionLayer(this AacFlBase that) => DoCreateMainLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Base);
/// Create the main layer of that system for a specific type of layer, clearing the previous one of the same system. You are not obligated to have a main layer.
public static AacFlLayer CreateMainAv3Layer(this AacFlBase that, VRCAvatarDescriptor.AnimLayerType animLayerType) => DoCreateMainLayerOnController(that, animLayerType); public static AacFlLayer CreateMainAv3Layer(this AacFlBase that, VRCAvatarDescriptor.AnimLayerType animLayerType) => DoCreateMainLayerOnController(that, animLayerType);
/// Create a supporting Fx layer for that system and suffix, 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 static AacFlLayer CreateSupportingFxLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.FX, suffix); public static AacFlLayer CreateSupportingFxLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.FX, suffix);
/// Create a supporting Gesture layer for that system and suffix, 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 static AacFlLayer CreateSupportingGestureLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Gesture, suffix); public static AacFlLayer CreateSupportingGestureLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Gesture, suffix);
/// Create a supporting Action layer for that system and suffix, 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 static AacFlLayer CreateSupportingActionLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Action, suffix); public static AacFlLayer CreateSupportingActionLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Action, suffix);
/// Create a supporting Idle layer for that system and suffix, 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 static AacFlLayer CreateSupportingIdleLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Additive, suffix); public static AacFlLayer CreateSupportingIdleLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Additive, suffix);
/// Create a supporting Locomotion layer for that system and suffix, 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 static AacFlLayer CreateSupportingLocomotionLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Base, suffix); public static AacFlLayer CreateSupportingLocomotionLayer(this AacFlBase that, string suffix) => DoCreateSupportingLayerOnController(that, VRCAvatarDescriptor.AnimLayerType.Base, suffix);
/// Create a supporting layer for that system and suffix, 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 static AacFlLayer CreateSupportingAv3Layer(this AacFlBase that, VRCAvatarDescriptor.AnimLayerType animLayerType, string suffix) => DoCreateSupportingLayerOnController(that, animLayerType, suffix); public static AacFlLayer CreateSupportingAv3Layer(this AacFlBase that, VRCAvatarDescriptor.AnimLayerType animLayerType, string suffix) => DoCreateSupportingLayerOnController(that, animLayerType, suffix);
private static AacFlLayer DoCreateMainLayerOnController(AacFlBase that, VRCAvatarDescriptor.AnimLayerType animType) private static AacFlLayer DoCreateMainLayerOnController(AacFlBase that, VRCAvatarDescriptor.AnimLayerType animType)
@@ -51,12 +73,14 @@ namespace AnimatorAsCode.V1.VRCDestructiveWorkflow
return (AnimatorController) ad.baseAnimationLayers.First(it => it.type == animLayerType).animatorController; return (AnimatorController) ad.baseAnimationLayers.First(it => it.type == animLayerType).animatorController;
} }
/// Remove all main layers matching that system from all animators of the Avatar descriptor.
public static void RemoveAllMainLayers(this AacFlBase that) public static void RemoveAllMainLayers(this AacFlBase that)
{ {
var layerName = that.InternalConfiguration().SystemName; var layerName = that.InternalConfiguration().SystemName;
RemoveLayerOnAllControllers(that, that.InternalConfiguration().DefaultsProvider.ConvertLayerName(layerName)); RemoveLayerOnAllControllers(that, that.InternalConfiguration().DefaultsProvider.ConvertLayerName(layerName));
} }
/// Remove all supporting layers matching that system and suffix from all animators of the Avatar descriptor.
public static void RemoveAllSupportingLayers(this AacFlBase that, string suffix) public static void RemoveAllSupportingLayers(this AacFlBase that, string suffix)
{ {
var layerName = that.InternalConfiguration().SystemName; var layerName = that.InternalConfiguration().SystemName;
+4 -1
View File
@@ -1,6 +1,9 @@
Migrating from V0 to V1 Migrating AnimatorAsCode from V0 to V1
====== ======
TODO: Fix mixed Linear/Easing curve generator???
TODO: Fix undo slow operations (ask bd?)
AnimatorAsCode V1 introduces the following main breaking changes: AnimatorAsCode V1 introduces the following main breaking changes:
- VRChat Avatars is now an optional dependency. AnimatorAsCode can now be used in non-VRChat projects. - VRChat Avatars is now an optional dependency. AnimatorAsCode can now be used in non-VRChat projects.
- All VRChat-related functions have been split between two classes of extension methods. - All VRChat-related functions have been split between two classes of extension methods.