using UnityEngine;
[RequireComponent (typeof(Controller))]
public class Jump : MonoBehaviour
{
[SerializeField, Range(0f, 10f)] private float jumpHeight = 3f;
[SerializeField, Range(0, 5)] private int maxAirJumps = 0;
[SerializeField, Range(0f, 5f)] private float downwardMovementMultiplier = 3f;
[SerializeField, Range(0f, 5f)] private float upwardMovementMultiplier = 1.7f;
[SerializeField, Range(0f, 0.3f)] private float coyoteTime = 0.2f;
[SerializeField, Range(0f, 0.3f)] private float jumpBufferTime = 0.2f;
private Controller controller;
private Rigidbody2D body;
private Ground ground;
private Vector2 velocity;
private int jumpPhase;
private float defaultGravityScale, jumpSpeed, coyoteCounter, jumpBufferCounter;
private bool desiredJump, onGround, isJumping;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Awake()
{
body = GetComponent<Rigidbody2D>();
ground = GetComponent<Ground>();
controller = GetComponent<Controller>();
defaultGravityScale = 1f;
}
// Update is called once per frame
void Update()
{
desiredJump |= controller.input.RetrieveJumpInput(this.gameObject);
}
private void FixedUpdate()
{
onGround = ground.OnGround;
velocity = body.linearVelocity;
if (onGround && Mathf.Abs(body.linearVelocity.y) <= 0.01f)
{
jumpPhase = 0;
coyoteCounter = coyoteTime;
isJumping = false;
}
else
{
coyoteCounter -= Time.deltaTime;
}
if (desiredJump)
{
desiredJump = false;
jumpBufferCounter = jumpBufferTime;
}
else if(!desiredJump && jumpBufferCounter > 0)
{
jumpBufferCounter -= Time.deltaTime;
}
if(jumpBufferCounter > 0)
{
JumpAction();
}
if(controller.input.RetrieveHoldJumpInput(this.gameObject) && body.linearVelocity.y > 0f)
{
body.gravityScale = upwardMovementMultiplier;
}
else if(!controller.input.RetrieveHoldJumpInput(this.gameObject) || body.linearVelocity.y < 0f)
{
body.gravityScale = downwardMovementMultiplier;
}
else
{
body.gravityScale = defaultGravityScale;
}
body.linearVelocity = velocity;
}
private void JumpAction()
{
if (coyoteCounter > 0f || (jumpPhase < maxAirJumps && isJumping))
{
if (isJumping)
{
jumpPhase += 1;
}
jumpBufferCounter = 0;
coyoteCounter = 0;
jumpSpeed = Mathf.Sqrt(-2f * Physics2D.gravity.y * jumpHeight);
isJumping = true;
if(velocity.y > 0f)
{
jumpSpeed = Mathf.Max(jumpSpeed - velocity.y, 0f);
}
if (onGround)
{
velocity.y += jumpSpeed;
}
else
{
velocity.y = jumpSpeed;
}
}
}
}
I intended to give some leniency in timing the jumps. So added jump buffer but the issue I am facing is when I set maxAirJump to 1 or higher value, perform the maximum jumps allowed and press jump just before landing it jumps, as intended, but if I continue tapping jump it does one less maxAirJump than intended, ie, if I set maxAirJump to 2 it will jump twice in air and just before landing if jump is triggered then in next sequence of jumps it will only do 1 maxAirJump.