banner



How To Switch Animations For Different Weapons Unity

Difficulty: Intermediate - Recommended after Interrupt Management and Brain Transplants

Location: Assets/Plugins/Animancer/Examples/06 State Machines/06 Weapons

Namespace: Animancer.Examples.StateMachines.Weapons

This example demonstrates how you can implement a graphic symbol that can move around and attack with various dissimilar weapons. It is based on a character and animations downloaded from Mixamo which unfortunately cannot exist legally redistributed in their raw source course, meaning that they cannot be directly included in Animancer. So instead of providing a fix-made scene, this instance explains how to download the required assets and set them up from scratch in Unity using the Brain Transplants example equally a base.

Required Assets

Character

The first thing you demand to decide is which character model yous want to apply:

  • You can download whatsoever of the Mixamo Characters.
    • We are using the grapheme called Paladin J Nordstrom, but you can choose any you like.
    • Once you take downloaded the character you will demand to configure its Import Settings as explained hither, including exposing the Right Hand bone so that we can attach weapons to it.
  • The DefaultHumanoid model included in Animancer at Assets/Plugins/Animancer/Examples/Art/Default Humanoid would work.
  • Or you could even use a Sprite based character if you have all the animations listed beneath.

Animations

One time you have a graphic symbol, you will need to get the post-obit animations for them:

Animations Import Settings

Idle, Walk, and Run.

If you are using a Humanoid Rig, the Humanoid-Idle, Humanoid-Walk, and Humanoid-Run animations included in Animancer will work.

The Import Settings of these animations should have Loop Time and Loop Pose enabled.

You tin can disable Loop Pose if yous want to use Root Motion for the grapheme's master movements.

Several Attack animations for each weapon y'all want to implement.

Nosotros are using 3 weapons with the post-obit Mixamo Animations:

  • Unarmed uses Punching and Battle which comprise one attack each.
  • Gild uses Ane Hand Club Philharmonic which contains three attacks that we split up in Unity.
  • Great Sword uses Great Sword Slash which contains 3 attacks that we separate in Unity.
We desire to let the animations to motion the character with Root Movement just not rotate them, so nosotros set the Root Transform Rotation and Root Transform Position (Y) to Bake Into Pose based on the Original values.

Optional Sheathe and Unsheathe animations for each weapon.

We are using the post-obit Mixamo Animations:

  • None for Unarmed
  • Draw Sword 2 for the Club which nosotros play backwards to sheathe it.
  • Draw A Great Sword 2 and Sheath A Great Sword ane for the Swell Sword.
Aforementioned as above.

Weapons

Yous will also need a model for each weapon except Unarmed. The Getting Animations page lists several places where you tin get models or programs to create your own, but for this example we are simply using primitive shapes (cubes, cylinders, and capsules). Most of the construction should exist obvious at a glance except for the spiked parts which are created by skewing cubes:

Hierarchy Transform

By rotating the kid cube 45 degrees on one axis then scaling the parent object on a dissimilar axis, the cube gets stretched diagonally then that it turns into a spike:

Set on Input

The AttackInput script would normally be role of the CharacterBrain, but we have implemented it separately so that we tin can reuse the classes from the Brain Transplants case and have it work with both the KeyboardBrain and MouseBrain:
            using Animancer; using Animancer.Examples.StateMachines.Brains; using Animancer.FSM; using Animancer.Units; using UnityEngine;  public sealed class AttackInput : MonoBehaviour {     [SerializeField] private CharacterState _Attack;     [SerializeField, Seconds] private float _AttackInputTimeOut = 0.5f;      individual StateMachine<CharacterState>.InputBuffer _InputBuffer;      private void Awake()     {         _InputBuffer = new StateMachine<CharacterState>.InputBuffer(_Attack.Character.StateMachine);     }      private void Update()     {         if (Input.GetButtonDown("Fire2"))// Right Click by default.         {             _InputBuffer.Buffer(_Attack, _AttackInputTimeOut);         }          _InputBuffer.Update();     } }                      

Information technology starts with a reference to the Attack State which is assigned in the Inspector (once we create it below):

          [SerializeField] private CharacterState _Attack;                  

We are also using a concept known as input buffering which only ways that if a button press fails to trigger the desired action, it will still be able to do and then for a brusque time later. Animancer's Finite State Machine system has an InputBuffer course which is very easy to use. Then we brand a "time out" field to determine how long the buffer will last and initialize it with the StateMachine it will be buffering (in seconds):

          [SerializeField, Seconds] individual float _AttackInputTimeOut = 0.5f;  private StateMachine<CharacterState>.InputBuffer _InputBuffer;  private void Awake() {     _InputBuffer = new StateMachine<CharacterState>.InputBuffer(_Attack.Character.StateMachine); }                  

Then when we discover the Attack push button beingness pressed and would ordinarily call ...StateMachine.TrySetState(_Attack) we instead call Buffer on the InputBuffer where we also specify the time out elapsing:

          individual void Update() {     if (Input.GetButtonDown("Fire2"))// Right Click by default.     {         _InputBuffer.Buffer(_Attack, _AttackInputTimeOut);     }                  

Then at the finish of the Update method nosotros call Update on the buffer to brand it try to enter the buffered action and bank check if information technology has timed out:

                      _InputBuffer.Update(); }                  

You could give each attack a different time out period, but using the same 0.five second window for every attack tends to give more than consistent gameplay where the actor tin can go a feel for when they will need to printing the button.

Weapon

The Weapon script is simply a component which holds the animations relating to a weapon so that it tin can be attached to the weapon'due south model in the scene:

          using Animancer; using UnityEngine;  public sealed course Weapon : MonoBehaviour {     [SerializeField]     private ClipTransition[] _AttackAnimations;     public ClipTransition[] AttackAnimations => _AttackAnimations;      [SerializeField]     private ClipTransition _EquipAnimation;     public ClipTransition EquipAnimation => _EquipAnimation;      [SerializeField]     private ClipTransition _UnequipAnimation;     public ClipTransition UnequipAnimation => _UnequipAnimation; }                  

In a existent game, this class might have other details like impairment, damage type, weapon category, etc. It could also inherit from a base Item class for things like weight, price, and description.

Equip State

The EquipState script manages the currently equipped Weapon. It is a is a CharacterState and then that other actions cannot be performed while it is playing the EquipAnimation and UnequipAnimation of the Weapon when it is changed:
            using Animancer; using Animancer.Examples.StateMachines.Brains; using Animancer.FSM; using UnityEngine;  public sealed class EquipState : CharacterState {     [SerializeField] individual Transform _WeaponHolder;     [SerializeField] individual Weapon _Weapon;      private Weapon _EquippingWeapon;     private Action _OnUnequipEnd;      public Weapon Weapon     {         get => _Weapon;         set up         {             if (enabled)                 render;              _EquippingWeapon = value;             if (!Grapheme.StateMachine.TrySetState(this))                 _EquippingWeapon = _Weapon;         }     }      private void Awake()     {         _EquippingWeapon = _Weapon;         _OnUnequipEnd = OnUnequipEnd;         AttachWeapon();     }      public override bool CanEnterState => _Weapon != _EquippingWeapon;      private void OnEnable()     {         if (_Weapon.UnequipAnimation.IsValid)         {             var country = Character.Animancer.Play(_Weapon.UnequipAnimation);             state.Events.OnEnd = _OnUnequipEnd;         }         else         {             OnUnequipEnd();         }     }      individual void OnUnequipEnd()     {         DetachWeapon();         _Weapon = _EquippingWeapon;         AttachWeapon();          if (_Weapon.EquipAnimation.IsValid)         {             var state = Character.Animancer.Play(_Weapon.EquipAnimation);             country.Events.OnEnd = Character.ForceEnterIdleState;         }         else         {             Graphic symbol.StateMachine.ForceSetState(Character.Idle);         }     }      private void AttachWeapon()     {         if (_Weapon == null)             return;          if (_WeaponHolder != nil)         {             var transform = _Weapon.transform;             transform.parent = _WeaponHolder;             transform.localPosition = default;             transform.localRotation = Quaternion.identity;             transform.localScale = Vector3.one;         }          _Weapon.gameObject.SetActive(true);     }      private void DetachWeapon()     {         if (_Weapon == nil)             return;          _Weapon.transform.parent = transform;         _Weapon.gameObject.SetActive(faux);     }      individual void FixedUpdate()     {         Character.Rigidbody.velocity = default;     }      public override bool CanExitState => false; }                      

The RightHand bone of a character is commonly in their wrist, so instead of needing to manually get-go the equipped weapon from that position we take simply created an empty Weapon Holder object every bit a kid of the hand which we can attach weapons to:

          [SerializeField] private Transform _WeaponHolder;                  

We want other scripts (the AttackState in this example) to be able to access the currently equipped Weapon and besides attempt to change it (unremarkably the CharacterBrain would handle that, simply in this case we are just using UI Buttons) and then we have private fields for the current weapon and the new ane we desire to equip with a public property that tries to put the Character in this country when you ready it:

          [SerializeField] private Weapon _Weapon;  private Weapon _EquippingWeapon;  public Weapon Weapon {     become => _Weapon;     set     {         if (enabled)             return;          _EquippingWeapon = value;         if (!Grapheme.StateMachine.TrySetState(this))             _EquippingWeapon = _Weapon;     } }  private void Awake() {     _EquippingWeapon = _Weapon;     ... }                  

We only want this land to be entered when you lot are actually irresolute to a dissimilar Weapon, and so we override the CanEnterState belongings to enforce that restriction:

          public override bool CanEnterState => _Weapon != _EquippingWeapon;                  

Note that if CanEnterState (or the CanExitState belongings of whatsoever state the Character is currently in) returns false, the Weapon property simply undoes the modify. This ensures that the character cannot change weapons in the middle of other actions that do not let Interruptions (such equally attacks).

When the character does actually enter this country, nosotros desire to play the UnequipAnimation from the previous Weapon if it has one and then swap to the new weapon:

          private void OnEnable() {     if (_Weapon.UnequipAnimation.IsValid)     {         var state = Character.Animancer.Play(_Weapon.UnequipAnimation);         state.Events.OnEnd = _OnUnequipEnd;     }                  

Or if there is no UnequipAnimation, we but swap to the new Weapon immediately:

                      else     {         OnUnequipEnd();     } }                  

Directly assigning the OnUnequipEnd method to the OnEnd result would create some Garbage every time this state is entered, and so instead we want to create a consul from it on startup so that we tin can reuse the same object every time:

          private Action _OnUnequipEnd;  private void Awake() {     ...     _OnUnequipEnd = OnUnequipEnd;     AttachWeapon(); }                  

One time the UnequipAnimation ends (or is skipped because it was missing), nosotros detach the previous Weapon from the character's mitt, assign and adhere the new weapon, and and so play the EquipAnimation of the new Weapon:

          private void OnUnequipEnd() {     DetachWeapon();     _Weapon = _EquippingWeapon;     AttachWeapon();      if (_Weapon.EquipAnimation.IsValid)     {         var country = Graphic symbol.Animancer.Play(_Weapon.EquipAnimation);         country.Events.OnEnd = Graphic symbol.ForceEnterIdleState;     }     else     {         Character.StateMachine.ForceSetState(Graphic symbol.Idle);     } }  private void AttachWeapon() {     if (_Weapon == null)         return;      if (_WeaponHolder != null)     {         var transform = _Weapon.transform;         transform.parent = _WeaponHolder;         transform.localPosition = default;         transform.localRotation = Quaternion.identity;         transform.localScale = Vector3.i;     }      _Weapon.gameObject.SetActive(true); }  private void DetachWeapon() {     if (_Weapon == null)         return;      _Weapon.transform.parent = transform;     _Weapon.gameObject.SetActive(false); }                  

And finally, nosotros foreclose annihilation from moving the character while in this state or Interrupting it:

          individual void FixedUpdate() {     Character.Rigidbody.velocity = default; }  public override bool CanExitState => false;                  

Attack Country

The AttackState script simply plays the appropriate animations from the EquipState.Weapon:
            using Animancer; using Animancer.Examples.StateMachines.Brains; using UnityEngine;  public sealed class AttackState : CharacterState {     [SerializeField] private EquipState _Equipment;      private int _AttackIndex = int.MaxValue;      individual void OnEnable()     {         Character.Animancer.Animator.applyRootMotion = true;          if (ShouldRestartCombo())         {             _AttackIndex = 0;         }         else         {             _AttackIndex++;         }          var animation = _Equipment.Weapon.AttackAnimations[_AttackIndex];         var state = Character.Animancer.Play(animation);         country.Events.OnEnd = Character.ForceEnterIdleState;     }      individual bool ShouldRestartCombo()     {         var attackAnimations = _Equipment.Weapon.AttackAnimations;          if (_AttackIndex >= attackAnimations.Length - 1)             return true;          var state = attackAnimations[_AttackIndex].Country;         if (land == null ||             state.Weight == 0)             render true;          return false;     }      private void FixedUpdate()     {         Grapheme.Rigidbody.velocity = default;     }      public override bool CanExitState => false;      private void OnDisable()     {         Grapheme.Animancer.Animator.applyRootMotion = fake;     } }                      

It starts with a Serialized reference to the EquipState to be assigned in the Inspector:

          [SerializeField] individual EquipState _Equipment;                  

Normally that reference might go in the Grapheme class, but since that script comes from the Encephalon Transplants example nosotros exercise non want to alter it.

It is quite common for attack animations in games to crusade the character to step forward so the first thing we do when entering this state is enable Root Motion (and disable it when exiting this state):

          private void OnEnable() {     Character.Animancer.Animator.applyRootMotion = true;     ... }  private void OnDisable() {     Grapheme.Animancer.Animator.applyRootMotion = false; }                  

Since each Weapon can have multiple attack animations which they perform in sequence, the next affair we need to practice is determine which blitheness to use. Each time this state is entered nosotros either beginning from the starting time blitheness or movement onto the next ane in the sequence:

          private int _AttackIndex = int.MaxValue;  private void OnEnable() {     ...      if (ShouldRestartCombo())     {         _AttackIndex = 0;     }     else     {         _AttackIndex++;     }      ... }                  

We desire to restart from the first assault if we are already at the terminal animation or if the previous animation has non yet faded out. Otherwise we want to accelerate to the next attack:

          private bool ShouldRestartCombo() {     var attackAnimations = _Equipment.Weapon.AttackAnimations;      if (_AttackIndex >= attackAnimations.Length - ane)         return true;      var state = attackAnimations[_AttackIndex].State;     if (state == null ||         state.Weight == 0)         render true;      return faux; }                  

Once we know which attack nosotros are up to, we tin can simply play its blitheness:

          individual void OnEnable() {     ...      var animation = _Equipment.Weapon.AttackAnimations[_AttackIndex];     var land = Grapheme.Animancer.Play(animation);     land.Events.OnEnd = Grapheme.ForceEnterIdleState; }                  

And but like with the EquipState, nosotros do not want the character to move during this action or to allow other actions to Interrupt it:

          private void FixedUpdate() {     Character.Rigidbody.velocity = default; }  public override bool CanExitState => faux;                  

Root Motility Redirect

Since the graphic symbol model (the object with the Animator component) is separate from the root of the grapheme (the object with the Rigidbody component), nosotros are using a very uncomplicated RootMotionRedirect script to apply the movements from the Animator to the Rigidbody as explained in the Root Motility example:

          using UnityEngine;  public sealed form RootMotionRedirect : MonoBehaviour {     [SerializeField] private Rigidbody _Rigidbody;     [SerializeField] private Animator _Animator;      private void OnAnimatorMove()     {         if (_Animator.applyRootMotion)         {             _Rigidbody.MovePosition(_Rigidbody.position + _Animator.deltaPosition);             _Rigidbody.MoveRotation(_Rigidbody.rotation * _Animator.deltaRotation);         }     } }                  

Scene Setup

This example is based on the Brain Transplants scene then the first affair you should do is create a copy of it (either using Edit/Duplicate (Ctrl + D) or past opening it and using File/Save As... to save a copy somewhere else).

Character

  • If you are using a unlike character model from the DefaultHumanoid included in Animancer, delete the existing model (a kid of the Grapheme object) and drag your own into the same place in the hierarchy.
    • Make sure the new model has its position and rotation reset to zero.
    • Add an AnimancerComponent to it.
    • Select the Grapheme and assign the new model as its Animancer reference.
  • Besides add together a RootMotionRedirect component to the model and assign its references.

  • If y'all are not using the Humanoid-Idle, Humanoid-Walk, and Humanoid-Run animations, assign the ones you want to use in the IdleState on the Character and the LocomotionState on the Brain.
Idle Locomotion

Weapons

Each of the Weapons is a model with a Weapon script attached (except for Unarmed which has no model). They all start inactive (and Unarmed gets equipped on startup because information technology is assigned as the default).

The Unarmed and Great Sword setups are fairly obvious:

Unarmed Great Sword

Unarmed has two attacks and no Equip Animation or Unequip Animation.

Keen Sword has three attacks with both an Equip Animation and an Unequip Animation.

We only have a single animation chosen Draw Sword 2 to use for the Club'due south Equip Blitheness, only we can too use that same animation played backwards (Speed = -1) for the Unequip Blitheness.

Attacks

Each of the other new scripts we made in this instance can exist attached to the Encephalon object:

Buttons

And finally, nosotros can not use some UI Buttons to set the EquipState.Weapon when the player clicks them:

Note that if the Equip State does not actually allow itself to be entered, the displayed text will still exist changed. Nosotros could fix that by having the EquipState set the text rather than doing it in the UI Push button, only that is not really relevant to the purpose of that script and so nosotros have kept it separate for this example.

Concluding Issue

This all combines to create a character that tin do everything from the Brain Transplants example as well as equip different weapons and set on with them.

Source: https://kybernetik.com.au/animancer/docs/examples/fsm/weapons/

Posted by: cornettinglacrievor.blogspot.com

0 Response to "How To Switch Animations For Different Weapons Unity"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel