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
Yes, this is my playermovement code. Code (CSharp): using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerMovement : MonoBehaviour { public CharacterController2D controller; public Animator animator; public Rigidbody2D rigidBody2D; float horizontalMove = 0f; public float runSpeed = 40f; bool jump = false; bool sprint = false; // Update is called once per frame void Update () { horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed; animator.SetFloat("Speed", Mathf.Abs(horizontalMove)); if (Input.GetButtonDown ("Jump")) { jump = true; animator.SetBool("IsJumping", true); } if (Input.GetButtonDown("Shift")) { sprint = true; } if (Input.GetButtonUp ("Shift")) { sprint = false; } if (rigidBody2D.velocity.y == 0) { animator.SetBool ("IsJumping", false); } } public void OnLanding () { animator.SetBool("IsJumping", false); } void FixedUpdate () { controller.Move(horizontalMove * Time.fixedDeltaTime, false, jump); jump = false; } } And this is my characterController2D Code (CSharp): using UnityEngine; using UnityEngine.Events; public class CharacterController2D : MonoBehaviour { [SerializeField] private float m_JumpForce = 400f; // Amount of force added when the player jumps. [Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f; // Amount of maxSpeed applied to crouching movement. 1 = 100% [Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement [SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping; [SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character [SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded. [SerializeField] private Transform m_CeilingCheck; // A position marking where to check for ceilings [SerializeField] private Collider2D m_CrouchDisableCollider; // A collider that will be disabled when crouching const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded private bool m_Grounded; // Whether or not the player is grounded. const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up private Rigidbody2D m_Rigidbody2D; private bool m_FacingRight = true; // For determining which way the player is currently facing. private Vector3 m_Velocity = Vector3.zero; [Header("Events")] [Space] public UnityEvent OnLandEvent; [System.Serializable] public class BoolEvent : UnityEvent<bool> { } public BoolEvent OnCrouchEvent; private bool m_wasCrouching = false; private void Awake() { m_Rigidbody2D = GetComponent<Rigidbody2D>(); if (OnLandEvent == null) OnLandEvent = new UnityEvent(); if (OnCrouchEvent == null) OnCrouchEvent = new BoolEvent(); } private void FixedUpdate() { bool wasGrounded = m_Grounded; 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[i].gameObject != gameObject) { m_Grounded = true; if (!wasGrounded) OnLandEvent.Invoke(); } } } public void Move(float move, bool crouch, bool jump) { // If crouching, check to see if the character can stand up if (!crouch) { // If the character has a ceiling preventing them from standing up, keep them crouching if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround)) { crouch = true; } } //only control the player if grounded or airControl is turned on if (m_Grounded || m_AirControl) { // If crouching if (crouch) { if (!m_wasCrouching) { m_wasCrouching = true; OnCrouchEvent.Invoke(true); } // Reduce the speed by the crouchSpeed multiplier move *= m_CrouchSpeed; // Disable one of the colliders when crouching if (m_CrouchDisableCollider != null) m_CrouchDisableCollider.enabled = false; } else { // Enable the collider when not crouching if (m_CrouchDisableCollider != null) m_CrouchDisableCollider.enabled = true; if (m_wasCrouching) { m_wasCrouching = false; OnCrouchEvent.Invoke(false); } } // Move the character by finding the target velocity Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y); // And then smoothing it out and applying it to the character m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing); // If the input is moving the player right and the player is facing left... if (move > 0 && !m_FacingRight) { // ... flip the player. Flip(); } // Otherwise if the input is moving the player left and the player is facing right... else if (move < 0 && m_FacingRight) { // ... flip the player. Flip(); } } // If the player should jump... if (m_Grounded && jump) { // Add a vertical force to the player. m_Grounded = false; m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce)); } } private void Flip() { // Switch the way the player is labelled as facing. m_FacingRight = !m_FacingRight; // Multiply the player's x local scale by -1. Vector3 theScale = transform.localScale; theScale.x *= -1; transform.localScale = theScale; } }
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.
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.
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.
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
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).
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?
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.
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.
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.
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.
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.
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.