Search Unity

Mario Style Jumping?

Discussion in '2D' started by AV_Corey, Jan 25, 2016.

  1. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    I've looked everywhere and cannot find how to get a Mario style jump mechanic in C#.

    By a Mario style jump I mean you can tap the jump key and the player will do a little hop and if you hold it they will perform a higher jump. I'm very new to programming and didn't want to bother you professionals with this probably simple question but this is my last resort.
     
  2. topherbwell

    topherbwell

    Joined:
    Jun 8, 2015
    Posts:
    180
    I wrote this for you. It is heavily commented and should explain everything, so as long as you are here to learn it should get you to a good starting point.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class NewBehaviourScript : MonoBehaviour
    5. {
    6.     /*these floats are the force you use to jump, the max time you want your jump to be allowed to happen,
    7.      * and a counter to track how long you have been jumping*/
    8.     public float jumpForce;
    9.     public float jumpTime;
    10.     public float jumpTimeCounter;
    11.     /*this bool is to tell us whether you are on the ground or not
    12.      * the layermask lets you select a layer to be ground; you will need to create a layer named ground(or whatever you like) and assign your
    13.      * ground objects to this layer.
    14.      * The stoppedJumping bool lets us track when the player stops jumping.*/
    15.     public bool grounded;
    16.     public LayerMask whatIsGround;
    17.     public bool stoppedJumping;
    18.  
    19.     /*the public transform is how you will detect whether we are touching the ground.
    20.      * Add an empty game object as a child of your player and position it at your feet, where you touch the ground.
    21.      * the float groundCheckRadius allows you to set a radius for the groundCheck, to adjust the way you interact with the ground*/
    22.  
    23.     public Transform groundCheck;
    24.     public float groundCheckRadius;
    25.  
    26.     //You will need a rigidbody to apply forces for jumping, in this case I am using Rigidbody 2D because we are trying to emulate Mario :)
    27.     private Rigidbody2D rb;
    28.  
    29.     void Start()
    30.     {
    31.         //sets the jumpCounter to whatever we set our jumptime to in the editor
    32.         jumpTimeCounter = jumpTime;
    33.     }
    34.  
    35.     void Update()
    36.     {
    37.         //determines whether our bool, grounded, is true or false by seeing if our groundcheck overlaps something on the ground layer
    38.         grounded = Physics2D.OverlapCircle (groundCheck.position, groundCheckRadius, whatIsGround);
    39.  
    40.  
    41.         //if we are grounded...
    42.         if(grounded)
    43.         {
    44.             //the jumpcounter is whatever we set jumptime to in the editor.
    45.             jumpTimeCounter = jumpTime;
    46.         }
    47.     }
    48.  
    49.     void FixedUpdate()
    50.     {
    51.         //I placed this code in FixedUpdate because we are using phyics to move.
    52.  
    53.         //if you press down the mouse button...
    54.         if(Input.GetMouseButtonDown(0) )
    55.         {
    56.             //and you are on the ground...
    57.             if(grounded)
    58.             {
    59.                 //jump!
    60.                 rb.velocity = new Vector2 (rb.velocity.x, jumpForce);
    61.                 stoppedJumping = false;
    62.             }
    63.         }
    64.  
    65.         //if you keep holding down the mouse button...
    66.         if((Input.GetMouseButton(0)) && !stoppedJumping)
    67.         {
    68.             //and your counter hasn't reached zero...
    69.             if(jumpTimeCounter > 0)
    70.             {
    71.                 //keep jumping!
    72.                 rb.velocity = new Vector2 (rb.velocity.x, jumpForce);
    73.                 jumpTimeCounter -= Time.deltaTime;
    74.             }
    75.         }
    76.  
    77.  
    78.         //if you stop holding down the mouse button...
    79.         if(Input.GetMouseButtonUp(0))
    80.         {
    81.             //stop jumping and set your counter to zero.  The timer will reset once we touch the ground again in the update function.
    82.             jumpTimeCounter = 0;
    83.             stoppedJumping = true;
    84.         }
    85.     }
    86. }
     
    twomack37 likes this.
  3. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    I haven't tried this yet but I can't explain how grateful I am for you to have gone and wrote all of that for me. >.< Thanks so much man.
     
  4. topherbwell

    topherbwell

    Joined:
    Jun 8, 2015
    Posts:
    180
    It's no big deal. Most of it I just copy/pasted from existing scripts I am using and just deleted all the irrelevant stuff.

    Hope it helps!
     
  5. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    I just tried it out... Hey do you wanna get married?
     
    topherbwell likes this.
  6. topherbwell

    topherbwell

    Joined:
    Jun 8, 2015
    Posts:
    180
    heh nice I'll take it that it worked out then? great!
     
    AV_Corey likes this.
  7. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    It is all working perfectly apart from sometimes it will just eat the button input and not jump. I'm suspecting it's something to do with the groundCheck Radius or the groundCheck box collider attatched to my player but I'm not too sure. Have you seen this behaviour in the project you're using this code with?
     
  8. hawken

    hawken

    Joined:
    Aug 22, 2013
    Posts:
    475
    Wouldn't advise putting the sensor for jumping in FixedUpdate. Makes for laggy gameplay
     
    MoonJelly likes this.
  9. MoonJelly

    MoonJelly

    Joined:
    Oct 2, 2014
    Posts:
    225
    And I wouldn't advise controlling your 2D platformer character with the physics engine (rigidbody2D, applying force, setting velocity, etc). Raycasting is, in my experience, a much better way to go.
     
  10. hawken

    hawken

    Joined:
    Aug 22, 2013
    Posts:
    475
    Done right, using 2D physics is totally fine, you get a slew of advantages doing everything in the physics system, it's just another way of approaching things. 2D platformers try to emulate physics so why not use a physics engine if you have one? ;)
     
    theANMATOR2b likes this.
  11. hawken

    hawken

    Joined:
    Aug 22, 2013
    Posts:
    475
    here's how I go about it, I'll show the theory:

    Update - grab input.

    Fixed Update - add continuous forces.

    Functions - impulse forces.

    So, for example, if you jump and want an extended jump with the button held down:
    1. Listen for jump input in Update.
    2. Make sure the player is grounded and not holding down the jump key from his/her previous jump (set a flag when landed).
    3. Fire an impulse of minimum jump force using a function.
    4. if the button is held down, keep adding some small force in Fixed update, gravity, mass and this will work together to make a max height.
    5. check for apex of jump and switch to falling when the player's Y movement becomes negative
    6. check to see if the player landed and when they release the jump key set a flag to allow for jump input once again.
     
    Last edited: Jan 26, 2016
  12. topherbwell

    topherbwell

    Joined:
    Jun 8, 2015
    Posts:
    180
    Don't put a collider on the groundCheck object. Just an empty game object (a Transform)as a child of the player is all that is needed. I suspect if you are not jumping occasionally it has to do with the positioning/radius of the ground check.

    Insert the following function into your code to visualize the radius and position of the ground check in the scene view.
    Code (CSharp):
    1. void OnDrawGizmos()
    2.     {
    3.         Gizmos.DrawSphere(groundCheck.position, groundCheckRadius);
    4.     }
     
    Last edited: Jan 26, 2016
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    8,126
    Just to add to the discussion, you might find this article interesting. It shows 3 different ways to approach animation for a 2D game. The jumps are like you describe: holding the jump key produces a higher jump It also covers double-jumping (allowing the player to do one extra jump while in the air, but not more than that).
     
  14. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    Thanks for the explanation man, it is a big help :D
     
  15. AV_Corey

    AV_Corey

    Joined:
    Jan 7, 2016
    Posts:
    113
    Aha, I just moved everything from the FixedUpdate() into the Update() part of the script and it seems to be working fine now... Also I hate to be an ass but would you have any idea how to add a double jump into this code? Last time I had a double jump I used an int for TotalJumps, an int for currentJumps and a bool for whether or not the player canJump. I'm not too sure how I would implement this into the current code though.
     
    Last edited: Jan 26, 2016
  16. MoonJelly

    MoonJelly

    Joined:
    Oct 2, 2014
    Posts:
    225
    That seems like a reasonable way of doing it. I'd have an int _maxJumps and another int remainingJumps which is set to _maxJumps when you become grounded. When you press the jump button, ensure that remainingJumps > 0, do the actual jump and then decrement remainingJumps.
     
  17. hawken

    hawken

    Joined:
    Aug 22, 2013
    Posts:
    475
    Code (csharp):
    1. if(jump && !grounded && jumpTimes < maxJumpTimes)
    2. {
    3. Jump();
    4. jumpTimes++;
    5. }
    Then reset your jumpTimes on grounded = true.
     
  18. Techn0man

    Techn0man

    Joined:
    Jun 4, 2017
    Posts:
    2
    When I tried this it just sent a bunch of error text messages that said

    "UnassignedReferenceException: The variable groundCheck of Jumping has not been assigned.
    You probably need to assign the groundCheck variable of the Jumping script in the inspector.
    UnityEngine.Transform.get_position () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/TransformBindings.gen.cs:27)
    Jumping.Update () (at Assets/Jumping.cs:37"
    and it placed my charater like what? 10 units up? or 5 :/
     
  19. Techn0man

    Techn0man

    Joined:
    Jun 4, 2017
    Posts:
    2
    Just relized I'm using 3D coliders and Rigid bodies... maybe that's the cause ¯\_(ツ)_/¯
     
  20. harvtb04

    harvtb04

    Joined:
    Apr 3, 2018
    Posts:
    1
    Can you just add this to your script or do you need to make a new script?
     
  21. Gamegenorator

    Gamegenorator

    Joined:
    Jul 3, 2017
    Posts:
    11
    How to you controller the high of the longer jump?
     
  22. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    8,126
    Please check out my article. It's mostly about animation, but in the process I develop a controller for Mario-style running and jumping (plus a single double-jump, but you could easily take that out if it's not wanted).
     
  23. PainStone

    PainStone

    Joined:
    Apr 20, 2019
    Posts:
    4
    Hello! I am a new programmer and I need to know how to make my character jump with the last detected speed before jumping and keep that speed in the air.
     
  24. MoonJelly

    MoonJelly

    Joined:
    Oct 2, 2014
    Posts:
    225
    So you're going for an oldschool Castlevania jump then, where you can't change direction mid-air? I would think you'd just write your jump code like any other example you'll find, and in your move code, don't stop the character's movement if they're jumping.

    Sorry that's not a more detailed response. I'm very tired and about to head to bed. Hopefully that gives you something to work with. If you haven't watched tutorials on YouTube on how to do basic jumping, you should do that. :)
     
  25. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    8,126
    Or read the article linked right above your post. It explains and demonstrates applying your running speed to the jump, and as @MoonJelly says, if you don't want them to change speed in midair, then simply take out the code that allows them to do that.

    (Note that GamaSutra munges the code formatting a bit, but there's a demo project you can download and study.)
     
    MoonJelly likes this.
  26. PainStone

    PainStone

    Joined:
    Apr 20, 2019
    Posts:
    4
    I have been watching video tutorials on YouTube, but none of them comes to the solution to my problem.

    this is what i got it--->
    void Jump ()
    {
    rb2d.AddForce (new Vector2 (0, jumpForce));
    // jumpForce = rb2d.velocity;
    }
     
  27. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    8,126
    Don't use physics for a Mario-style game. It will only make your life harder and your game worse.
     
    MoonJelly likes this.