Hi! I’m working on a 2D platformer and the script for player’s movement. Player has a lot of movement, like moving left and right, jumping, falling through platform. It also has rolling when pressing S key down - the key for ducking - and a movement key - A or D - at the same time.
However, I’m facing an issue I cannot fix:
- Upon pressing S key down while player is running - so A or D are pressed down - the player start ducking but keeps moving left or right in the ducking position awkwardly. How to make sure that player stop all movement it was previously doing when pressing S key down for ducking? As well as making sure it would stay ducked while continuously pressing S key down?
Here is the script for my player’s movement in case it helps
Please let me know if you have any tips on how to fix this issue.
Many thanks!
public class NewBehaviourScript : MonoBehaviour
{
public float speed = 5f;
public float jumpSpeed = 8f;
public float rollSpeed = 8f; // Speed during roll
public float rollDuration = 0.3f; // Duration of roll effect
private float direction = 0f;
private Rigidbody2D player;
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask groundLayer;
private bool isTouchingGround;
private Animator playerAnimation;
[SerializeField] private Collider2D playerCollider;
// Add variables for ducking and rolling
private bool isDucking = false;
private bool isRolling = false;
private float rollTime = 0.5f; // Timer for roll duration
// Add a variable to check for platform tags
private GameObject currentPlatform;
// Track if the player is dropping through the platform
private bool isDroppingThrough = false;
// Start is called before the first frame update
void Start()
{
player = GetComponent<Rigidbody2D>();
playerAnimation = GetComponent<Animator>();
playerCollider = GetComponent<Collider2D>(); // Get the player's collider
}
// Update is called once per frame
void Update()
{
// Check if the player is on the ground
isTouchingGround = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer);
direction = Input.GetAxis("Horizontal");
// Handle rolling logic
if (isRolling)
{
rollTime += Time.deltaTime;
if (rollTime >= rollDuration)
{
// Stop rolling after the duration
isRolling = false;
playerAnimation.SetBool("Roll", false);
player.velocity = new Vector2(0, player.velocity.y); // Stop movement
playerAnimation.SetFloat("Speed", 0f); // Ensure idle animation
}
else
{
// Move the player in the direction it's facing
player.velocity = new Vector2(rollSpeed * Mathf.Sign(transform.localScale.x), player.velocity.y);
}
}
else
{
// Move the player left or right (only if not ducking or rolling)
if (!isDucking)
{
if (direction > 0f)
{
player.velocity = new Vector2(direction * speed, player.velocity.y);
transform.localScale = new Vector2(3.751758f, 3.751758f);
}
else if (direction < 0f)
{
player.velocity = new Vector2(direction * speed, player.velocity.y);
transform.localScale = new Vector2(-3.751758f, 3.751758f);
}
else
{
player.velocity = new Vector2(0, player.velocity.y);
}
}
else
{
// If ducking, stop horizontal movement
player.velocity = new Vector2(0, player.velocity.y);
}
// Jump logic (allow jumping from ducking)
if (Input.GetButtonDown("Jump") && isTouchingGround)
{
if (isDucking)
{
// Reset ducking state and animation
playerAnimation.SetBool("Duck", false);
isDucking = false;
}
// Set jump velocity
player.velocity = new Vector2(player.velocity.x, jumpSpeed);
playerAnimation.SetTrigger("Jump");
}
}
// Update Animator Parameters
playerAnimation.SetFloat("Speed", Mathf.Abs(player.velocity.x));
playerAnimation.SetBool("OnGround", isTouchingGround);
playerAnimation.SetBool("Duck", isDucking);
playerAnimation.SetBool("Roll", isRolling);
// Ducking and drop through platform logic
if (Input.GetKeyDown(KeyCode.S) && isTouchingGround && !isRolling)
{
playerAnimation.SetBool("Duck", true);
isDucking = true;
// Drop through platform if player is on a platform
if (currentPlatform != null && currentPlatform.CompareTag("Platform") && !isDroppingThrough)
{
StartCoroutine(DropThroughPlatform());
}
}
else if (Input.GetKeyUp(KeyCode.S) && isDucking)
{
playerAnimation.SetBool("Duck", false);
isDucking = false;
}
// Handle Roll Input
if (Input.GetKey(KeyCode.S) && Mathf.Abs(direction) > 0f && isTouchingGround && !isRolling)
{
// Start rolling: set animation and adjust speed
playerAnimation.SetBool("Roll", true);
isRolling = true;
rollTime = 0f; // Reset roll timer
player.velocity = new Vector2(rollSpeed * Mathf.Sign(transform.localScale.x), player.velocity.y);
// Flip the character's sprite depending on the direction of the roll
transform.localScale = new Vector2(direction > 0f ? 3.751758f : -3.751758f, 3.751758f);
}
// Handle fall animation
if (player.velocity.y < -0.1f && !isTouchingGround)
{
playerAnimation.SetTrigger("Fall");
}
else if (isTouchingGround)
{
playerAnimation.ResetTrigger("Fall");
playerAnimation.SetBool("Jump", false); // Reset jump after landing
}
}
// Detect if the player is on a platform by using tags
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Platform"))
{
currentPlatform = collision.gameObject;
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Platform"))
{
currentPlatform = null;
}
}
// Coroutine to drop through platform by temporarily disabling collision between player and platform
private IEnumerator DropThroughPlatform()
{
Collider2D platformCollider = currentPlatform.GetComponent<CompositeCollider2D>();
Physics2D.IgnoreCollision(playerCollider, platformCollider, true); // Disable collision with the platform
yield return new WaitForSeconds(1f); // Adjust the delay as necessary
Physics2D.IgnoreCollision(playerCollider, platformCollider, false); // Re-enable collision
}
}