Why is my character floating in the air instead of standing on the ground in Unity?
I’m working on a Unity project and have implemented a character with a Rigidbody and Collider for physics interactions. However, I noticed that my character is floating or hanging in the air instead of standing properly on the ground.
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerController : MonoBehaviour
{
public float walkSpeed = 5f; // Walking speed
public float runSpeedMultiplier = 1.5f; // Running speed multiplier
public float jumpImpulse = 10f; // Jump force
private Vector2 moveInput; // Movement input
private Rigidbody2D rb; // Rigidbody2D component
private Animator animator; // Animator component
private SpriteRenderer spriteRenderer; // SpriteRenderer component
public LayerMask groundLayer; // Ground detection layer
private bool isGrounded = false; // Is the player grounded?
public float CurrentMoveSpeed => IsRunning ? walkSpeed * runSpeedMultiplier : walkSpeed; // Current movement speed
private bool IsRunning => Keyboard.current != null && Keyboard.current.shiftKey.isPressed; // Check if Shift is pressed
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
private void Update()
{
CheckGrounded(); // Update grounded state
UpdateAnimations(); // Update animations
UpdateSpriteDirection(); // Update sprite direction based on movement
}
private void FixedUpdate()
{
ApplyMovement(); // Apply movement based on input
}
public void OnMove(InputAction.CallbackContext context)
{
// Read movement input
if (context.performed || context.started)
{
moveInput = context.ReadValue<Vector2>();
}
else if (context.canceled)
{
moveInput = Vector2.zero;
}
}
public void OnJump(InputAction.CallbackContext context)
{
// Jump if grounded
if (context.started && isGrounded)
{
rb.velocity = new Vector2(rb.velocity.x, jumpImpulse); // Apply jump force
animator.SetTrigger("jump"); // Trigger jump animation
}
}
private void CheckGrounded()
{
// Ground detection using OverlapCircle
Vector2 groundCheckPosition = new Vector2(transform.position.x, transform.position.y - 0.5f);
float checkRadius = 0.2f; // Slightly larger radius for consistent detection
Collider2D groundCheck = Physics2D.OverlapCircle(groundCheckPosition, checkRadius, groundLayer);
isGrounded = groundCheck != null;
// Debug visualization
Debug.DrawRay(groundCheckPosition, Vector2.down * 0.1f, isGrounded ? Color.green : Color.red);
// Reset falling/jumping states when grounded
if (isGrounded)
{
animator.SetBool("isFalling", false);
animator.SetBool("isJumping", false);
}
}
private void ApplyMovement()
{
// Apply movement with current speed
Vector2 targetVelocity = new Vector2(moveInput.x * CurrentMoveSpeed, rb.velocity.y);
rb.velocity = targetVelocity;
}
private void UpdateAnimations()
{
// Handle jump and fall animations
if (!isGrounded)
{
animator.SetFloat("yVelocity", rb.velocity.y); // Track y velocity for transitions
animator.SetBool("isFalling", rb.velocity.y < -0.1f); // Falling if downward velocity
animator.SetBool("isJumping", rb.velocity.y > 0.1f); // Jumping if upward velocity
}
else
{
animator.SetBool("isFalling", false);
animator.SetBool("isJumping", false);
}
// Handle running and movement animations
animator.SetBool("isMoving", Mathf.Abs(moveInput.x) > 0.1f); // Ignore very small movements
animator.SetBool("isRunning", IsRunning);
}
private void UpdateSpriteDirection()
{
// Flip sprite based on movement direction
if (moveInput.x != 0)
{
spriteRenderer.flipX = moveInput.x < 0;
}
}
private void OnDrawGizmos()
{
// Visualize the ground detection radius in the scene view
Gizmos.color = isGrounded ? Color.green : Color.red;
Gizmos.DrawWireSphere(new Vector2(transform.position.x, transform.position.y - 0.5f), 0.2f);
}
}