using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerMovement : MonoBehaviour
{
public Rigidbody2D rb; // Player's Rigidbody2D component
public Animator animator; // Animator for controlling animations
private bool isFacingRight = true; // Tracks which direction the player is facing
[Header("Movement")]
public float moveSpeed = 5f; // Horizontal movement speed
private float horizontalMovement; // Input value for horizontal movement
[Header("Jumping")]
public float jumpPower = 10f; // Force applied when jumping
public int maxJumps = 2; // Maximum allowed jumps (for double jump)
private int jumpsRemaining; // Remaining jumps
[Header("Ground Check")]
public Transform groundCheckPos; // Position to check for ground
public Vector2 groundCheckSize = new Vector2(0.5f, 0.05f); // Size of ground check box
public LayerMask groundLayer; // Ground layer for collision check
private bool isGrounded; // Whether the player is on the ground
[Header("Gravity")]
public float baseGravity = 2f; // Base gravity scale
public float maxFallSpeed = 18f; // Maximum downward fall speed
public float fallSpeedMultiplier = 2f; // Extra gravity applied while falling
[Header("Wall Check")]
public Transform WallCheckPos; // Position to check for wall contact
public Vector2 WallCheckSize = new Vector2(0.5f, 0.05f); // Size of wall check box
public LayerMask WallLayer; // Wall layer for collision check
[Header("Wall Movement")]
public float wallSlideSpeed = 2f; // Downward slide speed when on wall
private bool isWallSliding; // Whether the player is currently sliding on a wall
private bool isWallJumping; // Whether the player is currently wall-jumping
private float walljumpDirection; // Direction away from wall
public float wallJumpTime = 0.5f; // Grace period to trigger wall jump
private float wallJumpTimer; // Timer countdown for wall jump
public Vector2 wallJumpPower = new Vector2(5f, 10f); // Force applied during wall jump
private void Start()
{
isFacingRight = transform.localScale.x > 0; // Set initial facing direction
}
private void Update()
{
GroundCheck(); // Check if player is on ground
ProcessGravity(); // Adjust gravity/fall behavior
ProcessWallSlide(); // Handle wall slide state
ProcessWallJump(); // Handle wall jump timing
if (!isWallJumping)
{
rb.linearVelocity = new Vector2(horizontalMovement * moveSpeed, rb.linearVelocity.y); // Apply horizontal movement
Flip(); // Flip sprite direction based on movement
}
// Update animation parameters
animator.SetFloat("yVelocity", rb.linearVelocity.y);
animator.SetFloat("magnitude", Mathf.Abs(rb.linearVelocity.x));
animator.SetBool("isWallSliding", isWallSliding);
}
///
/// Called when movement input is received
///
public void Move(InputAction.CallbackContext context)
{
horizontalMovement = context.ReadValue().x; // Read horizontal input
}
///
/// Called when jump input is received
///
public void Jump(InputAction.CallbackContext context)
{
if (context.performed)
{
if (wallJumpTimer > 0f)
{
// Perform wall jump
isWallJumping = true;
rb.linearVelocity = new Vector2(walljumpDirection * wallJumpPower.x, wallJumpPower.y);
wallJumpTimer = 0;
animator.SetTrigger("jump");
// Flip character if jumping in opposite direction
if ((walljumpDirection > 0 && !isFacingRight) || (walljumpDirection < 0 && isFacingRight))
{
isFacingRight = !isFacingRight;
Vector3 ls = transform.localScale;
ls.x *= -1f;
transform.localScale = ls;
}
Invoke(nameof(CancelWallJump), wallJumpTime + 0.1f); // End wall jump after delay
}
else if (jumpsRemaining > 0)
{
// Normal jump
rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpPower);
jumpsRemaining--;
animator.SetTrigger("jump");
}
}
// Apply variable jump height when button is released
if (context.canceled && rb.linearVelocity.y > 0)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, rb.linearVelocity.y * 0.5f);
}
}
///
/// Checks if the player is grounded
///
private void GroundCheck()
{
isGrounded = Physics2D.OverlapBox(groundCheckPos.position, groundCheckSize, 0, groundLayer);
if (isGrounded)
{
jumpsRemaining = maxJumps; // Reset jumps when on ground
}
}
///
/// Checks if the player is touching a wall
///
private bool WallCheck()
{
return Physics2D.OverlapBox(WallCheckPos.position, WallCheckSize, 0, WallLayer);
}
///
/// Adjusts gravity for falling or rising states
///
private void ProcessGravity()
{
if (rb.linearVelocity.y < 0)
{
rb.gravityScale = baseGravity * fallSpeedMultiplier;
rb.linearVelocity = new Vector2(rb.linearVelocity.x, Mathf.Max(rb.linearVelocity.y, -maxFallSpeed));
}
else
{
rb.gravityScale = baseGravity;
}
}
///
/// Handles wall slide behavior
///
private void ProcessWallSlide()
{
if (!isGrounded && WallCheck() && horizontalMovement != 0)
{
isWallSliding = true;
rb.linearVelocity = new Vector2(rb.linearVelocity.x, Mathf.Max(rb.linearVelocity.y, -wallSlideSpeed));
}
else
{
isWallSliding = false;
}
}
///
/// Handles timing logic and setup for wall jump
///
private void ProcessWallJump()
{
if (isWallSliding)
{
isWallJumping = false;
walljumpDirection = -Mathf.Sign(transform.localScale.x); // Set direction away from wall
wallJumpTimer = wallJumpTime;
CancelInvoke(nameof(CancelWallJump));
}
else if (wallJumpTimer > 0f)
{
wallJumpTimer -= Time.deltaTime; // Decrease wall jump timer
}
}
///
/// Cancels wall jump state after timeout
///
private void CancelWallJump()
{
isWallJumping = false;
}
///
/// Flips the character sprite based on movement direction
///
private void Flip()
{
if ((isFacingRight && horizontalMovement < 0) || (!isFacingRight && horizontalMovement > 0))
{
isFacingRight = !isFacingRight;
Vector3 ls = transform.localScale;
ls.x *= -1f;
transform.localScale = ls;
}
}
///
/// Draws gizmos in the editor for ground and wall checks
///
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.white;
if (groundCheckPos != null)
Gizmos.DrawWireCube(groundCheckPos.position, groundCheckSize);
Gizmos.color = Color.blue;
if (WallCheckPos != null)
Gizmos.DrawWireCube(WallCheckPos.position, WallCheckSize);
}
}