Forum begins after the advertisement:


[Part 3] The Player Character Attacks Twice with one mouse click

Home Forums Video Game Tutorial Series Creating a Metroidvania in Unity [Part 3] The Player Character Attacks Twice with one mouse click

Viewing 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • #15701
    Adhiraj Patil
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hello guys, for past few Days I’ve been watching the metroidvania game tutorial and I am trying to replicate exact same steps as shown in the video. Now I have reached the part where I have added attack animation. When I press Mouse 1 for attack the attack animation plays but the Player plays the attack animation twice on one click. I have no Idea why this happens, could it be because of the Time.deltaTime we used.

    I am attaching my code and Video link in the discription

    View post on imgur.com
    <code>
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerController : MonoBehaviour
    {
        [Header("Horizontal Movement Settings:")]
        [SerializeField] private float walkSpeed = 1;
        [Space(5)]
    
        [Header("Vertical Movement Settings")]
        [SerializeField] private float jumpForce = 45f;
        private float jumpBufferCounter = 0;
        [SerializeField] private float jumpBufferFrames;
        private float coyoteTimeCounter = 0;
        [SerializeField] private float coyoteTime;
        private int airJumpCounter = 0;
        [SerializeField] private int maxAirJumps;
        [Space(5)]
    
        [Header("Ground Check Settings:")]
        [SerializeField] private Transform groundCheckPoint;
        [SerializeField] private float groundCheckY = 0.2f;
        [SerializeField] private float groundCheckX = 0.5f;
        [SerializeField] private LayerMask whatIsGround;
        [Space(5)]
    
        [Header("Dash Settings")]
        [SerializeField] private float dashSpeed;
        [SerializeField] private float dashTime;
        [SerializeField] private float dashCooldown;
        [SerializeField] GameObject dashEffect;
        [Space(5)]
    
        [Header("Dash Settings")]
        bool attack = false;
        float timeBetweenAttack, timeSinceAttack;
    
        PlayerStateList pState;
        private Rigidbody2D rb;
        private float xAxis;
        private float gravity;
        Animator anim;
        private bool canDash = true;
        private bool dashed;
    
    
    
        //creates a singleton of the PlayerController
        public static PlayerController instance;
    
        private void Awake()
        {
            if (instance != null && instance != this)
            {
                Destroy(gameObject);
            }
            else
            {
                instance = this;
            }
        }
    
        // Start is called before the first frame update
        void Start()
        {
            pState = GetComponent<PlayerStateList>();
    
            rb = GetComponent<Rigidbody2D>();
    
            anim = GetComponent<Animator>();
    
            gravity = rb.gravityScale;
        }
    
        // Update is called once per frame
        void Update()
        {
            GetInputs();
            UpdateJumpVariables();
    
            if (pState.dashing) return;
            Flip();
            Move();
            Jump();
            StartDash();
            Attack();
        }
    
        void GetInputs()
        {
            xAxis = Input.GetAxisRaw("Horizontal");
            attack = Input.GetMouseButton(0);
        }
    
        void Flip()
        {
            if (xAxis < 0)
            {
                transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y);
            }
            else if (xAxis > 0)
            {
                transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y);
            }
        }
    
        private void Move()
        {
            rb.velocity = new Vector2(walkSpeed * xAxis, rb.velocity.y);
            anim.SetBool("walking", rb.velocity.x != 0 && Grounded());
        }
    
        void StartDash()
        {
            if (Input.GetButtonDown("Dash") && canDash && !dashed)
            {
                StartCoroutine(Dash());
                dashed = true;
            }
    
            if (Grounded())
            {
                dashed = false;
            }
        }
    
        IEnumerator Dash()
        {
            canDash = false;
            pState.dashing = true;
            anim.SetTrigger("dashing");
            rb.gravityScale = 0;
            rb.velocity = new Vector2(transform.localScale.x * dashSpeed, 0);
            if (Grounded()) Instantiate(dashEffect, transform);
            yield return new WaitForSeconds(dashTime);
            rb.gravityScale = gravity;
            pState.dashing = false;
            yield return new WaitForSeconds(dashCooldown);
            canDash = true;
        }
    
        void Attack()
        {
            timeSinceAttack += Time.deltaTime;
            if(attack && timeSinceAttack >= timeBetweenAttack)
            {
                timeSinceAttack = 0;
                anim.SetTrigger("Attacking");
            }
        }
    
        public bool Grounded()
        {
            if (Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround)
                || Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround)
                || Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckX, 0, 0), Vector2.down, groundCheckY, whatIsGround))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    
        void Jump()
        {
            if (Input.GetButtonUp("Jump") && rb.velocity.y > 0)
            {
                rb.velocity = new Vector2(rb.velocity.x, 0);
    
                pState.jumping = false;
            }
    
            if (!pState.jumping)
            {
                if (jumpBufferCounter > 0 && coyoteTimeCounter > 0)
                {
                    rb.velocity = new Vector3(rb.velocity.x, jumpForce);
    
                    pState.jumping = true;
                }
                else if (!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump"))
                {
                    pState.jumping = true;
    
                    airJumpCounter++;
    
                    rb.velocity = new Vector3(rb.velocity.x, jumpForce);
                }
            }
    
            anim.SetBool("jumping", !Grounded());
        }
    
        void UpdateJumpVariables()
        {
            if (Grounded())
            {
                pState.jumping = false;
                coyoteTimeCounter = coyoteTime;
                airJumpCounter = 0;
            }
            else
            {
                coyoteTimeCounter -= Time.deltaTime;
            }
    
            if (Input.GetButtonDown("Jump"))
            {
                jumpBufferCounter = jumpBufferFrames;
            }
            else
            {
                jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10;
            }
        }
    }</code>
    #15706
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Adhiraj, thanks for taking the time to post the video. It’s really helpful.

    I suspect the issue lies with your animator transition (i.e. the connecting arrow) from Attack back to Idle. Check that the Exit Time for that is set to 1 or below. If it is higher than 1, your animation will repeat itself.

    #15709
    Adhiraj Patil
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hey Terence, thank you for replying, I went through the animator and checked the transition from attack to idle and the exit time is set to 1. I am attaching a video for the same. Thanks.

    #15710
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Can you put the Animator window on the left, then play the game in the Editor and trigger the attack animation? This will allow you to see any issues with animation flow on the Animator window.

    Record a video of this and let me have a look at the Animator window.

    #15714
    Adhiraj Patil
    Level 3
    Participant
    Helpful?
    Up
    0
    ::

    Hey, Yes, I have attached the video also I noticed that If I hold Mouse 1 the character attacks continuously, with delay offcourse.

    Link : https://imgur.com/a/ShRAko0

    #15715
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Ah, I found the issue now. Add the highlighted portion to your code below:

    void GetInputs()
    {
        xAxis = Input.GetAxisRaw("Horizontal");
        attack = Input.GetMouseButtonDown(0);
    }

    GetMouseButton() will detect if you hold down the mouse button (i.e. can fire multiple times), whereas GetMouseButtonDown() will detect only the first frame where you click the mouse (i.e. only fires once).

    #15716
    Adhiraj Patil
    Level 3
    Participant
    Helpful?
    Up
    1
    ::

    Damn thanks, it worked. how can I miss this, So many thank yous.

    has upvoted this post.
Viewing 7 posts - 1 through 7 (of 7 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: