Add Animator As Code
This commit is contained in:
@@ -0,0 +1,939 @@
|
||||
using System;
|
||||
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
|
||||
{
|
||||
internal 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;
|
||||
}
|
||||
}
|
||||
|
||||
internal class AacStateMachine
|
||||
{
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly AnimationClip _emptyClip;
|
||||
private readonly AacBackingAnimator _backingAnimator;
|
||||
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||
private readonly float _gridShiftX;
|
||||
private readonly float _gridShiftY;
|
||||
|
||||
public AacStateMachine(AnimatorStateMachine machine, AnimationClip emptyClip, AacBackingAnimator backingAnimator, IAacDefaultsProvider defaultsProvider)
|
||||
{
|
||||
_machine = machine;
|
||||
_emptyClip = emptyClip;
|
||||
_backingAnimator = backingAnimator;
|
||||
_defaultsProvider = defaultsProvider;
|
||||
|
||||
var grid = defaultsProvider.Grid();
|
||||
_gridShiftX = grid.x;
|
||||
_gridShiftY = grid.y;
|
||||
}
|
||||
|
||||
internal AacBackingAnimator BackingAnimator()
|
||||
{
|
||||
return _backingAnimator;
|
||||
}
|
||||
|
||||
public AacStateMachine WithEntryPosition(int x, int y)
|
||||
{
|
||||
_machine.entryPosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacStateMachine WithExitPosition(int x, int y)
|
||||
{
|
||||
_machine.exitPosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacStateMachine WithAnyStatePosition(int x, int y)
|
||||
{
|
||||
_machine.anyStatePosition = GridPosition(x, y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState NewState(string name, int x, int y)
|
||||
{
|
||||
var state = _machine.AddState(name, GridPosition(x, y));
|
||||
_defaultsProvider.ConfigureState(state, _emptyClip);
|
||||
|
||||
return new AacFlState(state, _machine, _defaultsProvider);
|
||||
}
|
||||
|
||||
public AacFlTransition AnyTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return AnyTransition(destination, _machine);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
|
||||
{
|
||||
return EntryTransition(destination, _machine);
|
||||
}
|
||||
|
||||
private AacFlTransition AnyTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.State)), animatorStateMachine, null, destination.State);
|
||||
}
|
||||
|
||||
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||
{
|
||||
_defaultsProvider.ConfigureTransition(transition);
|
||||
return transition;
|
||||
}
|
||||
|
||||
private AacFlEntryTransition EntryTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
return new AacFlEntryTransition(animatorStateMachine.AddEntryTransition(destination.State), animatorStateMachine, null, destination.State);
|
||||
}
|
||||
|
||||
internal Vector3 LastStatePosition()
|
||||
{
|
||||
return _machine.states.Length > 0 ? _machine.states.Last().position : Vector3.zero;
|
||||
}
|
||||
|
||||
private Vector3 GridPosition(int x, int y)
|
||||
{
|
||||
return new Vector3(x * _gridShiftX , y * _gridShiftY, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlState
|
||||
{
|
||||
public readonly AnimatorState State;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||
private readonly AacBackingAnimator _backingAnimator;
|
||||
private VRCAvatarParameterDriver _driver;
|
||||
private VRCAnimatorTrackingControl _tracking;
|
||||
private VRCAnimatorLocomotionControl _locomotionControl;
|
||||
|
||||
public AacFlState(AnimatorState state, AnimatorStateMachine machine, IAacDefaultsProvider defaultsProvider)
|
||||
{
|
||||
State = state;
|
||||
_machine = machine;
|
||||
_defaultsProvider = defaultsProvider;
|
||||
}
|
||||
|
||||
public AacFlState LeftOf(AacFlState otherState) => MoveNextTo(otherState, -1, 0);
|
||||
public AacFlState RightOf(AacFlState otherState) => MoveNextTo(otherState, 1, 0);
|
||||
public AacFlState Over(AacFlState otherState) => MoveNextTo(otherState, 0, -1);
|
||||
public AacFlState Under(AacFlState otherState) => MoveNextTo(otherState, 0, 1);
|
||||
|
||||
public AacFlState LeftOf() => MoveNextTo(null, -1, 0);
|
||||
public AacFlState RightOf() => MoveNextTo(null, 1, 0);
|
||||
public AacFlState Over() => MoveNextTo(null, 0, -1);
|
||||
public AacFlState Under() => MoveNextTo(null, 0, 1);
|
||||
|
||||
public AacFlState Shift(AacFlState otherState, int shiftX, int shiftY) => MoveNextTo(otherState, shiftX, shiftY);
|
||||
|
||||
private AacFlState MoveNextTo(AacFlState otherStateOrSecondToLastWhenNull, int x, int y)
|
||||
{
|
||||
if (otherStateOrSecondToLastWhenNull == null)
|
||||
{
|
||||
var other = _machine.states[_machine.states.Length - 2];
|
||||
Shift(other.position, x, y);
|
||||
|
||||
return this;
|
||||
}
|
||||
else
|
||||
{
|
||||
var other = _machine.states.First(animatorState => animatorState.state == otherStateOrSecondToLastWhenNull.State);
|
||||
Shift(other.position, x, y);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public AacFlState Shift(Vector3 otherPosition, int shiftX, int shiftY)
|
||||
{
|
||||
var states = _machine.states;
|
||||
for (var index = 0; index < states.Length; index++)
|
||||
{
|
||||
var childAnimatorState = states[index];
|
||||
if (childAnimatorState.state == State)
|
||||
{
|
||||
var cms = childAnimatorState;
|
||||
cms.position = otherPosition + new Vector3(shiftX * _defaultsProvider.Grid().x, shiftY * _defaultsProvider.Grid().y, 0);
|
||||
states[index] = cms;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_machine.states = states;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithAnimation(Motion clip)
|
||||
{
|
||||
State.motion = clip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlState WithAnimation(AacFlClip clip)
|
||||
{
|
||||
State.motion = clip.Clip;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition TransitionsTo(AacFlState destination)
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(State.AddTransition(destination.State)), _machine, State, destination.State);
|
||||
}
|
||||
|
||||
public AacFlTransition TransitionsFromAny()
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(_machine.AddAnyStateTransition(State)), _machine, null, State);
|
||||
}
|
||||
|
||||
public AacFlEntryTransition TransitionsFromEntry()
|
||||
{
|
||||
return new AacFlEntryTransition(_machine.AddEntryTransition(State), _machine, null, State);
|
||||
}
|
||||
|
||||
public AacFlState AutomaticallyMovesTo(AacFlState destination)
|
||||
{
|
||||
var transition = ConfigureTransition(State.AddTransition(destination.State));
|
||||
transition.hasExitTime = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AacFlTransition Exits()
|
||||
{
|
||||
return new AacFlTransition(ConfigureTransition(State.AddExitTransition()), _machine, State, null);
|
||||
}
|
||||
|
||||
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||
{
|
||||
_defaultsProvider.ConfigureTransition(transition);
|
||||
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 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(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<VRCAvatarParameterDriver>();
|
||||
_driver.parameters = new List<VRC_AvatarParameterDriver.Parameter>();
|
||||
}
|
||||
|
||||
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 MotionTime(AacFlFloatParameter floatParam)
|
||||
{
|
||||
State.timeParameterActive = true;
|
||||
State.timeParameter = floatParam.Name;
|
||||
|
||||
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<VRCAnimatorTrackingControl>();
|
||||
}
|
||||
|
||||
|
||||
private void CreateLocomotionBehaviorIfNotExists()
|
||||
{
|
||||
if (_locomotionControl != null) return;
|
||||
_locomotionControl = State.AddStateMachineBehaviour<VRCAnimatorLocomotionControl>();
|
||||
}
|
||||
|
||||
public enum TrackingElement
|
||||
{
|
||||
Head,
|
||||
LeftHand,
|
||||
RightHand,
|
||||
Hip,
|
||||
LeftFoot,
|
||||
RightFoot,
|
||||
LeftFingers,
|
||||
RightFingers,
|
||||
Eyes,
|
||||
Mouth
|
||||
}
|
||||
|
||||
public AacFlState WithSpeed(AacFlFloatParameter parameter)
|
||||
{
|
||||
State.speedParameter = parameter.Name;
|
||||
State.speedParameterActive = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlTransition : AacFlNewTransitionContinuation
|
||||
{
|
||||
private readonly AnimatorStateTransition _transition;
|
||||
|
||||
public AacFlTransition(AnimatorStateTransition transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
_transition = transition;
|
||||
}
|
||||
|
||||
public AacFlTransition WithSourceInterruption()
|
||||
{
|
||||
_transition.interruptionSource = TransitionInterruptionSource.Source;
|
||||
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 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, AnimatorState 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)
|
||||
{
|
||||
_transition.AddCondition(mode, threshold, parameter);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public class AacFlNewTransitionContinuation
|
||||
{
|
||||
public readonly AnimatorTransitionBase Transition;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly AnimatorState _sourceNullableIfAny;
|
||||
private readonly AnimatorState _destinationNullableIfExits;
|
||||
|
||||
public AacFlNewTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AacFlTransitionContinuationAbstractWithOr
|
||||
{
|
||||
protected readonly AnimatorTransitionBase Transition;
|
||||
private readonly AnimatorStateMachine _machine;
|
||||
private readonly AnimatorState _sourceNullableIfAny;
|
||||
private readonly AnimatorState _destinationNullableIfExits;
|
||||
|
||||
public AacFlTransitionContinuationAbstractWithOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState 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
|
||||
{
|
||||
newTransition = _machine.AddEntryTransition(_destinationNullableIfExits);
|
||||
}
|
||||
|
||||
return newTransition;
|
||||
}
|
||||
|
||||
private AnimatorStateTransition NewTransition()
|
||||
{
|
||||
if (_sourceNullableIfAny == null)
|
||||
{
|
||||
return _machine.AddAnyStateTransition(_destinationNullableIfExits);
|
||||
}
|
||||
|
||||
if (_destinationNullableIfExits == null)
|
||||
{
|
||||
return _sourceNullableIfAny.AddExitTransition();
|
||||
}
|
||||
|
||||
return _sourceNullableIfAny.AddTransition(_destinationNullableIfExits);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user