• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by tornprince2012 · Jul 30, 2019 at 06:25 AM · 2d game2d-platformer2d-physics

Creating a delay after being grounded so the player can still jump while falling.

Hey everyone, I have a tiny problem that I can't solve ( noob at scripting, yes ).

2D platformer - jumping. While grounded check works perfectly, everyone knows that back in the old days this was a known thing : if you're falling from the edge of an object ( the one you had grounded = true a split second ago ), player can't jump and falls down to his death.

What I am trying to do is to add a very short delay between player being grounded and not being grounded anymore so that the player can still jump while he's not physically on the edge anymore.

Can anyone help me with this, please?

Here's my code if someone has a minute to spare...

 public float moveSpeed;
 private float activeMoveSpeed;

 public bool canMove;

 public Rigidbody2D myRigidBody;

 public float jumpSpeed;

 public Transform groundCheck;
 public float groundCheckRadius;
 public LayerMask whatIsGround;

 public bool isGrounded;


 private Animator myAnim;

 public Vector3 respawnPosition;

 private bool onPlatform;
 public float onPlatformSpeedModifier;

 public LevelManager theLevelManager;

 public GameObject stompBox;

 public float knockbackForce;
 public float knockbackLength;
 private float knockbackCounter;

 public float invincibilityLength;
 private float invincibilityCounter;

 public AudioSource playerJumpSound;
 public AudioSource playerHurtSound;


 // Start is called before the first frame update
 void Start()
 {
     myRigidBody = GetComponent<Rigidbody2D>();
     myAnim = GetComponent<Animator>();

     respawnPosition = transform.position;

     theLevelManager = FindObjectOfType<LevelManager>();

     activeMoveSpeed = moveSpeed;

     canMove = true;

 }

 // Update is called once per frame
 void Update()
 {

     isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);

     

     if (knockbackCounter <= 0 && canMove)
     {
         if (onPlatform)
         {
             activeMoveSpeed = moveSpeed * onPlatformSpeedModifier;
         }
         else
         {
             activeMoveSpeed = moveSpeed;
         }

         if (Input.GetAxisRaw("Horizontal") > 0f)
         //if (CrossPlatformInputManager.GetAxis("Horizontal") > 0f)
         {
             myRigidBody.velocity = new Vector3(activeMoveSpeed, myRigidBody.velocity.y, 0f);
             transform.localScale = new Vector3(1f, 1f, 1f);
         }
         else if (Input.GetAxisRaw("Horizontal") < 0f)
         //else if (CrossPlatformInputManager.GetAxis("Horizontal") < 0f)
         {
             myRigidBody.velocity = new Vector3(-activeMoveSpeed, myRigidBody.velocity.y, 0f);
             transform.localScale = new Vector3(-1f, 1f, 1f);
         }
         else
         {
             myRigidBody.velocity = new Vector3(0f, myRigidBody.velocity.y, 0f);
         }


         if (Input.GetButtonDown("Jump") && isGrounded)
         //if (CrossPlatformInputManager.GetButtonDown("Jump") && isGrounded)
         {
             myRigidBody.velocity = new Vector3(myRigidBody.velocity.x, jumpSpeed, 0f);
             playerJumpSound.Play();
         }


     }

     if(knockbackCounter > 0)
     {
         knockbackCounter -= Time.deltaTime;

         if (transform.localScale.x > 0)
         {
             myRigidBody.velocity = new Vector3(-knockbackForce * 3f, knockbackForce, 0f);
         }
         else
         {
             myRigidBody.velocity = new Vector3(knockbackForce * 3f, knockbackForce, 0f);
         }    
     }

    
     if (invincibilityCounter > 0)
     {
         invincibilityCounter -= Time.deltaTime;
     }

     if(invincibilityCounter <= 0)
     {
         theLevelManager.invincible = false;
     }


     myAnim.SetFloat("Speed", Mathf.Abs(myRigidBody.velocity.x));
     myAnim.SetBool("Grounded", isGrounded);

     if(myRigidBody.velocity.y < 0)
     {
         stompBox.SetActive(true);
     }
     else
     {
         stompBox.SetActive(false);
     }

 }
 public void Knockback()
 {
     knockbackCounter = knockbackLength;
     invincibilityCounter = invincibilityLength;
     theLevelManager.invincible = true;
 }

 public IEnumerator RespawnAfterFall()
 {
     yield return new WaitForSeconds(2f);
     transform.position = respawnPosition;

 }

 private void OnTriggerEnter2D(Collider2D other)
 {
     if(other.tag == "KillPlane")
     {
         
         StartCoroutine("RespawnAfterFall");

         //gameObject.SetActive(false);

         //transform.position = respawnPosition;

         //theLevelManager.Respawn();
     }   

     if(other.tag == "Checkpoint")
     {
         respawnPosition = other.transform.position;
     }
 }

 private void OnCollisionEnter2D(Collision2D other)
 {
     if(other.gameObject.tag == "MovingPlatform")
     {
         transform.parent = other.transform;
         onPlatform = true;
     }
 }

 private void OnCollisionExit2D(Collision2D other)
 {
     if(other.gameObject.tag == "MovingPlatform")
     {
         transform.parent = null;
         onPlatform = false;
     }
 }

}

Comment

People who like this

0 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by I_Am_Err00r · Jul 30, 2019 at 01:37 PM

First add a public float secondChanceTime (this variable will represent short delay you want, set that in the inspector) and maybe a private bool secondChance and set it default to true; then somewhere in that giant Update block (might want to break out each function into their own to make a little cleaner) add this line:

 if(isGrounded != true)
 {
 Invoke("SecondChance", secondChanceTime);
 }

Then somewhere outside of that update block add this:

 //this function can either be public or private, depends on if other scripts need to know about the secondChance change
 
 public void SecondChance()
 {
 secondChance = false;
 }

Then change jump function to something like this:

 if (Input.GetButtonDown("Jump") && secondChance == true)

And then don't forget to add something back to the isGrounded to make secondChance true again, and that will give you the short window to jump again if you fall off platform.

Comment
tornprince2012

People who like this

1 Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image tornprince2012 · Jul 31, 2019 at 05:39 PM 0
Share

Thank you so much!!!

Worked like a charm after some understanding that I needed to be isGrounded once thePlayer touches the ground and can jump again. Thank you!!!!

avatar image Bunny83 · Jul 31, 2019 at 06:04 PM 0
Share

This is not really a good approach. As long as isGrounded is false you queue another SecondChance execution every frame. while this is relatively irrelevant for a single jump, if can easily produce interference when you jump in quick succession or if you loose ground contact quite frequently. A re-triggerable cooldown would be simpler, more reliable and less resource intensive.

avatar image

Answer by Bunny83 · Jul 31, 2019 at 06:12 PM

Just declare a cooldown / timer variable which takes care of the "signal extension".

 public float jumpTimeExtension = 0.5f;
 float jumpCondition = 0;
 
 void Update()
 {
     // [ ... ]
     if (isGrounded)
         jumpCondition = jumpTimeExtension;
     if (jumpCondition > 0)
     {
         jumpCondition -= Time.deltaTime;
         if (Input.GetButtonDown("Jump"))
         {
             myRigidBody.velocity = new Vector3(myRigidBody.velocity.x, jumpSpeed, 0f);
             playerJumpSound.Play();    
         }
     }
     // [ ... ]
 }

So while "jumpCondition" is greater than 0 you can jump. As long as you are grounded it's set to "jumpTimeExtension" every frame and therefore greater than 0. Since we subtract deltaTime each frame it naturally drops over time if it's not reset every frame. So once the time has run out you can no longer jump. As soon as you get back to ground the timer resets immediately.

Comment
LazyBonesJohn

People who like this

1 Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image tornprince2012 · Aug 01, 2019 at 12:47 PM 0
Share

Thank you for your time and effort to help!

I would agree to this because of your great explanation about doing things the "right" way resources-wise and due to its simplicity.

However, if I make that delay for jump a quarter of a second, I can squeeze 2 jumps if I am quick enough. Now - this is not my goal. I would like to keep a single jump only WHILE having that delay where player is falling down from platforms but still able to save themselves during that quarter of a second.

Is there any way to prevent any jumps after the initial one?

avatar image LazyBonesJohn · May 29, 2022 at 03:23 AM 1
Share

@tornprince2012 yes you can do that. The way to do it is also implement a max number of jumps. Basically you create a Public int maxJumps = 1; and Public int jumpCount;

At start/awake go jumpCount = maxJumps;

Then whenever grounded go jumpCount= max jumps;

Whenever you do a jump go jumpCount -= 1; Then add another if statement when checking if it's permissible to jump with If (jumpCount > 0)

Important to note, jump refresh should be tied to the ground detection, not the "second chance" timer, as tying it to the second chance timer will allow the same multi jump issue.

An alternative or additional approach would be to put a timer between jumps, this would also be good if you wanted your character to be able to double jump.

avatar image Bunny83 LazyBonesJohn · May 29, 2022 at 11:13 AM 0
Share

Right, either a maxJumpCount or simply set the timer to 0 when you actually jump. That timer just acts like a bool which allows you to jump as long as it's greater than 0. Setting it to 0 would immediately stop any additional jumps.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

146 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

OnTriggerEnter2D(Collider2D other) 2 Answers

Turning off an on URP lights 2d 0 Answers

Can anybody help me with this? Character bodying is falling apart. 0 Answers

Help Me! I want to make a pixel fairy! 1 Answer

How can I make an object stop all momentum and hold it's position in air? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges