How to structure different types of 2D jump logic?
Good morning!
In early development of a 2D platformer I've met a few complications which I'm afraid only will get worse by time. I successfully implemented a jump mechanic where he jumps higher by holding the jump button in comparison to a simple tap.
Throughout the game the character should be able to get new abilities to both double jump and hover in the air for a short time.
New jump abilities might be implemented in the future.
. 
Currently I got these relevant scripts on my player:
 - PlayerCollisionCheck (ground check, etc)
 - PlayerInput (handles all input and forwards it to the relevant script, I'd like to keep all of my user input code here)
 - PlayerMovement (handles left and right movements)
 - PlayerJump (jump logic)
. 
I see the reason of my difficulty is my lack of knowledge of how to properly structure the different jump logic. The script is currently full of states and checks (even redundant ones) to restrict the player from unwanted movement, yet allowing flexibility.
.
I'm starting to lose track of the logic and I'd like to know how to structure it in an orderly matter.
Thanks in advance!
Here's my current code for the PlayerJump script:
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 
 [RequireComponent(typeof(Rigidbody2D))]
 public class PlayerJump : MonoBehaviour
 {
     // Jump states
     enum JumpState { jumpReady, jumping, jumpDone, hover }
     JumpState jumpState;
 
     // Jump abilities
     enum JumpAbility { none, doubleJump, hover }
     [SerializeField]
     JumpAbility jumpAbility = JumpAbility.none;
 
     // Jump
     [SerializeField]
     float jumpForce;
     [SerializeField]
     float jumpTimeMax;
     [SerializeField]
     float jumpTimeMin;
     float jumpTimeCounter;
 
     // Double Jump
     bool hasDoubleJump = false;
 
     // Hover
     [SerializeField]
     float hoverForce = 0.3f;
     [SerializeField]
     float hoverTime = 1f;
 
     // Input
     bool jumpButtonDown = false;
     bool jumpButtonUp = false;
 
     // Components
     Rigidbody2D rgbd2d;
 
     // Scripts
     PlayerCollisionCheck playerCollisionCheck;
 
 
     // Awake
     void Awake()
     {
         rgbd2d = GetComponent<Rigidbody2D>();
         playerCollisionCheck = GetComponent<PlayerCollisionCheck>();
     }
 
 
     // Start
     void Start()
     {
         jumpTimeCounter = jumpTimeMax;
         jumpState = JumpState.jumpReady;
     }
 
 
     // Update
     void FixedUpdate()
     {
         // Check if the player is grounded
         if (playerCollisionCheck.GroundCheck())
         {
             jumpState = JumpState.jumpReady;
             hasDoubleJump = false;
         }
 
 
         // if jump button is pressed and the player is grounded
         if (jumpButtonDown && jumpState == JumpState.jumpReady)
         {
             // Double Jump
             if (hasDoubleJump)
                 jumpTimeCounter = jumpTimeMin;
             // Normal Jump
             else
                 jumpTimeCounter = jumpTimeMax;
 
             // Jump
             rgbd2d.velocity = Vector2.up * jumpForce;
             jumpButtonDown = false;
             jumpState = JumpState.jumping;
         }
 
         // if jump button is held down and the timer hasn't run out yet OR minimum jump height has not yet been achieved
         if (!jumpButtonUp && (jumpState == JumpState.jumping || jumpState == JumpState.jumpDone) && jumpTimeCounter > 0)
         {
             // Keep jumping
             rgbd2d.velocity = Vector2.up * jumpForce;
             jumpTimeCounter -= Time.deltaTime;
         }
         // if jump button is held down AND the timer has run out AND the player has the ability to hover
         else if (!jumpButtonUp && jumpState == JumpState.hover && jumpTimeCounter > 0)
         {
             // Hover
             float yVelocity = 0f;
             float newVelocity = Mathf.SmoothDamp(rgbd2d.velocity.y, hoverForce, ref yVelocity, 1);
             rgbd2d.velocity = Vector2.up * Mathf.Clamp(newVelocity, 1, int.MaxValue);
             jumpTimeCounter -= Time.deltaTime;
         }
 
         // if jump has finished AND button is still pressed AND the player has the ability to hover
         if (jumpTimeCounter < 0 && !jumpButtonUp && jumpAbility == JumpAbility.hover && jumpState == JumpState.jumping)
         {
             // Initiate Hover
             jumpState = JumpState.hover;
             jumpTimeCounter = hoverTime;
         }
 
         // if jump button is released
         if (jumpButtonUp)
         {
             // If stopping hover
             if (jumpAbility == JumpAbility.hover && jumpState == JumpState.hover)
             {
                 jumpTimeCounter = 0;
                 jumpButtonUp = false;
                 jumpState = JumpState.jumpDone;
             }
             // If minimum jump has been achieved
             else if (jumpTimeMax - jumpTimeCounter > jumpTimeMin)
             {
                 jumpTimeCounter = 0;
                 jumpButtonUp = false;
                 jumpState = JumpState.jumpDone;
             }
             // If minimum jump has not been achieved
             else
             {
                 jumpTimeCounter = jumpTimeMin - (jumpTimeMax - jumpTimeCounter);
                 jumpButtonUp = false;
                 jumpState = JumpState.jumpDone;
             }
         }
     }
 
 
     // When jump button is pressed
     public void OnJumpInputDown()
     {
         // If the player is ready to jump
         if (jumpState == JumpState.jumpReady && !hasDoubleJump)
         {
             jumpButtonDown = true;
         }
 
         // If the player CAN and is ready to double jump
         else if (jumpAbility == JumpAbility.doubleJump && !hasDoubleJump && (jumpState == JumpState.jumpDone || jumpState == JumpState.jumping))
         {
             jumpButtonDown = true;
             jumpState = JumpState.jumpReady;
             hasDoubleJump = true;
         }
 
         // If the player CAN and is ready to hover
         else if (jumpAbility == JumpAbility.hover && jumpState != JumpState.hover && (jumpState == JumpState.jumpDone || jumpState == JumpState.jumping))
         {
             jumpState = JumpState.hover;
             jumpTimeCounter = hoverTime;
             jumpButtonDown = false;
         }
     }
 
     // When jump button is released
     public void OnJumpInputUp()
     {
         // If the player is jumping
         if (jumpState == JumpState.jumping || jumpState == JumpState.hover)
         {
             jumpButtonUp = true;
         }
     }
 }
 
              Answer by SmackDan · Feb 16, 2018 at 08:23 PM
I generally don't like bumping threads, I'll give it a one time go to see if some new eyes has an answer to point me in the right direction. :)
Your answer