Search Unity

Trouble with On Land Event

Discussion in 'Scripting' started by FuzeCraft, Sep 17, 2018.

  1. FuzeCraft

    FuzeCraft

    Joined:
    Oct 23, 2016
    Posts:
    3
    Hello !
    I'm working on Unity 2018.2.7f1 on a 2D project. I have a problem with my character's jump animation, let me explain myself : my character jumps well, but the animation doesn't work unless I press the jump button twice. I used a Debug.Log on my On Land's function, and I found out that 1/2sec after my jump, the function runs which stops the jump's animation. How can I solve this problem ?
    Tell me if you need anything from my project I'm a beginner to Unity.
    Thanks alot !
    Brodwin
     
  2. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    Can you post your code?
     
  3. FuzeCraft

    FuzeCraft

    Joined:
    Oct 23, 2016
    Posts:
    3
    Yes, this is my playermovement code.

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PlayerMovement : MonoBehaviour {
    7.  
    8.     public CharacterController2D controller;
    9.     public Animator animator;
    10.     public Rigidbody2D rigidBody2D;
    11.  
    12.     float horizontalMove = 0f;
    13.  
    14.     public float runSpeed = 40f;
    15.  
    16.     bool jump = false;
    17.  
    18.     bool sprint = false;
    19.  
    20.     // Update is called once per frame
    21.     void Update () {
    22.  
    23.         horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
    24.         animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
    25.  
    26.  
    27.         if (Input.GetButtonDown ("Jump"))
    28.         {
    29.             jump = true;
    30.             animator.SetBool("IsJumping", true);
    31.         }
    32.  
    33.         if (Input.GetButtonDown("Shift"))
    34.         {
    35.             sprint = true;
    36.         }
    37.  
    38.         if (Input.GetButtonUp ("Shift"))
    39.         {
    40.             sprint = false;
    41.         }
    42.  
    43.         if (rigidBody2D.velocity.y == 0)
    44.         {
    45.             animator.SetBool ("IsJumping", false);
    46.         }
    47.  
    48.     }
    49.  
    50.     public void OnLanding ()
    51.     {
    52.         animator.SetBool("IsJumping", false);
    53.     }
    54.  
    55.     void FixedUpdate () {
    56.  
    57.         controller.Move(horizontalMove * Time.fixedDeltaTime, false, jump);
    58.         jump = false;
    59.     }
    60.  
    61. }
    And this is my characterController2D
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4.  
    5. public class CharacterController2D : MonoBehaviour
    6. {
    7.     [SerializeField] private float m_JumpForce = 400f;                            // Amount of force added when the player jumps.
    8.     [Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f;            // Amount of maxSpeed applied to crouching movement. 1 = 100%
    9.     [Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f;    // How much to smooth out the movement
    10.     [SerializeField] private bool m_AirControl = false;                            // Whether or not a player can steer while jumping;
    11.     [SerializeField] private LayerMask m_WhatIsGround;                            // A mask determining what is ground to the character
    12.     [SerializeField] private Transform m_GroundCheck;                            // A position marking where to check if the player is grounded.
    13.     [SerializeField] private Transform m_CeilingCheck;                            // A position marking where to check for ceilings
    14.     [SerializeField] private Collider2D m_CrouchDisableCollider;                // A collider that will be disabled when crouching
    15.  
    16.     const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
    17.     private bool m_Grounded;            // Whether or not the player is grounded.
    18.     const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
    19.     private Rigidbody2D m_Rigidbody2D;
    20.     private bool m_FacingRight = true;  // For determining which way the player is currently facing.
    21.     private Vector3 m_Velocity = Vector3.zero;
    22.  
    23.     [Header("Events")]
    24.     [Space]
    25.  
    26.     public UnityEvent OnLandEvent;
    27.  
    28.     [System.Serializable]
    29.     public class BoolEvent : UnityEvent<bool> { }
    30.  
    31.     public BoolEvent OnCrouchEvent;
    32.     private bool m_wasCrouching = false;
    33.  
    34.     private void Awake()
    35.     {
    36.         m_Rigidbody2D = GetComponent<Rigidbody2D>();
    37.  
    38.         if (OnLandEvent == null)
    39.             OnLandEvent = new UnityEvent();
    40.  
    41.         if (OnCrouchEvent == null)
    42.             OnCrouchEvent = new BoolEvent();
    43.     }
    44.  
    45.     private void FixedUpdate()
    46.     {
    47.         bool wasGrounded = m_Grounded;
    48.         m_Grounded = false;
    49.  
    50.         // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
    51.         // This can be done using layers instead but Sample Assets will not overwrite your project settings.
    52.         Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
    53.         for (int i = 0; i < colliders.Length; i++)
    54.         {
    55.             if (colliders[i].gameObject != gameObject)
    56.             {
    57.                 m_Grounded = true;
    58.                 if (!wasGrounded)
    59.                     OnLandEvent.Invoke();
    60.             }
    61.         }
    62.     }
    63.  
    64.  
    65.     public void Move(float move, bool crouch, bool jump)
    66.     {
    67.         // If crouching, check to see if the character can stand up
    68.         if (!crouch)
    69.         {
    70.             // If the character has a ceiling preventing them from standing up, keep them crouching
    71.             if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround))
    72.             {
    73.                 crouch = true;
    74.             }
    75.         }
    76.  
    77.         //only control the player if grounded or airControl is turned on
    78.         if (m_Grounded || m_AirControl)
    79.         {
    80.  
    81.             // If crouching
    82.             if (crouch)
    83.             {
    84.                 if (!m_wasCrouching)
    85.                 {
    86.                     m_wasCrouching = true;
    87.                     OnCrouchEvent.Invoke(true);
    88.                 }
    89.  
    90.                 // Reduce the speed by the crouchSpeed multiplier
    91.                 move *= m_CrouchSpeed;
    92.  
    93.                 // Disable one of the colliders when crouching
    94.                 if (m_CrouchDisableCollider != null)
    95.                     m_CrouchDisableCollider.enabled = false;
    96.             } else
    97.             {
    98.                 // Enable the collider when not crouching
    99.                 if (m_CrouchDisableCollider != null)
    100.                     m_CrouchDisableCollider.enabled = true;
    101.  
    102.                 if (m_wasCrouching)
    103.                 {
    104.                     m_wasCrouching = false;
    105.                     OnCrouchEvent.Invoke(false);
    106.                 }
    107.             }
    108.  
    109.             // Move the character by finding the target velocity
    110.             Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
    111.             // And then smoothing it out and applying it to the character
    112.             m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing);
    113.  
    114.             // If the input is moving the player right and the player is facing left...
    115.             if (move > 0 && !m_FacingRight)
    116.             {
    117.                 // ... flip the player.
    118.                 Flip();
    119.             }
    120.             // Otherwise if the input is moving the player left and the player is facing right...
    121.             else if (move < 0 && m_FacingRight)
    122.             {
    123.                 // ... flip the player.
    124.                 Flip();
    125.             }
    126.         }
    127.         // If the player should jump...
    128.         if (m_Grounded && jump)
    129.         {
    130.             // Add a vertical force to the player.
    131.             m_Grounded = false;
    132.             m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
    133.         }
    134.     }
    135.  
    136.  
    137.     private void Flip()
    138.     {
    139.         // Switch the way the player is labelled as facing.
    140.         m_FacingRight = !m_FacingRight;
    141.  
    142.         // Multiply the player's x local scale by -1.
    143.         Vector3 theScale = transform.localScale;
    144.         theScale.x *= -1;
    145.         transform.localScale = theScale;
    146.     }
    147. }
    148.  
     
  4. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    Does your character stop at the top of his jump? It's worth noting that vertical velocity can equal zero at the top of the jump.
     
  5. FuzeCraft

    FuzeCraft

    Joined:
    Oct 23, 2016
    Posts:
    3
    No it doesnt stop, only the animation stops right after the character jumps but the jump still works
     
  6. hamberge

    hamberge

    Joined:
    Aug 30, 2015
    Posts:
    36
    My guess is just that this code:

    if (rigidBody2D.velocity.y == 0)
    {
    animator.SetBool ("IsJumping", false);
    }


    is executed at the top of your guy's jump because vertical velocity is 0 at the top of any arced trajectory (it's physics). This may not be the case though, and it also doesn't seem to explain why you have to press jump twice.
     
  7. MehmetCakir

    MehmetCakir

    Joined:
    Jul 18, 2017
    Posts:
    5
    It is a problem with whatIsGround, character "thinks" that he/she is grounded right after you press jump button, so stops animation from playing immediately. So you can jump twice. I could not figure how to solve it though.
     
  8. Adien22

    Adien22

    Joined:
    Aug 19, 2019
    Posts:
    44
    Ok, so I found the only solution that worked, for me at least. I stopped using the OnLanding event, and instead, I added my animator to the character controller.
    everywhere you set m_Grouned to true, add animator.SetBool("IsJumping", true);
    everywhere you set m_Grounded false, add animator.SetBool("IsJumping", false);

    works like a charm for me now. Hope this helps if you still needed it

    If you do it this way, delete it out of your movement script also. or it won't work
     
    A7med378 likes this.
  9. A7med378

    A7med378

    Joined:
    Dec 13, 2017
    Posts:
    1
    Thanks this solution worked for me too.
     
    Adien22 likes this.
  10. PixelFireXY

    PixelFireXY

    Joined:
    Nov 2, 2011
    Posts:
    56
    I know it's an old post, but for who has the same problem (or similar) and this solution is not working, just change FixedUpdate with Update and the code will detect the ground correctly (and animations will work).
     
    halferhu, Jordylicious and AdvikMehta like this.
  11. areevalo

    areevalo

    Joined:
    May 8, 2020
    Posts:
    1
    Hi, I had the problem that my character didnt do the jump animation when I jumped very close to the edge of a platform but changing FixedUpdate for Update in the CharacterController worked for me. But now when i fall on the platform it stays on the last frame of the jump animation until I don't jump again. Any ideas?
     

    Attached Files:

  12. MightyPoro

    MightyPoro

    Joined:
    Mar 18, 2020
    Posts:
    1
    Some guy named Ethan Evans gave this solution in the youtube comments of this video :

    He was answering to
    Zone valdezil: "please help me! Why i need to double press the UP/W key to see the animation of jumping?"

    Anyway this solution worked for me too so here it is:

    Worked on it for a little while and I came up with the following.


    But first, at the top of the script with all of the global variables you are going to want to add the following:


    private System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();


    Here's the updated FixedUpdate method that I came up with.


    private void FixedUpdate()
    {

    if (!m_Grounded)
    {
    sw.Start();
    }

    m_Grounded = false;


    // The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
    // This can be done using layers instead but Sample Assets will not overwrite your project settings.
    Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
    for (int i = 0; i < colliders.Length; i++)
    {
    if (colliders.gameObject != gameObject)
    {
    //sw.Stop();
    m_Grounded = true;
    if (sw.ElapsedMilliseconds > (long)60)
    OnLandEvent.Invoke();
    sw.Reset();
    }
    }
    }


    Basically what I did was that I took the "wasGrounded" variable out of the equation because there wasn't enough time after the jump for the ground check to stop colliding with the ground. I've replaced it with a Stopwatch which starts every time the player is no longer on the ground. If a collision has occurred, m_Grounded is changed to true and then the if statement calls ElapsedMilliseconds, which returns the amount of time that has passed in milliseconds. I set this limit to be greater than 60 ms, which was enough time for my jump force to clear the ground.


    If you are still having the same problems try changing the 60ms. Should of made this SerializeField so you can change it easily from the editor (or at least that's how I think it works, still pretty new with C# and Unity lol).


    There is a slight bug with this when it comes to bunny-hopping. If you time it right the Jumping variable in the animator won't be updated and remain true, which will cause the animation to cycle through back to the first frame. Not sure if this is the fault of my code or me not knowing that much about Unity haha.


    Lmk if there are any other bugs you find.
     
    nyirkos and WillyWalker like this.
  13. WillyWalker

    WillyWalker

    Joined:
    Aug 10, 2020
    Posts:
    1
    The stopwatch method worked perfect for me, however I did make some slight alterations. I added a variable that looked like this

    [SerializeField] private float GroundedWait = 60f;

    in the public class, and then in the FixedUpdate function instead of saying

    if (sw.ElapsedMilliseconds > (long)60)

    I said

    if (sw.ElapsedMilliseconds > (GroundedWait)

    I also gave that if statement brackets because for some reason it seemed to be missing them. The only thing this does is allow you to change how long your sprite has to clear the ground from inside Unity for fine tuning.
     
  14. seanje

    seanje

    Joined:
    Aug 12, 2020
    Posts:
    2
    I had this exact issue for a while as well, and it turned out to be about where I place my Ground Check--needs to be very exact. If too low to the ground, as stated before not enough time passed to get the Ground Check off the ground. If too high, it thought I was always jumping. Try experimenting with your Ground Check position.
     
    vannavva and Digital_Owl like this.
  15. Baba57

    Baba57

    Joined:
    Jan 28, 2021
    Posts:
    2
    It was worked for me before. I moved up groundcheck littebit up and it was working but now, i have same problem and right now it is not working like that for me.
     
  16. Baba57

    Baba57

    Joined:
    Jan 28, 2021
    Posts:
    2
    I fixed my problem! It is my first game making experience, i was following Brackeys tutorial about 2d game. in tutorial we download a script called CharacterController2D. That was why i have the problem. I found the solution on the internet on answers.unity.com.

    Inside CharacterController2D script found:

    m_Grounded = true;
    if (!wasGrounded)
    OnLandEvent.Invoke();


    delete the (!) and it should be like that:

    m_Grounded = true;
    if (wasGrounded)
    OnLandEvent.Invoke();

    it fixed my problem.

    EDIT:
    If problem happens again (happened to me) just rewrite the (!) same place you deleted it in CharacterController2D script. I don't understand why it is like that but that fixed my problem again.
     
    Last edited: Jan 29, 2021
    TaronTonoyan and ThatAsianBoy like this.
  17. Jordylicious

    Jordylicious

    Joined:
    Feb 18, 2020
    Posts:
    2
    This solved it for me, thanks!
     
  18. Digital_Owl

    Digital_Owl

    Joined:
    Feb 7, 2021
    Posts:
    46
    thanks i've been searching for an answer for 2 hours, trying to fix it myself for 2 more hours and finally found this, that was issue in my case.
     
  19. vannavva

    vannavva

    Joined:
    Sep 29, 2021
    Posts:
    1
    I have just signed up to say thank u <3
     
  20. nyirkos

    nyirkos

    Joined:
    Jan 7, 2021
    Posts:
    2
    The stopwatch method worked perfectly for me as well. Big thank you to MightyPoro!!!