Unity 2d Platformer PlayerController
• Has Movement • Has Coyote Time • Has Time Bufferusing System.Collections; using UnityEngine; public class PlayerController : MonoBehaviour { [SerializeField] private Rigidbody2D rb; [Header("Character Movement")] [SerializeField] private float speed = 8f; [SerializeField] private float deceleration = 30f; private float horizontal; [SerializeField] private bool isFacingRight = true; [Header("Jumping")] [SerializeField] private float jumpingPower = 21f; private float holdJumpTime; private bool isJumping; [Header("Jumping Cooldown")] [SerializeField] private float coyoteTime = 0.4f; private float coyoteTimeCounter; [Header("Jump Buffer")] [SerializeField] private float jumpBufferTime = 0.2f; private float jumpBufferCounter; [Header("Ground Check")] [SerializeField] private Transform groundCheck; [SerializeField] private LayerMask groundLayer; [SerializeField] public float groundCheckRadius; private void Awake() { rb = GetComponent<Rigidbody2D>(); if (rb == null) { Debug.LogError("Rigidbody2D component not found on the player!"); } } private void Update() { horizontal = Input.GetAxisRaw("Horizontal"); if (IsGrounded()) { coyoteTimeCounter = coyoteTime; } else { coyoteTimeCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { jumpBufferCounter = jumpBufferTime; } else { jumpBufferCounter -= Time.deltaTime; } if (coyoteTimeCounter > 0f && jumpBufferCounter > 0f && !isJumping) { rb.velocity = new Vector2(rb.velocity.x, jumpingPower); jumpBufferCounter = 0f; StartCoroutine(JumpCooldown()); } if (Input.GetButtonUp("Jump") && rb.velocity.y > 0f) { rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f); coyoteTimeCounter = 0f; } Flip(); } private void FixedUpdate() { float horizontalInput = Input.GetAxisRaw("Horizontal"); float newVelocityX = horizontalInput * speed; // Apply deceleration if no movement input if (horizontalInput == 0 && Mathf.Abs(rb.velocity.x) > 0) { // Calculate the direction of the current velocity float decelerationDirection = Mathf.Sign(rb.velocity.x); // Calculate the new velocity after applying deceleration newVelocityX = rb.velocity.x - deceleration * decelerationDirection * Time.fixedDeltaTime; // Ensure velocity doesn't overshoot zero due to deceleration if (Mathf.Sign(newVelocityX) != decelerationDirection) { newVelocityX = 0f; } } rb.velocity = new Vector2(newVelocityX, rb.velocity.y); } private bool IsGrounded() { return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer); } private void Flip() { if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f) { Vector3 localScale = transform.localScale; isFacingRight = !isFacingRight; localScale.x *= -1f; transform.localScale = localScale; } } private IEnumerator JumpCooldown() { isJumping = true; yield return new WaitForSeconds(0.4f); isJumping = false; } private void OnDrawGizmos() { Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius); } }
Leave a Comment