Search Unity

Bug Fall animation triggering when I'm on the floor even though I'm not

Discussion in 'Animation' started by n7pankake, Mar 7, 2023.

  1. n7pankake

    n7pankake

    Joined:
    Nov 18, 2017
    Posts:
    19
    So for some reason in some "terrains" the animation of falling suddenly decides to run for some reason and it says my VERTICAL movement is negative (which is the reason why is running) but that does not make any sense since I'm running on Horizontal (Just spamming A and D going back and forth).

    The condition is simple Any state can go to FALL when vertical is LESS than 0 (Falling basically) so that way doesn't matter what if I'm falling it should show that animation. Let me know if you require something else here is my code is a bit extensive. I have been slowly adapting my animations to the code there's a lot of things to animate yet right now I have finish so far Running, Swap directions, Idle, Jumping and Landing. But I noticed that if I stay running and fall it didn't swap to FALL so I did that ANY State. I should prob do a RUN to Fall and Idle to Fall but I was having too many issues with the animations and stuff.

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using UnityEngine;
    4.  
    5. public class PlayerController : MonoBehaviour
    6. {
    7.     //Scriptable object which holds all the player's movement parameters. If you don't want to use it
    8.     //just paste in all the parameters, though you will need to manuly change all references in this script
    9.  
    10.     //HOW TO: to add the scriptable object, right-click in the project window -> create -> Player Data
    11.     //Next, drag it into the slot in playerMovement on your player
    12.  
    13.     public ControllerData Data;
    14.  
    15.     #region Variables
    16.     //Components
    17.     public Rigidbody2D rb2D { get; private set; }
    18.     public Animator anim { get; private set; }
    19.  
    20.     //Variables control the various actions the player can perform at any time.
    21.     //These are fields which can are public allowing for other sctipts to read them
    22.     //but can only be privately written to.
    23.     public bool IsFacingRight { get; private set; }
    24.     public bool IsGrounded { get; private set; }
    25.     public bool IsJumping { get; private set; }
    26.     public bool IsWallJumping { get; private set; }
    27.     public bool IsSliding { get; private set; }
    28.  
    29.     //Timers (also all fields, could be private and a method returning a bool could be used)
    30.     public float LastOnGroundTime { get; private set; }
    31.     public float LastOnWallTime { get; private set; }
    32.     public float LastOnWallRightTime { get; private set; }
    33.     public float LastOnWallLeftTime { get; private set; }
    34.  
    35.     //Jump
    36.     private bool _isJumpCut;
    37.     private bool _isJumpFalling;
    38.  
    39.     [Header("Bounce")]
    40.     [SerializeField] private float bounceSpeed;
    41.  
    42.     //Wall Jump
    43.     private float _wallJumpStartTime;
    44.     private int _lastWallJumpDir;
    45.  
    46.     private Vector2 _moveInput;
    47.     public float LastPressedJumpTime { get; private set; }
    48.  
    49.     //Set all of these up in the inspector
    50.     [Header("Checks")]
    51.     [SerializeField] private Transform _groundCheckPoint;
    52.     //Size of groundCheck depends on the size of your character generally you want them slightly small than width (for ground) and height (for the wall check)
    53.     [SerializeField] private Vector2 _groundCheckSize = new Vector2(0.49f, 0.03f);
    54.     [Space(5)]
    55.     [SerializeField] private Transform _frontWallCheckPoint;
    56.     [SerializeField] private Transform _backWallCheckPoint;
    57.     [SerializeField] private Vector2 _wallCheckSize = new Vector2(0.5f, 1f);
    58.  
    59.     [Header("Layers & Tags")]
    60.     [SerializeField] private LayerMask _groundLayer;
    61.     #endregion
    62.  
    63.     private void Awake()
    64.     {
    65.         rb2D = GetComponent<Rigidbody2D>();
    66.         anim = GetComponentInChildren<Animator>();
    67.     }
    68.  
    69.     private void Start()
    70.     {
    71.         SetGravityScale(Data.gravityScale);
    72.         IsFacingRight = true;
    73.     }
    74.  
    75.     private void Update()
    76.     {
    77.         #region TIMERS
    78.         LastOnGroundTime -= Time.deltaTime;
    79.         LastOnWallTime -= Time.deltaTime;
    80.         LastOnWallRightTime -= Time.deltaTime;
    81.         LastOnWallLeftTime -= Time.deltaTime;
    82.  
    83.         LastPressedJumpTime -= Time.deltaTime;
    84.         #endregion
    85.  
    86.         #region INPUT HANDLER
    87.         _moveInput.x = Input.GetAxisRaw("Horizontal");
    88.         anim.SetFloat("Horizontal", Mathf.Abs(_moveInput.x));
    89.         _moveInput.y = Input.GetAxisRaw("Vertical");
    90.         anim.SetFloat("Vertical", rb2D.velocity.y);
    91.  
    92.         if (_moveInput.x != 0)
    93.             CheckDirectionToFace(_moveInput.x > 0);
    94.  
    95.         if (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.C) || Input.GetKeyDown(KeyCode.J))
    96.         {
    97.             OnJumpInput();
    98.         }
    99.  
    100.         if (Input.GetKeyUp(KeyCode.Space) || Input.GetKeyUp(KeyCode.C) || Input.GetKeyUp(KeyCode.J))
    101.         {
    102.             OnJumpUpInput();
    103.         }
    104.         #endregion
    105.  
    106.         #region COLLISION CHECKS
    107.         if (!IsJumping)
    108.         {
    109.             //Ground Check
    110.             if (Physics2D.OverlapBox(_groundCheckPoint.position, _groundCheckSize, 0, _groundLayer) && !IsJumping) //checks if set box overlaps with ground
    111.             {
    112.                 IsGrounded = true;
    113.                 anim.SetBool("isGrounded", IsGrounded);
    114.                 LastOnGroundTime = Data.coyoteTime; //if so sets the lastGrounded to coyoteTime
    115.             }
    116.  
    117.             //Right Wall Check
    118.             if (((Physics2D.OverlapBox(_frontWallCheckPoint.position, _wallCheckSize, 0, _groundLayer) && IsFacingRight)
    119.                     || (Physics2D.OverlapBox(_backWallCheckPoint.position, _wallCheckSize, 0, _groundLayer) && !IsFacingRight)) && !IsWallJumping)
    120.                 LastOnWallRightTime = Data.coyoteTime;
    121.  
    122.             //Right Wall Check
    123.             if (((Physics2D.OverlapBox(_frontWallCheckPoint.position, _wallCheckSize, 0, _groundLayer) && !IsFacingRight)
    124.                 || (Physics2D.OverlapBox(_backWallCheckPoint.position, _wallCheckSize, 0, _groundLayer) && IsFacingRight)) && !IsWallJumping)
    125.                 LastOnWallLeftTime = Data.coyoteTime;
    126.  
    127.             //Two checks needed for both left and right walls since whenever the play turns the wall checkPoints swap sides
    128.             LastOnWallTime = Mathf.Max(LastOnWallLeftTime, LastOnWallRightTime);
    129.         }
    130.         #endregion
    131.  
    132.         #region JUMP CHECKS
    133.         if (IsJumping && rb2D.velocity.y < 0)
    134.         {
    135.             IsJumping = false;
    136.  
    137.             if (!IsWallJumping)
    138.                 _isJumpFalling = true;
    139.             IsGrounded = false;
    140.             anim.SetBool("isGrounded", IsGrounded);
    141.         }
    142.  
    143.         if (IsWallJumping && Time.time - _wallJumpStartTime > Data.wallJumpTime)
    144.         {
    145.             IsWallJumping = false;
    146.         }
    147.  
    148.         if (LastOnGroundTime > 0 && !IsJumping && !IsWallJumping)
    149.         {
    150.             _isJumpCut = false;
    151.  
    152.             if (!IsJumping)
    153.                 _isJumpFalling = false;
    154.         }
    155.  
    156.         //Jump
    157.         if (CanJump() && LastPressedJumpTime > 0)
    158.         {
    159.             IsJumping = true;
    160.             anim.SetTrigger("Jump");
    161.             IsGrounded = false;
    162.             anim.SetBool("isGrounded", IsGrounded);
    163.             IsWallJumping = false;
    164.             _isJumpCut = false;
    165.             _isJumpFalling = false;
    166.             Jump();
    167.         }
    168.         //WALL JUMP
    169.         else if (CanWallJump() && LastPressedJumpTime > 0)
    170.         {
    171.             IsWallJumping = true;
    172.             IsJumping = false;
    173.             _isJumpCut = false;
    174.             _isJumpFalling = false;
    175.             _wallJumpStartTime = Time.time;
    176.             _lastWallJumpDir = (LastOnWallRightTime > 0) ? -1 : 1;
    177.  
    178.             WallJump(_lastWallJumpDir);
    179.         }
    180.         #endregion
    181.  
    182.         #region SLIDE CHECKS
    183.         if (CanSlide() && ((LastOnWallLeftTime > 0 && _moveInput.x < 0) || (LastOnWallRightTime > 0 && _moveInput.x > 0)))
    184.             IsSliding = true;
    185.         else
    186.             IsSliding = false;
    187.         #endregion
    188.  
    189.         #region GRAVITY
    190.         //Higher gravity if we've released the jump input or are falling
    191.         if (IsSliding)
    192.         {
    193.             SetGravityScale(0);
    194.         }
    195.         else if (rb2D.velocity.y < 0 && _moveInput.y < 0)
    196.         {
    197.             //Much higher gravity if holding down
    198.             SetGravityScale(Data.gravityScale * Data.fastFallGravityMult);
    199.             //Caps maximum fall speed, so when falling over large distances we don't accelerate to insanely high speeds
    200.             rb2D.velocity = new Vector2(rb2D.velocity.x, Mathf.Max(rb2D.velocity.y, -Data.maxFastFallSpeed));
    201.         }
    202.         else if (_isJumpCut)
    203.         {
    204.             //Higher gravity if jump button released
    205.             SetGravityScale(Data.gravityScale * Data.jumpCutGravityMult);
    206.             rb2D.velocity = new Vector2(rb2D.velocity.x, Mathf.Max(rb2D.velocity.y, -Data.maxFallSpeed));
    207.         }
    208.         else if ((IsJumping || IsWallJumping || _isJumpFalling) && Mathf.Abs(rb2D.velocity.y) < Data.jumpHangTimeThreshold)
    209.         {
    210.             SetGravityScale(Data.gravityScale * Data.jumpHangGravityMult);
    211.         }
    212.         else if (rb2D.velocity.y < 0)
    213.         {
    214.             IsGrounded = false;
    215.             anim.SetBool("isGrounded", IsGrounded);
    216.             //Higher gravity if falling
    217.             SetGravityScale(Data.gravityScale * Data.fallGravityMult);
    218.             //Caps maximum fall speed, so when falling over large distances we don't accelerate to insanely high speeds
    219.             rb2D.velocity = new Vector2(rb2D.velocity.x, Mathf.Max(rb2D.velocity.y, -Data.maxFallSpeed));
    220.         }
    221.         else
    222.         {
    223.             //Default gravity if standing on a platform or moving upwards
    224.             SetGravityScale(Data.gravityScale);
    225.         }
    226.         #endregion
    227.     }
    228.  
    229.     private void FixedUpdate()
    230.     {
    231.         //Handle Run
    232.         if (IsWallJumping)
    233.             Run(Data.wallJumpRunLerp);
    234.         else
    235.             Run(1);
    236.  
    237.         //Handle Slide
    238.         if (IsSliding)
    239.             Slide();
    240.     }
    241.  
    242.     #region INPUT CALLBACKS
    243.     //Methods which whandle input detected in Update()
    244.     public void OnJumpInput()
    245.     {
    246.         LastPressedJumpTime = Data.jumpInputBufferTime;
    247.     }
    248.  
    249.     public void OnJumpUpInput()
    250.     {
    251.         if (CanJumpCut() || CanWallJumpCut())
    252.             _isJumpCut = true;
    253.     }
    254.     #endregion
    255.  
    256.     #region GENERAL METHODS
    257.     public void SetGravityScale(float scale)
    258.     {
    259.         rb2D.gravityScale = scale;
    260.     }
    261.     #endregion
    262.  
    263.     //MOVEMENT METHODS
    264.     #region RUN METHODS
    265.     private void Run(float lerpAmount)
    266.     {
    267.         //Calculate the direction we want to move in and our desired velocity
    268.         float targetSpeed = _moveInput.x * Data.runMaxSpeed;
    269.         //We can reduce are control using Lerp() this smooths changes to are direction and speed
    270.         targetSpeed = Mathf.Lerp(rb2D.velocity.x, targetSpeed, lerpAmount);
    271.  
    272.         #region Calculate AccelRate
    273.         float accelRate;
    274.  
    275.         //Gets an acceleration value based on if we are accelerating (includes turning)
    276.         //or trying to decelerate (stop). As well as applying a multiplier if we're air borne.
    277.         if (LastOnGroundTime > 0)
    278.             accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? Data.runAccelAmount : Data.runDeccelAmount;
    279.         else
    280.             accelRate = (Mathf.Abs(targetSpeed) > 0.01f) ? Data.runAccelAmount * Data.accelInAir : Data.runDeccelAmount * Data.deccelInAir;
    281.         #endregion
    282.  
    283.         #region Add Bonus Jump Apex Acceleration
    284.         //Increase are acceleration and maxSpeed when at the apex of their jump, makes the jump feel a bit more bouncy, responsive and natural
    285.         if ((IsJumping || IsWallJumping || _isJumpFalling) && Mathf.Abs(rb2D.velocity.y) < Data.jumpHangTimeThreshold)
    286.         {
    287.             accelRate *= Data.jumpHangAccelerationMult;
    288.             targetSpeed *= Data.jumpHangMaxSpeedMult;
    289.         }
    290.         #endregion
    291.  
    292.         #region Conserve Momentum
    293.         //We won't slow the player down if they are moving in their desired direction but at a greater speed than their maxSpeed
    294.         if (Data.doConserveMomentum && Mathf.Abs(rb2D.velocity.x) > Mathf.Abs(targetSpeed) && Mathf.Sign(rb2D.velocity.x) == Mathf.Sign(targetSpeed) && Mathf.Abs(targetSpeed) > 0.01f && LastOnGroundTime < 0)
    295.         {
    296.             //Prevent any deceleration from happening, or in other words conserve are current momentum
    297.             //You could experiment with allowing for the player to slightly increae their speed whilst in this "state"
    298.             accelRate = 0;
    299.         }
    300.         #endregion
    301.  
    302.         //Calculate difference between current velocity and desired velocity
    303.         float speedDif = targetSpeed - rb2D.velocity.x;
    304.         //Calculate force along x-axis to apply to thr player
    305.  
    306.         float movement = speedDif * accelRate;
    307.  
    308.         //Convert this to a vector and apply to rigidbody
    309.         rb2D.AddForce(movement * Vector2.right, ForceMode2D.Force);
    310.  
    311.         /*
    312.          * For those interested here is what AddForce() will do
    313.          * RB.velocity = new Vector2(RB.velocity.x + (Time.fixedDeltaTime  * speedDif * accelRate) / RB.mass, RB.velocity.y);
    314.          * Time.fixedDeltaTime is by default in Unity 0.02 seconds equal to 50 FixedUpdate() calls per second
    315.         */
    316.     }
    317.  
    318.     private void Turn()
    319.     {
    320.         //stores scale and flips the player along the x axis,
    321.         Vector3 scale = transform.localScale;
    322.         scale.x *= -1;
    323.         transform.localScale = scale;
    324.  
    325.         IsFacingRight = !IsFacingRight;
    326.     }
    327.     #endregion
    328.  
    329.     #region JUMP METHODS
    330.     private void Jump()
    331.     {
    332.         //Ensures we can't call Jump multiple times from one press
    333.         LastPressedJumpTime = 0;
    334.         LastOnGroundTime = 0;
    335.  
    336.         #region Perform Jump
    337.         //We increase the force applied if we are falling
    338.         //This means we'll always feel like we jump the same amount
    339.         //(setting the player's Y velocity to 0 beforehand will likely work the same, but I find this more elegant :D)
    340.         float force = Data.jumpForce;
    341.         if (rb2D.velocity.y < 0)
    342.             force -= rb2D.velocity.y;
    343.  
    344.         rb2D.AddForce(Vector2.up * force, ForceMode2D.Impulse);
    345.         #endregion
    346.     }
    347.  
    348.     private void WallJump(int dir)
    349.     {
    350.         //Ensures we can't call Wall Jump multiple times from one press
    351.         LastPressedJumpTime = 0;
    352.         LastOnGroundTime = 0;
    353.         LastOnWallRightTime = 0;
    354.         LastOnWallLeftTime = 0;
    355.  
    356.         #region Perform Wall Jump
    357.         Vector2 force = new Vector2(Data.wallJumpForce.x, Data.wallJumpForce.y);
    358.         force.x *= dir; //apply force in opposite direction of wall
    359.  
    360.         if (Mathf.Sign(rb2D.velocity.x) != Mathf.Sign(force.x))
    361.             force.x -= rb2D.velocity.x;
    362.  
    363.         if (rb2D.velocity.y < 0) //checks whether player is falling, if so we subtract the velocity.y (counteracting force of gravity). This ensures the player always reaches our desired jump force or greater
    364.             force.y -= rb2D.velocity.y;
    365.  
    366.         //Unlike in the run we want to use the Impulse mode.
    367.         //The default mode will apply are force instantly ignoring masss
    368.         rb2D.AddForce(force, ForceMode2D.Impulse);
    369.         #endregion
    370.     }
    371.     #endregion
    372.  
    373.     #region OTHER MOVEMENT METHODS
    374.     private void Slide()
    375.     {
    376.         //Works the same as the Run but only in the y-axis
    377.         //THis seems to work fine, buit maybe you'll find a better way to implement a slide into this system
    378.         float speedDif = Data.slideSpeed - rb2D.velocity.y;
    379.         float movement = speedDif * Data.slideAccel;
    380.         //So, we clamp the movement here to prevent any over corrections (these aren't noticeable in the Run)
    381.         //The force applied can't be greater than the (negative) speedDifference * by how many times a second FixedUpdate() is called. For more info research how force are applied to rigidbodies.
    382.         movement = Mathf.Clamp(movement, -Mathf.Abs(speedDif) * (1 / Time.fixedDeltaTime), Mathf.Abs(speedDif) * (1 / Time.fixedDeltaTime));
    383.  
    384.         rb2D.AddForce(movement * Vector2.up);
    385.     }
    386.     #endregion
    387.  
    388.     public void Bounce()
    389.     {
    390.         rb2D.velocity = new Vector2(rb2D.velocity.x, bounceSpeed);
    391.  
    392.         float force = Data.jumpForce;
    393.         if (rb2D.velocity.y < 0)
    394.             force -= rb2D.velocity.y;
    395.  
    396.         rb2D.AddForce((Vector2.up * force), ForceMode2D.Impulse);
    397.     }
    398.  
    399.  
    400.     #region CHECK METHODS
    401.     public void CheckDirectionToFace(bool isMovingRight)
    402.     {
    403.         if (isMovingRight != IsFacingRight)
    404.             Turn();
    405.     }
    406.  
    407.     private bool CanJump()
    408.     {
    409.         return LastOnGroundTime > 0 && !IsJumping;
    410.     }
    411.  
    412.     private bool CanWallJump()
    413.     {
    414.         return LastPressedJumpTime > 0 && LastOnWallTime > 0 && LastOnGroundTime <= 0 && (!IsWallJumping ||
    415.              (LastOnWallRightTime > 0 && _lastWallJumpDir == 1) || (LastOnWallLeftTime > 0 && _lastWallJumpDir == -1));
    416.     }
    417.  
    418.     private bool CanJumpCut()
    419.     {
    420.         return IsJumping && rb2D.velocity.y > 0;
    421.     }
    422.  
    423.     private bool CanWallJumpCut()
    424.     {
    425.         return IsWallJumping && rb2D.velocity.y > 0;
    426.     }
    427.  
    428.     public bool CanSlide()
    429.     {
    430.         if (LastOnWallTime > 0 && !IsJumping && !IsWallJumping && LastOnGroundTime <= 0)
    431.             return true;
    432.         else
    433.             return false;
    434.     }
    435.     #endregion
    436.  
    437.  
    438.     #region EDITOR METHODS
    439.     private void OnDrawGizmosSelected()
    440.     {
    441.         Gizmos.color = Color.yellow;
    442.         Gizmos.DrawWireCube(_groundCheckPoint.position, _groundCheckSize);
    443.         Gizmos.color = Color.red;
    444.         Gizmos.DrawWireCube(_frontWallCheckPoint.position, _wallCheckSize);
    445.         Gizmos.DrawWireCube(_backWallCheckPoint.position, _wallCheckSize);
    446.     }
    447.     #endregion
    448. }
    449.  

    upload_2023-3-7_10-53-35.png