using UnityEngine; using UnityEngine.InputSystem; public class HeavyBallMovement : MonoBehaviour { [Header("References")] [SerializeField] private PlayerInput _playerInput; [SerializeField] private Rigidbody rb; [SerializeField] private Camera cam; [Space] [Header("Player Parameters")] [SerializeField, Range(-100f, 100f)] private float moveSpeed; [SerializeField, Range(-100f, 100f)] private float airSpeed; [SerializeField, Range(-100f, 100f)] private float airMoveSpeed; [SerializeField, Range(-100f, 100f)] private float accelMaxSpeed; [SerializeField, Range(-100f, 100f)] private float jumpForce; [SerializeField, Range(-100f, 100)] private float doubleJump; [SerializeField, Range(0f, 100f)] public float holdThreshold; [SerializeField, Range(-100f, 100f)] private float reverseMultiplier; [Space] [Header("Grounded Settings")] [SerializeField] private LayerMask groundLayer; [SerializeField, Range(-100f, 100f)] private float radius; [SerializeField, Range(-100f, 100f)] private float maxDistance; [SerializeField, Range(-100f, 100f)] private float groundDamping; [SerializeField, Range(-100f, 100f)] private float airDamping; [SerializeField, Range(-100f, 100f)] private float slopeStickForce; [Space] [Header("Custom Gravity Parameters")] [SerializeField, Range(-100f, 100f)] private float playerGravity; [SerializeField, Range(-100f, 100f)] private float upwardMultiplier; [SerializeField, Range(-100f, 100f)] private float downwardMultiplier; [Space] [Header("Bool Parameters")] [SerializeField] public bool isGrounded; [SerializeField] public bool jumpPressed; [SerializeField] public bool isFullJump; [SerializeField] public bool doubleJumpUsed; [SerializeField] public bool jumpButton; private float jumpHoldTime = 0f; public float finalJump; private bool jumpBuffered; private bool wasGrounded; RaycastHit hit; Vector2 currentInput; Vector3 moveDirection; private void Update() { HandleInput(); jumpButton = _playerInput.jumpAction.action.WasPressedThisFrame(); if (_playerInput.jumpAction.action.WasPressedThisFrame()) { jumpBuffered = true; } } private void FixedUpdate() { HandleMovement(); HandleGroundCheck(); HandleJump(); CustomGravity(); jumpBuffered = false; } private void HandleMovement() { Vector2 input = Vector2.ClampMagnitude(currentInput, 1f); Vector3 camForward = cam.transform.forward; Vector3 camRight = cam.transform.right; camForward.y = 0f; camRight.y = 0f; camForward.Normalize(); camRight.Normalize(); moveDirection = camForward * input.y + camRight * input.x; moveDirection = moveDirection.normalized; if (isGrounded) { moveDirection = Vector3.ProjectOnPlane(moveDirection, hit.normal).normalized; Vector3 gravityAlongSlope = Vector3.ProjectOnPlane(Physics.gravity, hit.normal); rb.AddForce(-gravityAlongSlope, ForceMode.Acceleration); rb.AddForce(-hit.normal * slopeStickForce, ForceMode.Acceleration); } Vector3 flatVel = new Vector3(rb.linearVelocity.x, 0, rb.linearVelocity.z); Vector3 velDir = flatVel.magnitude > 0.01f ? flatVel.normalized : moveDirection; float alignment = Vector3.Dot(velDir, moveDirection); if (alignment < 0f) rb.AddForce(-velDir * moveSpeed * reverseMultiplier, ForceMode.Acceleration); float currentSpeed = isGrounded ? moveSpeed : airSpeed; if (moveDirection != Vector3.zero) rb.AddForce(moveDirection * currentSpeed, ForceMode.Force); } private void HandleJump() { if (_playerInput.jumpAction.action.IsPressed() && isGrounded && !jumpPressed) { jumpHoldTime += Time.deltaTime; } else { if (jumpHoldTime > 0f && isGrounded) { if (jumpHoldTime >= holdThreshold) { finalJump = 1.5f; isFullJump = true; } else { finalJump = 1f; isFullJump = false; } Vector3 v = rb.linearVelocity; v.y = 0f; rb.linearVelocity = v; rb.AddForce(new(0, finalJump * jumpForce, 0), ForceMode.Impulse); jumpHoldTime = 0f; jumpPressed = true; } } if (!isGrounded && isFullJump && !doubleJumpUsed && jumpBuffered) { Vector3 v = rb.linearVelocity; v.y = 0f; rb.linearVelocity = v; rb.AddForce(1f * doubleJump * Vector3.up, ForceMode.Impulse); doubleJumpUsed = true; } } private void CustomGravity() { if (!isGrounded) { if (rb.linearVelocity.y > 0f) { rb.AddForce(Physics.gravity * upwardMultiplier, ForceMode.Acceleration); } else if (rb.linearVelocity.y < 0f) { rb.AddForce(Physics.gravity * downwardMultiplier, ForceMode.Acceleration); } } } private void HandleGroundCheck() { isGrounded = wasGrounded; isGrounded = (Physics.SphereCast(transform.position, radius, Vector3.down, out hit, maxDistance, groundLayer)); if (isGrounded && !wasGrounded) { rb.linearDamping = groundDamping; rb.mass = 2f; jumpPressed = false; finalJump = 0f; isFullJump = false; doubleJumpUsed = false; } else { rb.linearDamping = airDamping; rb.mass = 0.5f; rb.AddForce(moveDirection * airMoveSpeed, ForceMode.Acceleration); } } private void HandleInput() { currentInput = _playerInput.moveAction.action.ReadValue<Vector2>(); } }