From ea54506b53e4f0e84ea6e81fbd0e6acd60116983 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Fri, 16 Dec 2022 21:14:31 +0100 Subject: [PATCH] VRC behaviors to work on both States and SSM's. All VRC-specific behavior helpers are now extension functions that can be called using AacAnimatorNode --- Examples/GenExample3_Gesturing.cs | 1 + Framework/Editor/V0/AacAnimatorNode.cs | 6 + Framework/Editor/V0/AacFlStates.cs | 348 ++---------------- .../V0/Extensions/VRChat/TrackingElement.cs | 16 + .../Extensions/VRChat/VrcStateExtensions.cs | 289 +++++++++++++++ 5 files changed, 336 insertions(+), 324 deletions(-) create mode 100644 Framework/Editor/V0/Extensions/VRChat/TrackingElement.cs create mode 100644 Framework/Editor/V0/Extensions/VRChat/VrcStateExtensions.cs diff --git a/Examples/GenExample3_Gesturing.cs b/Examples/GenExample3_Gesturing.cs index 280ee6b..89f2d12 100644 --- a/Examples/GenExample3_Gesturing.cs +++ b/Examples/GenExample3_Gesturing.cs @@ -1,6 +1,7 @@ #if UNITY_EDITOR using System.Linq; using AnimatorAsCode.V0; +using AnimatorAsCode.V0.Extensions.VRChat; using UnityEngine; using VRC.SDK3.Avatars.Components; using UnityEditor; diff --git a/Framework/Editor/V0/AacAnimatorNode.cs b/Framework/Editor/V0/AacAnimatorNode.cs index c79aa7e..c351007 100644 --- a/Framework/Editor/V0/AacAnimatorNode.cs +++ b/Framework/Editor/V0/AacAnimatorNode.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Generic; using UnityEngine; // ReSharper disable once CheckNamespace @@ -14,6 +16,8 @@ namespace AnimatorAsCode.V0 protected readonly AacFlStateMachine ParentMachine; protected readonly IAacDefaultsProvider DefaultsProvider; + protected Dictionary behaviorCache = new Dictionary(); + protected AacAnimatorNode(AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider) { ParentMachine = parentMachine; @@ -53,5 +57,7 @@ namespace AnimatorAsCode.V0 SetPosition(otherPosition + new Vector3(shiftX * DefaultsProvider.Grid().x, shiftY * DefaultsProvider.Grid().y, 0)); return (TNode) this; } + + public abstract TBehaviour EnsureBehaviour() where TBehaviour : StateMachineBehaviour; } } diff --git a/Framework/Editor/V0/AacFlStates.cs b/Framework/Editor/V0/AacFlStates.cs index e84be4d..63aecba 100644 --- a/Framework/Editor/V0/AacFlStates.cs +++ b/Framework/Editor/V0/AacFlStates.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.Linq; using UnityEditor.Animations; using UnityEngine; -using VRC.SDK3.Avatars.Components; -using VRC.SDKBase; // ReSharper disable once CheckNamespace namespace AnimatorAsCode.V0 @@ -297,16 +295,24 @@ namespace AnimatorAsCode.V0 Machine.defaultState = newDefaultState.State; return this; } + + public override TBehaviour EnsureBehaviour() + { + if (behaviorCache.TryGetValue(typeof(TBehaviour), out var existingBehavior)) + return (TBehaviour)existingBehavior; + + foreach (var behaviour in Machine.behaviours) + if (behaviour is TBehaviour myBehaviour) + return myBehaviour; + + return Machine.AddStateMachineBehaviour(); + } } public class AacFlState : AacAnimatorNode { public readonly AnimatorState State; private readonly AnimatorStateMachine _machine; - private VRCAvatarParameterDriver _driver; - private VRCAnimatorTrackingControl _tracking; - private VRCAnimatorLocomotionControl _locomotionControl; - private VRCAnimatorTemporaryPoseSpace _temporaryPoseSpace; public AacFlState(AnimatorState state, AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider) : base(parentMachine, defaultsProvider) { @@ -371,259 +377,12 @@ namespace AnimatorAsCode.V0 return transition; } - public AacFlState Drives(AacFlIntParameter parameter, int value) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Set, - name = parameter.Name, value = value - }); - return this; - } - - public AacFlState Drives(AacFlFloatParameter parameter, float value) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Set, - name = parameter.Name, value = value - }); - return this; - } - - public AacFlState DrivingIncreases(AacFlFloatParameter parameter, float additiveValue) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Add, - name = parameter.Name, value = additiveValue - }); - return this; - } - - public AacFlState DrivingDecreases(AacFlFloatParameter parameter, float positiveValueToDecreaseBy) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Add, - name = parameter.Name, value = -positiveValueToDecreaseBy - }); - return this; - } - - public AacFlState DrivingIncreases(AacFlIntParameter parameter, int additiveValue) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Add, - name = parameter.Name, value = additiveValue - }); - return this; - } - - public AacFlState DrivingDecreases(AacFlIntParameter parameter, int positiveValueToDecreaseBy) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Add, - name = parameter.Name, value = -positiveValueToDecreaseBy - }); - return this; - } - - public AacFlState DrivingRandomizesLocally(AacFlFloatParameter parameter, float min, float max) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Random, - name = parameter.Name, valueMin = min, valueMax = max - }); - _driver.localOnly = true; - return this; - } - - public AacFlState DrivingRandomizesLocally(AacFlBoolParameter parameter, float chance) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Random, - name = parameter.Name, chance = chance - }); - _driver.localOnly = true; - return this; - } - - public AacFlState DrivingRandomizesLocally(AacFlIntParameter parameter, int min, int max) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - type = VRC_AvatarParameterDriver.ChangeType.Random, - name = parameter.Name, valueMin = min, valueMax = max - }); - _driver.localOnly = true; - return this; - } - - public AacFlState Drives(AacFlBoolParameter parameter, bool value) - { - CreateDriverBehaviorIfNotExists(); - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - name = parameter.Name, value = value ? 1 : 0 - }); - return this; - } - - public AacFlState Drives(AacFlBoolParameterGroup parameters, bool value) - { - CreateDriverBehaviorIfNotExists(); - foreach (var parameter in parameters.ToList()) - { - _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter - { - name = parameter.Name, value = value ? 1 : 0 - }); - } - return this; - } - - public AacFlState DrivingLocally() - { - CreateDriverBehaviorIfNotExists(); - _driver.localOnly = true; - return this; - } - - private void CreateDriverBehaviorIfNotExists() - { - if (_driver != null) return; - _driver = State.AddStateMachineBehaviour(); - _driver.parameters = new List(); - } - public AacFlState WithWriteDefaultsSetTo(bool shouldWriteDefaults) { State.writeDefaultValues = shouldWriteDefaults; return this; } - public AacFlState PrintsToLogUsingTrackingBehaviour(string value) - { - CreateTrackingBehaviorIfNotExists(); - _tracking.debugString = value; - - return this; - } - - public AacFlState TrackingTracks(TrackingElement element) - { - CreateTrackingBehaviorIfNotExists(); - SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Tracking); - - return this; - } - - public AacFlState TrackingAnimates(TrackingElement element) - { - CreateTrackingBehaviorIfNotExists(); - SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Animation); - - return this; - } - - public AacFlState TrackingSets(TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType) - { - CreateTrackingBehaviorIfNotExists(); - SettingElementTo(element, trackingType); - - return this; - } - - public AacFlState LocomotionEnabled() - { - CreateLocomotionBehaviorIfNotExists(); - _locomotionControl.disableLocomotion = false; - - return this; - } - - public AacFlState LocomotionDisabled() - { - CreateLocomotionBehaviorIfNotExists(); - _locomotionControl.disableLocomotion = true; - - return this; - } - - public AacFlState PlayableEnables(VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) - { - return PlayableSets(blendable, blendDurationSeconds, 1.0f); - } - - public AacFlState PlayableDisables(VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) - { - return PlayableSets(blendable, blendDurationSeconds, 0.0f); - } - - public AacFlState PlayableSets(VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds, float weight) - { - var playable = State.AddStateMachineBehaviour(); - playable.layer = blendable; - playable.goalWeight = weight; - playable.blendDuration = blendDurationSeconds; - - return this; - } - - public AacFlState PoseSpaceEntered(float delaySeconds = 0f) - { - CreateTemporaryPoseSpaceBehaviorIfNotExists(); - _temporaryPoseSpace.enterPoseSpace = true; - _temporaryPoseSpace.fixedDelay = true; - _temporaryPoseSpace.delayTime = delaySeconds; - - return this; - } - - public AacFlState PoseSpaceExited(float delaySeconds = 0f) - { - CreateTemporaryPoseSpaceBehaviorIfNotExists(); - _temporaryPoseSpace.enterPoseSpace = false; - _temporaryPoseSpace.fixedDelay = true; - _temporaryPoseSpace.delayTime = delaySeconds; - - return this; - } - - public AacFlState PoseSpaceEnteredPercent(float delayNormalized) - { - CreateTemporaryPoseSpaceBehaviorIfNotExists(); - _temporaryPoseSpace.enterPoseSpace = true; - _temporaryPoseSpace.fixedDelay = false; - _temporaryPoseSpace.delayTime = delayNormalized; - - return this; - } - - public AacFlState PoseSpaceExitedPercent(float delayNormalized) - { - CreateTemporaryPoseSpaceBehaviorIfNotExists(); - _temporaryPoseSpace.enterPoseSpace = false; - _temporaryPoseSpace.fixedDelay = false; - _temporaryPoseSpace.delayTime = delayNormalized; - - return this; - } - public AacFlState MotionTime(AacFlFloatParameter floatParam) { State.timeParameterActive = true; @@ -648,77 +407,6 @@ namespace AnimatorAsCode.V0 return this; } - private void SettingElementTo(TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target) - { - switch (element) - { - case TrackingElement.Head: - _tracking.trackingHead = target; - break; - case TrackingElement.LeftHand: - _tracking.trackingLeftHand = target; - break; - case TrackingElement.RightHand: - _tracking.trackingRightHand = target; - break; - case TrackingElement.Hip: - _tracking.trackingHip = target; - break; - case TrackingElement.LeftFoot: - _tracking.trackingLeftFoot = target; - break; - case TrackingElement.RightFoot: - _tracking.trackingRightFoot = target; - break; - case TrackingElement.LeftFingers: - _tracking.trackingLeftFingers = target; - break; - case TrackingElement.RightFingers: - _tracking.trackingRightFingers = target; - break; - case TrackingElement.Eyes: - _tracking.trackingEyes = target; - break; - case TrackingElement.Mouth: - _tracking.trackingMouth = target; - break; - default: - throw new ArgumentOutOfRangeException(nameof(element), element, null); - } - } - - private void CreateTrackingBehaviorIfNotExists() - { - if (_tracking != null) return; - _tracking = State.AddStateMachineBehaviour(); - } - - private void CreateLocomotionBehaviorIfNotExists() - { - if (_locomotionControl != null) return; - _locomotionControl = State.AddStateMachineBehaviour(); - } - - private void CreateTemporaryPoseSpaceBehaviorIfNotExists() - { - if (_temporaryPoseSpace != null) return; - _temporaryPoseSpace = State.AddStateMachineBehaviour(); - } - - public enum TrackingElement - { - Head, - LeftHand, - RightHand, - Hip, - LeftFoot, - RightFoot, - LeftFingers, - RightFingers, - Eyes, - Mouth - } - public AacFlState WithSpeed(AacFlFloatParameter parameter) { State.speedParameterActive = true; @@ -755,6 +443,18 @@ namespace AnimatorAsCode.V0 } _machine.states = states; } + + public override TBehaviour EnsureBehaviour() + { + if (behaviorCache.TryGetValue(typeof(TBehaviour), out var existingBehavior)) + return (TBehaviour)existingBehavior; + + foreach (var behaviour in State.behaviours) + if (behaviour is TBehaviour myBehaviour) + return myBehaviour; + + return State.AddStateMachineBehaviour(); + } } public class AacFlTransition : AacFlNewTransitionContinuation diff --git a/Framework/Editor/V0/Extensions/VRChat/TrackingElement.cs b/Framework/Editor/V0/Extensions/VRChat/TrackingElement.cs new file mode 100644 index 0000000..231fbbc --- /dev/null +++ b/Framework/Editor/V0/Extensions/VRChat/TrackingElement.cs @@ -0,0 +1,16 @@ +namespace AnimatorAsCode.V0.Extensions.VRChat +{ + public enum TrackingElement + { + Head, + LeftHand, + RightHand, + Hip, + LeftFoot, + RightFoot, + LeftFingers, + RightFingers, + Eyes, + Mouth + } +} \ No newline at end of file diff --git a/Framework/Editor/V0/Extensions/VRChat/VrcStateExtensions.cs b/Framework/Editor/V0/Extensions/VRChat/VrcStateExtensions.cs new file mode 100644 index 0000000..aac6c87 --- /dev/null +++ b/Framework/Editor/V0/Extensions/VRChat/VrcStateExtensions.cs @@ -0,0 +1,289 @@ +using System; +using VRC.SDK3.Avatars.Components; +using VRC.SDKBase; + +namespace AnimatorAsCode.V0.Extensions.VRChat +{ + public static class VrcStateExtensions + { + + public static TNode Drives(this TNode node,AacFlIntParameter parameter, int value) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Set, + name = parameter.Name, value = value + }); + return node; + } + + public static TNode Drives(this TNode node,AacFlFloatParameter parameter, float value) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Set, + name = parameter.Name, value = value + }); + return node; + } + + public static TNode DrivingIncreases(this TNode node,AacFlFloatParameter parameter, float additiveValue) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Add, + name = parameter.Name, value = additiveValue + }); + return node; + } + + public static TNode DrivingDecreases(this TNode node,AacFlFloatParameter parameter, float positiveValueToDecreaseBy) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Add, + name = parameter.Name, value = -positiveValueToDecreaseBy + }); + return node; + } + + public static TNode DrivingIncreases(this TNode node,AacFlIntParameter parameter, int additiveValue) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Add, + name = parameter.Name, value = additiveValue + }); + return node; + } + + public static TNode DrivingDecreases(this TNode node,AacFlIntParameter parameter, int positiveValueToDecreaseBy) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Add, + name = parameter.Name, value = -positiveValueToDecreaseBy + }); + return node; + } + + public static TNode DrivingRandomizesLocally(this TNode node,AacFlFloatParameter parameter, float min, float max) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Random, + name = parameter.Name, valueMin = min, valueMax = max + }); + driver.localOnly = true; + return node; + } + + public static TNode DrivingRandomizesLocally(this TNode node,AacFlBoolParameter parameter, float chance) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Random, + name = parameter.Name, chance = chance + }); + driver.localOnly = true; + return node; + } + + public static TNode DrivingRandomizesLocally(this TNode node,AacFlIntParameter parameter, int min, int max) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + type = VRC_AvatarParameterDriver.ChangeType.Random, + name = parameter.Name, valueMin = min, valueMax = max + }); + driver.localOnly = true; + return node; + } + + public static TNode Drives(this TNode node,AacFlBoolParameter parameter, bool value) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + name = parameter.Name, value = value ? 1 : 0 + }); + return node; + } + + public static TNode Drives(this TNode node,AacFlBoolParameterGroup parameters, bool value) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + foreach (var parameter in parameters.ToList()) + { + driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter + { + name = parameter.Name, value = value ? 1 : 0 + }); + } + return node; + } + + public static TNode DrivingLocally(this TNode node) where TNode : AacAnimatorNode + { + var driver = node.EnsureBehaviour(); + driver.localOnly = true; + return node; + } + + public static TNode PrintsToLogUsingTrackingBehaviour(this TNode node, string value) where TNode : AacAnimatorNode + { + var tracking = node.EnsureBehaviour(); + tracking.debugString = value; + + return node; + } + + public static TNode TrackingTracks(this TNode node, TrackingElement element) where TNode : AacAnimatorNode + { + var tracking = node.EnsureBehaviour(); + SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Tracking); + + return node; + } + + public static TNode TrackingAnimates(this TNode node, TrackingElement element) where TNode : AacAnimatorNode + { + var tracking = node.EnsureBehaviour(); + SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Animation); + + return node; + } + + public static TNode TrackingSets(this TNode node, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType) where TNode : AacAnimatorNode + { + var tracking = node.EnsureBehaviour(); + SettingElementTo(tracking, element, trackingType); + + return node; + } + + private static void SettingElementTo(VRCAnimatorTrackingControl tracking, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target) + { + switch (element) + { + case TrackingElement.Head: + tracking.trackingHead = target; + break; + case TrackingElement.LeftHand: + tracking.trackingLeftHand = target; + break; + case TrackingElement.RightHand: + tracking.trackingRightHand = target; + break; + case TrackingElement.Hip: + tracking.trackingHip = target; + break; + case TrackingElement.LeftFoot: + tracking.trackingLeftFoot = target; + break; + case TrackingElement.RightFoot: + tracking.trackingRightFoot = target; + break; + case TrackingElement.LeftFingers: + tracking.trackingLeftFingers = target; + break; + case TrackingElement.RightFingers: + tracking.trackingRightFingers = target; + break; + case TrackingElement.Eyes: + tracking.trackingEyes = target; + break; + case TrackingElement.Mouth: + tracking.trackingMouth = target; + break; + default: + throw new ArgumentOutOfRangeException(nameof(element), element, null); + } + } + + public static TNode LocomotionEnabled(this TNode node) where TNode : AacAnimatorNode + { + var locomotionControl = node.EnsureBehaviour(); + locomotionControl.disableLocomotion = false; + + return node; + } + + public static TNode LocomotionDisabled(this TNode node) where TNode : AacAnimatorNode + { + var locomotionControl = node.EnsureBehaviour(); + locomotionControl.disableLocomotion = true; + + return node; + } + + public static TNode PlayableEnables(this TNode node, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) where TNode : AacAnimatorNode + { + var playable = node.EnsureBehaviour(); + PlayableSets(playable, blendable, blendDurationSeconds, 1.0f); + return node; + } + + public static TNode PlayableDisables(this TNode node, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) where TNode : AacAnimatorNode + { + var playable = node.EnsureBehaviour(); + PlayableSets(playable, blendable, blendDurationSeconds, 0.0f); + return node; + } + + public static void PlayableSets(VRCPlayableLayerControl playable, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds, float weight) + { + playable.layer = blendable; + playable.goalWeight = weight; + playable.blendDuration = blendDurationSeconds; + } + + public static TNode PoseSpaceEntered(this TNode node, float delaySeconds = 0f) where TNode : AacAnimatorNode + { + var temporaryPoseSpace = node.EnsureBehaviour(); + temporaryPoseSpace.enterPoseSpace = true; + temporaryPoseSpace.fixedDelay = true; + temporaryPoseSpace.delayTime = delaySeconds; + + return node; + } + + public static TNode PoseSpaceExited(this TNode node, float delaySeconds = 0f) where TNode : AacAnimatorNode + { + var temporaryPoseSpace = node.EnsureBehaviour(); + temporaryPoseSpace.enterPoseSpace = false; + temporaryPoseSpace.fixedDelay = true; + temporaryPoseSpace.delayTime = delaySeconds; + + return node; + } + + public static TNode PoseSpaceEnteredPercent(this TNode node, float delayNormalized) where TNode : AacAnimatorNode + { + var temporaryPoseSpace = node.EnsureBehaviour(); + temporaryPoseSpace.enterPoseSpace = true; + temporaryPoseSpace.fixedDelay = false; + temporaryPoseSpace.delayTime = delayNormalized; + + return node; + } + + public static TNode PoseSpaceExitedPercent(this TNode node, float delayNormalized) where TNode : AacAnimatorNode + { + var temporaryPoseSpace = node.EnsureBehaviour(); + temporaryPoseSpace.enterPoseSpace = false; + temporaryPoseSpace.fixedDelay = false; + temporaryPoseSpace.delayTime = delayNormalized; + return node; + } + } +} \ No newline at end of file