Advertisement
Guest User

Untitled

a guest
Feb 8th, 2019
402
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 24.37 KB | None | 0 0
  1. #if UNITY_EDITOR
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using UnityEditor;
  7. using UnityEngine;
  8. using UnityEngine.Assertions;
  9.  
  10. // This example shows how to use the CSharp animator generator. Specifically, this class shows the "scriptable object"
  11. // animator type. This type uses scriptable objects to serialize it's data. Since this is a scriptable object, you need
  12. // to provide a way create an asset of this type. See the "Create" static method below. This type also requires one file per
  13. // scriptable object(like all scriptable objects in Unity). For this reason I recommend using the CSharpAnimator "Class"
  14. // type instead, since you don't need to do these things.
  15. public class CSharpAnimatorExamples : CSharpAnimator
  16. {
  17.     // Here we can declare serializable fields just like any monobehaviour or scriptable object class. These will appear in the animator's
  18.     // inspector when we create it. We define motions here so we can assign them to our states.
  19.     [SerializeField]
  20.     public Motion idleMotion;
  21.     [SerializeField]
  22.     public Motion runMotion;
  23.     [SerializeField]
  24.     public Motion jumpMotion;
  25.  
  26.     [SerializeField]
  27.     public float speedForRun = 5.0f;
  28.  
  29.     // You can create a method like this to make the type appear in the Unity editor.
  30.     [MenuItem("Assets/Create/CSharpAnimator/Scriptable Object Basic Test")]
  31.     public static void Create()
  32.     {
  33.         CreateWithType(typeof(CSharpAnimatorExamples));
  34.     }
  35.  
  36.     // In order to generate the animator, we need to override the Construct() method. This method should
  37.     // construct and return the AnimatorData so the animator asset can be generated.
  38.     public override AnimatorData Construct()
  39.     {
  40.         // This is how parameters are declared. These will be used to determine which animation should be playing and how. Just like
  41.         // in the animator window, we can create 4 different types of parameters; Float, Bool, Int and Trigger. We can also give them a default
  42.         // value(except trigger) by passing it as the second argument.
  43.         ParameterData speed = FloatParam("Speed", 1.0f);
  44.         ParameterData jumpTrigger = TriggerParam("JumpTrigger");
  45.        
  46.        
  47.         // Here we will define the entire animation layout. We do this by calling 'Animator' and then passing a graph and transition collection to
  48.         // it. Each of these function calls returns a context object that can have methods invoked on it in order to define settings. This allows
  49.         // you to only set the values you care about, and is more flexible than one massive function call with default parameters.
  50.         Animator
  51.         (
  52.             // This is the root of the graph. Inside of here we can define only layers.
  53.             Graph()
  54.             [
  55.                 // Each layer typically takes a name, and it's often a good idea to define a default state.
  56.                 Layer("Base").DefaultState("Idle")
  57.                 [
  58.                     // States and sub state machines are defined within states. Check the advanced test for how to use state machines inside
  59.                     // of layers. Typically a state will take a name(necessary for transitions to reference it), and a motion.
  60.                     State("Idle", idleMotion),
  61.                     State("Run", runMotion),
  62.                     State("Jump", jumpMotion)
  63.                 ]
  64.             ],
  65.  
  66.             // This call defines the group of transitions for the graph. Here we need to reference the states by a name string.
  67.             // Each transition can take a Source(single source), a SourceMultiple(list multiple sources as parameters), a SourceRecursive(recursively add all states
  68.             // below this state machine), any combination of these, as well a single destination state. All the usual transition options should be available through
  69.             // additional method calls chained onto the return value of 'Transition()'. For example use:
  70.             //
  71.             // Transition().Source("Run").Destination("Jump").ExitTime(0.9f).TransitionTime(0.1f)
  72.             //
  73.             // In order to change the exit time and transition time of the transition.
  74.             Transitions()
  75.             [
  76.                 Transition().SourceMultiple("Idle", "Run").Destination("Jump")
  77.                 [
  78.                     // Conditions are listed here. Call 'Float', 'Bool', 'Int', or 'Trigger' functions in order to define them,
  79.                     // depending on the parameter type. Just like in the animator window, all these conditions must be met in order
  80.                     // for the transition to take place. Of course, any of these transitions can be based on constants in code,
  81.                     // or exposed editor fields, so we no longer have to duplicate magic numbers in every transitions like we do in
  82.                     // the animator window.
  83.                     Trigger(jumpTrigger)
  84.                 ],
  85.                 // You can define as many transitions as needed by listing them here.
  86.                 Transition().Source("Jump").Destination("Idle").ExitTime(0.9f),
  87.  
  88.                 Transition().Source("Idle").Destination("Run")
  89.                 [
  90.                     Float(speed, speedForRun, ConditionMode.Greater)
  91.                 ],
  92.                 Transition().Source("Run").Destination("Idle")
  93.                 [
  94.                     Float(speed, speedForRun, ConditionMode.Less)
  95.                 ]
  96.             ]
  97.         );
  98.        
  99.         return currentData;
  100.     }
  101. }
  102.  
  103.  
  104. // This section shows a few examples of how to use the 'Class' version of the animator generator. This is my preferred
  105. // type since, unlike the scriptable object type, they don't require their own file. They're missing none
  106. // of the features of the scriptable object type as far as I'm aware. The only drawback I can see is I use a probably
  107. // unsupported method of drawing the serialized fields, which might break in the future. Also, anytime you rename a type
  108. // you'll have to reassign the type on the asset(you won't lose serialized data though, you'll need to explicitly press apply
  109. // in order to change types, so it won't wipe your data automatically if it can't find the type).
  110. //
  111. // Basically you just need to inherit from CSharpAnimator_ClassBase, override and write the Construct method, and create a "CSharpAnimator Class"
  112. // asset in the editor. Select your type from the drop down list and press generate.
  113.  
  114. // ==================================================================
  115. // ========================== Basic Test ============================
  116. // ==================================================================
  117. public class ClassBasicTest : CSharpAnimator_ClassBase
  118. {
  119.     // Just like the scriptable object type, you can defined serialized fields in the class that will appear in the
  120.     // editor.
  121.     [SerializeField]
  122.     public Motion idleMotion;
  123.     [SerializeField]
  124.     public Motion runMotion;
  125.     [SerializeField]
  126.     public Motion jumpMotion;
  127.  
  128.     [SerializeField]
  129.     public float speedForRun = 5.0f;
  130.  
  131.     // Again, we need to override the Construct method and return an animator data instance. Everything in this method
  132.     // should appear exactly the same as the scriptable object type.
  133.     public override AnimatorData Construct()
  134.     {
  135.         // This is how parameters are declared. These will be used to determine which animation should be playing and how. Just like
  136.         // in the animator window, we can create 4 different types of parameters; Float, Bool, Int and Trigger. We can also give them a default
  137.         // value(except trigger) by passing it as the second argument.
  138.         ParameterData speed = FloatParam("Speed", 1.0f);
  139.         ParameterData jumpTrigger = TriggerParam("JumpTrigger");
  140.        
  141.        
  142.         // Here we will define the entire animation layout. We do this by calling 'Animator' and then passing a graph and transition collection to
  143.         // it. Each of these function calls returns a context object that can have methods invoked on it in order to define settings. This allows
  144.         // you to only set the values you care about, and is more flexible than one massive function call with default parameters.
  145.         Animator
  146.         (
  147.             // This is the root of the graph. Inside of here we can define only layers.
  148.             Graph()
  149.             [
  150.                 // Each layer typically takes a name, and it's often a good idea to define a default state.
  151.                 Layer("Base").DefaultState("Idle")
  152.                 [
  153.                     // States and sub state machines are defined within states. Check the advanced test for how to use state machines inside
  154.                     // of layers. Typically a state will take a name(necessary for transitions to reference it), and a motion.
  155.                     State("Idle", idleMotion),
  156.                     State("Run", runMotion),
  157.                     State("Jump", jumpMotion)
  158.                 ]
  159.             ],
  160.  
  161.             // This call defines the group of transitions for the graph. Here we need to (unfortunately) reference the states by a name string.
  162.             // Each transition can take a Source(single source), a SourceMultiple(list multiple sources as parameters), a SourceRecursive(recursively add all states
  163.             // below this state machine), any combination of these, as well a single destination state. All the usual transition options should be available through
  164.             // additional method calls chained onto the return value of 'Transition()'. For example use:
  165.             //
  166.             // Transition().Source("Run").Destination("Jump").ExitTime(0.9f).TransitionTime(0.1f)
  167.             //
  168.             // In order to change the exit time and transition time of the transition.
  169.             Transitions()
  170.             [
  171.                 Transition().SourceMultiple("Idle", "Run").Destination("Jump")
  172.                 [
  173.                     // Conditions are listed here. Call 'Float', 'Bool', 'Int', or 'Trigger' functions in order to define them,
  174.                     // depending on the parameter type. Just like in the animator window, all these conditions must be met in order
  175.                     // for the transition to take place. Of course, any of these transitions can be based on constants in code,
  176.                     // or exposed editor fields, so we no longer have to duplicate magic numbers in every transitions like we do in
  177.                     // the animator window.
  178.                     Trigger(jumpTrigger)
  179.                 ],
  180.                 // You can define as many transitions as needed by listing them here.
  181.                 Transition().Source("Jump").Destination("Idle").ExitTime(0.9f),
  182.  
  183.                 Transition().Source("Idle").Destination("Run")
  184.                 [
  185.                     Float(speed, speedForRun, ConditionMode.Greater)
  186.                 ],
  187.                 Transition().Source("Run").Destination("Idle")
  188.                 [
  189.                     Float(speed, speedForRun, ConditionMode.Less)
  190.                 ]
  191.             ]
  192.         );
  193.        
  194.         return currentData;
  195.     }
  196. }
  197.  
  198. // ==================================================================
  199. // ======================== Advanced Test ===========================
  200. // ==================================================================
  201. public class ClassAdvancedTest : CSharpAnimator_ClassBase
  202. {
  203.     // Here we can declare editor fields that we can use while generating our animator. This works just like any monobehaviour or scripatble object.
  204.     // The most common field will probably be motions, since we use those to assign an animation to a state. Of course we can use any data we want here,
  205.     // for example we may have a (float) speed threshold the character must meet in order to be in the running state. This could be exposed to the editor
  206.     // here and tweaked before the animator is generated.
  207.  
  208.     // A more complex example used here is the motion array called 'randomIdleMotions'. This allows us to drag and drop any number of idle animations we want in
  209.     // the editor, and have the necessary states and transitions generated automatically using the GetRandomIdleStates and GetTransitionsBetweenRandomIdles functions.
  210.     // A single int parameter called 'currentRandomIdleIndex' then determines which of these idles is currently playing.
  211.     [SerializeField]
  212.     public Motion[] randomIdleMotions;
  213.     [SerializeField]
  214.     public Motion runMotion;
  215.     [SerializeField]
  216.     public Motion jumpMotion;
  217.     [SerializeField]
  218.     public Motion runningJumpMotion;
  219.  
  220.     [SerializeField]
  221.     public Motion crouchIdle;
  222.     [SerializeField]
  223.     public Motion crouchRun;
  224.  
  225.     [SerializeField]
  226.     public Motion falling;
  227.    
  228.     [SerializeField]
  229.     public AvatarMask upperBodyMask;
  230.     [SerializeField]
  231.     public Motion throwObject;
  232.  
  233.     [SerializeField]
  234.     public float speedForRun = 5.0f;
  235.  
  236.     // This function generates idleMotions.Length number of idle states, naming them "RandomIdle_0"..."RandomIdle_N".
  237.     public StateMachineNodeContext[] GetRandomIdleStates(Motion[] idleMotions)
  238.     {
  239.         Assert.IsTrue(idleMotions.Length > 0);
  240.         StateMachineNodeContext[] result = new StateMachineNodeContext[idleMotions.Length];
  241.         for(int i = 0; i < result.Length; ++i)
  242.         {
  243.             result[i] = State("RandomIdle_" + i.ToString(), idleMotions[i]);
  244.         }
  245.         return result;
  246.     }
  247.  
  248.     // This function generates a transition between every idle state to all other idle states based on the currentRandomIdleIndex parameter.
  249.     // In this case there is (idleMotions.Length^2  - idleMotions.Length) number of transitions. This probably isn't necessary, but this
  250.     // shows off how you might use functions like this to save yourself a massive amount of copying states and transitions.
  251.     public TransitionContext[] GetTransitionsBetweenRandomIdles(Motion[] idleMotions, ParameterData indexParam)
  252.     {
  253.         // A transition from every state to every other state except itself.
  254.         int count = (idleMotions.Length * idleMotions.Length) - idleMotions.Length;
  255.         TransitionContext[] result = new TransitionContext[count];
  256.  
  257.         int transitionIndex = 0;
  258.  
  259.         for(int i = 0; i < idleMotions.Length; ++i)
  260.         {
  261.             string thisState = "RandomIdle_" + i.ToString();
  262.             for(int t = 0; t < idleMotions.Length; ++t)
  263.             {
  264.                 if(i != t)
  265.                 {
  266.                     string otherState = "RandomIdle_" + t.ToString();
  267.  
  268.                     result[transitionIndex] = Transition().Source(thisState).Destination(otherState)
  269.                     [
  270.                         Int(indexParam, t, ConditionMode.Equals)
  271.                     ];
  272.                     ++transitionIndex;
  273.                 }
  274.             }
  275.         }
  276.  
  277.         return result;
  278.     }
  279.  
  280.     // This function will construct and return the animator data.
  281.     public override AnimatorData Construct()
  282.     {
  283.         // Declare all parameters we'll need for this graph.
  284.         ParameterData speed = FloatParam("Speed");
  285.         ParameterData isGrounded = BoolParam("IsGrounded", true);
  286.         ParameterData jumpTrigger = TriggerParam("JumpTrigger");
  287.         ParameterData isCrouched = BoolParam("IsCrouched", false);
  288.         ParameterData currentRandomIdleIndex = IntParam("CurrentRandomIdleIndex", 0);
  289.         ParameterData throwTrigger = TriggerParam("ThrowTrigger");
  290.        
  291.         Animator
  292.         (
  293.             Graph()
  294.             [
  295.                 // You can have any number of layers you want. Just keep adding them under Graph[]. The layer index
  296.                 // is based on the order that they appear in this section. Layers can also be assigned tags that will be
  297.                 // given to all child states and state machines unless overridden.
  298.                 Layer("Base")
  299.                     .Tag("BASE_LAYER_TAG")
  300.                 [
  301.                     // State machines can be nested as many times as needed. I find this very useful for grouping together states for
  302.                     // transitions. For example we use 'OnGround' and 'CrouchableStates' state machines to mass generate certain transitions.
  303.                     // All states in 'OnGround' can transition to 'Falling', and all states in 'CrouchableStates' can transition to 'Crouched'.
  304.                     StateMachine("OnGround")
  305.                     [
  306.                         StateMachine("CrouchableStates")
  307.                         [
  308.                             State("Run", runMotion),
  309.  
  310.                             // Because we define a tag here, this statemachine and all it's children will now be given
  311.                             // the 'RANDOM_IDLES_TAG' instead of the previously defined 'BASE_LAYER_TAG'. I find this very useful for
  312.                             // determining what kind of states we're in for gameplay purposes. For example, our character logic can
  313.                             // check if we're in any JumpState by checking for the 'JUMP_TAG' tag before performing an attack. This means
  314.                             // we don't have to hard code checks for individual states and the character logic can be further separated from
  315.                             // our animator logic.
  316.                             StateMachine("RandomIdles")
  317.                                 .Tag("RANDOM_IDLES_TAG")
  318.                             [
  319.                                 // GetRandomIdleStates returns an array of StateMachineNodeContexts so we can call this function here to generate all
  320.                                 // the states we need based off of 'randomIdleMotions'.
  321.                                 GetRandomIdleStates(randomIdleMotions)
  322.                             ]
  323.                         ],
  324.                         StateMachine("Crouched").DefaultState("CrouchIdle")
  325.                         [
  326.                             State("CrouchIdle", crouchIdle),
  327.                             State("CrouchRun", crouchRun)
  328.                         ]
  329.                     ],
  330.  
  331.                     State("Falling", falling),
  332.                    
  333.                     StateMachine("JumpStates").Tag("JUMP_TAG")
  334.                     [
  335.                         State("Jump", jumpMotion),
  336.                         State("RunningJump", runningJumpMotion)
  337.                     ]
  338.                 ],
  339.  
  340.                 // Our second layer is used for animations on the upper body. This is determined by the 'upperBodyMask' avatar mask we
  341.                 // pass into it.
  342.                 Layer("UpperBody")
  343.                     .BlendingMode(LayerBlendingMode.Override)
  344.                     .Weight(1.0f)
  345.                     .Timing(true)
  346.                     .IKPass(true)
  347.                     .AvatarMask(upperBodyMask)
  348.                 [
  349.                     // Pass in null here so we give full control to the base layer when we're not playing an animation on the upper body.
  350.                     State("UpperBodyNone", null),
  351.                     State("Throw", throwObject)
  352.                 ]
  353.             ],
  354.            
  355.             Transitions()
  356.             [
  357. #if true
  358.                 // When defining a transition, we can use SourceRecursive to add all states under a state machine
  359.                 // recursively. This transition says that all random idle states can transition to run if the conditions
  360.                 // are met. This saves a lot of copying transitions, since they only differ in their source state.
  361.                 Transition().SourceRecursive("RandomIdles").Destination("Run")
  362.                 [
  363.                     Float(speed, speedForRun, ConditionMode.Greater),
  364.                     Bool(isGrounded, true)
  365.                 ],
  366.                 // Same thing but back again. Transitioning to RandomIdles will add a transition to the RandomIdles state machine.
  367.                 Transition().Source("Run").Destination("RandomIdles")
  368.                 [
  369.                     Float(speed, speedForRun, ConditionMode.Less),
  370.                     Bool(isGrounded, true)
  371.                 ],
  372.  
  373.                 // Crouched run.
  374.                 Transition().SourceRecursive("CrouchIdle").Destination("CrouchRun")
  375.                 [
  376.                     Float(speed, speedForRun, ConditionMode.Greater),
  377.                     Bool(isGrounded, true)
  378.                 ],
  379.                 Transition().Source("CrouchRun").Destination("CrouchIdle")
  380.                 [
  381.                     Float(speed, speedForRun, ConditionMode.Less),
  382.                     Bool(isGrounded, true)
  383.                 ],
  384.            
  385.                 // Here we use the OnGround state machine to easily define transitions for everything that can be considered on ground.
  386.                 // Don't want a particular animation to transition to jump? That's easy, just don't put it in the 'OnGround' state machine.
  387.                 Transition().SourceRecursive("OnGround").Destination("Jump")
  388.                 [
  389.                     Trigger(jumpTrigger),
  390.                     Float(speed, speedForRun, ConditionMode.Less)
  391.                 ],
  392.                 Transition().SourceRecursive("OnGround").Destination("RunningJump")
  393.                 [
  394.                     Trigger(jumpTrigger),
  395.                     Float(speed, speedForRun, ConditionMode.Greater)
  396.                 ],
  397.                 // We can use SourceMultiple to define a list of specific states as sources. This is how you define a transition with an exit time.
  398.                 // Without specifying an exit time, the transition is assume to have none.
  399.                 Transition().SourceMultiple("Jump", "RunningJump").Destination("RandomIdles").ExitTime(0.9f),
  400.  
  401.                 // Same as above, we're using CrouchableStates to logically define which states can actually go into crounch.
  402.                 // We use 'Crouched' statemachine to say which states can transition back.
  403.                 Transition().SourceRecursive("CrouchableStates").Destination("Crouched")
  404.                 [
  405.                     Bool(isCrouched, true)
  406.                 ],
  407.                 Transition().SourceRecursive("Crouched").Destination("CrouchableStates")
  408.                 [
  409.                     Bool(isCrouched, false)
  410.                 ],
  411.  
  412.                 // Falling
  413.                 Transition().SourceRecursive("OnGround").Destination("Falling")
  414.                 [
  415.                     Bool(isGrounded, false)
  416.                 ],
  417.                 Transition().Source("Falling").Destination("OnGround")
  418.                 [
  419.                     Bool(isGrounded, true)
  420.                 ],
  421.  
  422.                 // Throwing using upper body layer
  423.                 Transition().Source("UpperBodyNone").Destination("Throw")
  424.                 [
  425.                     Trigger(throwTrigger)
  426.                 ],
  427.                 Transition().Source("Throw").Destination("UpperBodyNone").ExitTime(0.9f),
  428. #else
  429.                 // The above transition definitions can also be expressed much more concisely using this form. In a way this is less
  430.                 // readable, and also gives you less options. I personally prefer this way in general, though.
  431.                 Transition(Recursive("RandomIdles"), "Run", Float(speed, speedForRun, ConditionMode.Greater), Bool(isGrounded, true)),
  432.                 Transition(Single("Run"), "RandomIdles", Float(speed, speedForRun, ConditionMode.Less), Bool(isGrounded, true)),
  433.                
  434.                 Transition(Recursive("CrouchIdle"), "CrouchRun", Float(speed, speedForRun, ConditionMode.Greater), Bool(isGrounded, true)),
  435.                 Transition(Single("CrouchRun"), "CrouchIdle", Float(speed, speedForRun, ConditionMode.Less), Bool(isGrounded, true)),
  436.            
  437.                 Transition(Recursive("OnGround"), "Jump", Trigger(jumpTrigger), Float(speed, speedForRun, ConditionMode.Less)),
  438.                 Transition(Recursive("OnGround"), "RunningJump", Trigger(jumpTrigger), Float(speed, speedForRun, ConditionMode.Greater)),
  439.                 Transition(Multiple("Jump", "RunningJump"), "RandomIdles", 0.9f),
  440.                
  441.                 Transition(Recursive("CrouchableStates"), "Crouched", Bool(isCrouched, true)),
  442.                 Transition(Recursive("Crouched"), "CrouchableStates", Bool(isCrouched, false)),
  443.                
  444.                 Transition(Recursive("OnGround"), "Falling", Bool(isGrounded, false)),
  445.                 Transition(Single("Falling"), "OnGround", Bool(isGrounded, true)),
  446.  
  447.                 Transition(Single("UpperBodyNone"), "Throw", Trigger(throwTrigger)),
  448.                 Transition(Single("Throw"), "UpperBodyNone", 0.9f),
  449. #endif
  450.  
  451.                 // Since 'GetTransitionsBetweenRandomIdles' return an array of TransitionContext, we can call it here to
  452.                 // perform more complex logic to generate the random idle transitions for us.
  453.                 GetTransitionsBetweenRandomIdles(randomIdleMotions, currentRandomIdleIndex)
  454.             ]
  455.         );
  456.        
  457.         return currentData;
  458.     }
  459. }
  460.  
  461. // ==================================================================
  462. // ======================= Blend Tree Test ==========================
  463. // ==================================================================
  464. [System.Serializable]
  465. public class LeftRightForwardMotionSet
  466. {
  467.     // This class is used to define a set of animations for various turn rates. This way we don't have to duplicate
  468.     // all the code to define walk states vs run states.
  469.     [SerializeField]
  470.     public float speedThreshold;
  471.  
  472.     [SerializeField]
  473.     public Motion sharpLeft;
  474.     [SerializeField]
  475.     public Motion left;
  476.     [SerializeField]
  477.     public Motion forward;
  478.     [SerializeField]
  479.     public Motion right;
  480.     [SerializeField]
  481.     public Motion sharpRight;
  482. }
  483. public class ClassBlendTreeTest : CSharpAnimator_ClassBase
  484. {
  485.     // As mentioned before, you can serialized anything here, including custom classes. We do this to easily define
  486.     // walk and run turning animations.
  487.     [SerializeField]
  488.     public Motion idle;
  489.     [SerializeField]
  490.     public LeftRightForwardMotionSet walk;
  491.     [SerializeField]
  492.     public LeftRightForwardMotionSet run;
  493.  
  494.     // This function will generate a blend motion for a given set of turning animations.
  495.     public MotionContext GenerateLeftRightForwardBlendMotion(ParameterData param, LeftRightForwardMotionSet set)
  496.     {
  497.         MotionContext result =
  498.         BlendMotion1D(param, false)
  499.         [
  500.             BlendClip1D(set.sharpLeft, 0.0f),
  501.             BlendClip1D(set.left, 2.0f),
  502.             BlendClip1D(set.forward, 5.0f),
  503.             BlendClip1D(set.right, 8.0f),
  504.             BlendClip1D(set.sharpRight, 10.0f)
  505.         ];
  506.         return result;
  507.     }
  508.    
  509.     public override AnimatorData Construct()
  510.     {
  511.         // Our blend parameters are define like usual parameters.
  512.         ParameterData speed = FloatParam("Speed", 0.0f);
  513.         ParameterData turn = FloatParam("Turn", 0.5f);
  514.  
  515.         Animator
  516.         (
  517.             Graph()
  518.             [
  519.                 Layer("Base").DefaultState("LocomotionBlend")
  520.                 [
  521.                     // First we define a blend state. This is just like any other state, except inside it's []
  522.                     // brackets, it takes a single motion. This can be:
  523.                     // - BlendMotion1D
  524.                     // - BlendMotion2DSimpleDirectional
  525.                     // - BlendMotion2DFreeFormDirectional
  526.                     // - BlendMotion2DFreeFormCartesian
  527.                     // - BlendMotionDirect
  528.                     // - BlendClip1D
  529.                     // - BlendClip2D
  530.                     // - BlendClipDirect
  531.                     // All of the above can take any number of the above inside it's [] brackets recursively. Using
  532.                     // this we can construct blend trees. This is an example of idle, walk, and run animations being blended
  533.                     // together based on speed and turn rate. As you can see we can also define the blend thresholds as an
  534.                     // exposed parameter, so they don't have to be hard coded here. The only draw back is, we don't get a
  535.                     // nice animation preview as we tweak the values.
  536.                     BlendState("LocomotionBlend")
  537.                     [
  538.                         BlendMotion1D(speed, false)
  539.                         [
  540.                             BlendClip1D(idle, 0.0f),
  541.                             GenerateLeftRightForwardBlendMotion(turn, walk).ThresholdX(walk.speedThreshold),
  542.                             GenerateLeftRightForwardBlendMotion(turn, run).ThresholdX(run.speedThreshold)
  543.                         ]
  544.                     ]
  545.                 ]
  546.             ],
  547.            
  548.             // Having no transitions is okay.
  549.             Transitions()
  550.         );
  551.        
  552.         return currentData;
  553.     }
  554. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement