Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Stop Moving While Attacking

Discussion in 'Scripting' started by DrewJThomas, Mar 21, 2022.

  1. DrewJThomas

    DrewJThomas

    Joined:
    Feb 26, 2022
    Posts:
    92
    Title, I don't want my sprite to move for a second when the attack button is pushed.
    I suspect this isn't a very complicated code but I don't know how to do it! Thanks.

    My movement script:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5.  
    6. public class PlayerMovement : MonoBehaviour
    7. {
    8.    public CharacterController2D controller;
    9.    public Animator animator;
    10.  
    11.    public float runSpeed = 40f;
    12.  
    13.    float horizontalMove = 0f;
    14.    bool jump = false;
    15.    bool crouch = false;
    16.  
    17.    [SerializeField] private LayerMask m_WhatIsGround;                            // A mask determining what is ground to the character
    18.     [SerializeField] private Transform m_GroundCheck;                            // A position marking where to check if the player is grounded.
    19. const float k_GroundedRadius = .2f;
    20. private bool m_Grounded;
    21.  
    22. public UnityEvent OnLandEvent;
    23.  
    24.    [SerializeField] private AudioSource jumpSoundEffect;
    25.  
    26.     void Update()
    27.     {
    28.  
    29.        horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
    30.  
    31. animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
    32.  
    33.        if (m_Grounded && (Input.GetButtonDown("Jump")))
    34.        {
    35. jump = true;
    36. animator.SetBool("IsJumping", true);
    37. jumpSoundEffect.Play();
    38.        }
    39.  
    40.        if (Input.GetButtonDown("Crouch"))
    41.        {
    42. crouch = true;
    43.        } else if (Input.GetButtonUp("Crouch"))
    44.        {
    45.            crouch = false;
    46.        }
    47.     }
    48.  
    49. public void OnLanding ()
    50. {
    51.     animator.SetBool("IsJumping", false);
    52. }
    53.  
    54. public void OnCrouching (bool isCrouching)
    55. {
    56.     animator.SetBool("IsCrouching", isCrouching);
    57. }
    58.  
    59.     void FixedUpdate()
    60.     {
    61.  
    62. bool wasGrounded = m_Grounded;
    63.         m_Grounded = false;
    64.  
    65.         // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
    66.         // This can be done using layers instead but Sample Assets will not overwrite your project settings.
    67.         Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
    68.         for (int i = 0; i < colliders.Length; i++)
    69.         {
    70.             if (colliders[i].gameObject != gameObject)
    71.             {
    72.                 m_Grounded = true;
    73.                 if (!wasGrounded)
    74.                     OnLandEvent.Invoke();
    75.             }
    76.         }
    77.  
    78.  
    79.         //Move our character
    80. controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
    81. jump = false;
    82.     }
    83. }
    84.  
    My combat script (if needed)
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5.  
    6. public class PlayerCombat : MonoBehaviour
    7. {
    8.  
    9. public Animator animator;
    10.  
    11.   public Transform attackPoint;
    12.   public LayerMask enemyLayers;
    13.   public float attackRange = 0.5f;
    14.  
    15. public int attackDamage = 40;
    16.  
    17. public float attackRate = 2f;
    18. float nextAttackTime = 0f;
    19.  
    20. // //new code
    21. // private float gunHeat;
    22. // private const float TimeBetweenShots = .25f;
    23. // bool jump = false;
    24. // //end new code
    25.  
    26. [SerializeField] private LayerMask m_WhatIsGround;                            // A mask determining what is ground to the character
    27.     [SerializeField] private Transform m_GroundCheck;                            // A position marking where to check if the player is grounded.
    28. const float k_GroundedRadius = .2f;
    29. private bool m_Grounded;
    30.  
    31. public UnityEvent OnLandEvent;
    32.  
    33.  
    34. [SerializeField] private AudioSource attackSoundEffect;
    35.  
    36.     void Update()
    37.     {
    38.       if(Time.time >= nextAttackTime)
    39.       {
    40. if (m_Grounded && (Input.GetKeyDown(KeyCode.X)))
    41.       {
    42.        attackSoundEffect.Play();
    43. Attack();
    44. nextAttackTime = Time.time + 1f / attackRate;
    45.       }
    46.       }
    47.  
    48. // //new code
    49. // if (gunHeat > 0)
    50. // {
    51. //   gunHeat -= Time.deltaTime;
    52. // }
    53. // // is the player asking to shoot?
    54. // if (Input.GetButtonDown("Jump"))
    55. // {
    56. //    // can we shoot yet?
    57. //    if (gunHeat <= 0)
    58. //    {
    59. //      // heat the gun up so we have to wait a bit before shooting again
    60. //      gunHeat = TimeBetweenShots;
    61.  
    62. //      // DO THE SsHOT HERE
    63. //    }
    64. // }
    65. //      //end new code
    66.  
    67.     }
    68.    
    69.     void Attack()
    70.     {
    71.  
    72. //Play an attack animation
    73. animator.SetTrigger("Attack");
    74.  
    75. //Detect enemies in range of attack
    76. Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);
    77.  
    78. //Damage them
    79. foreach(Collider2D enemy in hitEnemies)
    80. {
    81.     enemy.GetComponent<Enemy>().takeDamage(attackDamage);
    82. }
    83.     }
    84.  
    85. void OnDrawGizmosSelected()
    86. {
    87. if(attackPoint == null)
    88. return;
    89.  
    90.   Gizmos.DrawWireSphere(attackPoint.position, attackRange);
    91. }
    92.  
    93.     private void FixedUpdate()
    94.     {
    95.         bool wasGrounded = m_Grounded;
    96.         m_Grounded = false;
    97.  
    98.         // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
    99.         // This can be done using layers instead but Sample Assets will not overwrite your project settings.
    100.         Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
    101.         for (int i = 0; i < colliders.Length; i++)
    102.         {
    103.             if (colliders[i].gameObject != gameObject)
    104.             {
    105.                 m_Grounded = true;
    106.                 if (!wasGrounded)
    107.                     OnLandEvent.Invoke();
    108.             }
    109.         }
    110.     }
    111.  
    112. }
    113.    
     
  2. BenevolenceGames

    BenevolenceGames

    Joined:
    Feb 17, 2021
    Posts:
    128
    Couldn't you just set a bool like "canMove", have it set to false as the first thing you do when running your attack method, and set it back to true with an animation event at the last frame of your attack animation?

    Then you would pass that bool as you call your move method. Should work, no?

    So 79. would read

    if (canMove) { //movement here }
     
    Last edited: Mar 21, 2022
    DrewJThomas and ChuckMaurice like this.
  3. ChuckMaurice

    ChuckMaurice

    Joined:
    Oct 3, 2017
    Posts:
    3
    If you want a fast solution, you could use a boolean

    If you want something more robust, you could make a state machine, but you'll need more time to do that.
    I don't know if your player got other actions than moving and shooting. If you want to create more actions later, or multiples states for your player that defines his actions (like swimming for example) the boolean can become very obnoxious later on because you'll need a lot of them ^^
     
    DrewJThomas and BenevolenceGames like this.
  4. BenevolenceGames

    BenevolenceGames

    Joined:
    Feb 17, 2021
    Posts:
    128
    I agree with Chuck, if you're going to have several movement methods (running, walking, jumping, crouching, swimming) plus several action methods (attacking, blocking, takingCover, throwingGrenade) you may want to invest time into a implementing a state machine because the conditions will get a bit encumbersome.
     
    DrewJThomas and ChuckMaurice like this.
  5. DrewJThomas

    DrewJThomas

    Joined:
    Feb 26, 2022
    Posts:
    92
    Thank you,

    I forgot to mention this is my first Unity/coding project and will probably need you to spell it out just a little bit
    But that all sounds doable, I'm just wondering how to set the "canMove" bool to actually know if the player can move or not
     
  6. BenevolenceGames

    BenevolenceGames

    Joined:
    Feb 17, 2021
    Posts:
    128
    So I would set it during the animations, personally. Do you know how to use Animation Events? If not you should google that. The basics are you can call a method from a frame of an animation. You have to insert the event, select the script and method and within that method you would change the bool of
    canMove
    . Put one on the first frame setting it to
    false
    and one on the last frame returning it to
    true
    . Do a little research and let me know if that helps.
     
    DrewJThomas likes this.
  7. DrewJThomas

    DrewJThomas

    Joined:
    Feb 26, 2022
    Posts:
    92
    It worked, I set an animation event with run speed at 0 on the first frame and then run speed at 50 (normal speed) on the last frame. Thanks!
     
    BenevolenceGames likes this.
  8. rodprogramdev

    rodprogramdev

    Joined:
    Oct 31, 2021
    Posts:
    2
    Try to setup a canMove = false variable inside of the function attack() declaration that you may have.

    Then you can create an IEnumerator for an attackDelay() then set the canMove = true; inside of the IEnumerator.
    Then from there you can call StartCoroutine(attackDelay()) inside of the function delay.
    This worked for me.
     
  9. Chubzdoomer

    Chubzdoomer

    Joined:
    Sep 27, 2014
    Posts:
    106
    This thread is over a year old, and the OP already solved his problem.