It's part of animation principles.You usually want to exaggerate weight, even if it's not realistic per se. It's more about how good it looks or feels.
Very nice explanation. Those who are taunting about video length. Please pay attention his explanation as they were detailed and he pointed the problems with usual unity script. So keep up the good work dude. :)
Very nice tutorial. A little optimization tip: You should multiply your scalars first and then multiply by the vector at the end, or use parenthesis to isolate your scalar multiplications, to avoid extra Vector2 creations. Also, once you're satisfied with your gravity value you can cache Physics2D.gravity.y * (fallMultiplier - 1) and Physics2D.gravity.y * (lowJumpMultiplier - 1) to avoid this unnecessary math on Update. Cheers!
@@Gyozamang He means that if you like how your jump is looking, you can just calculate the gravity.y * (fallMultipilier - 1) or (LowJumpMultiplier -1) like done in the code and write it as one number so the program does not have to do this math which is unnecessary because it does it every frame. You could store the calculation in a variable or something like this and let it calculate in Start() so it doesnt do it every Frame. Except you want to change the multipliers during the game like through power ups or such things (dont ask me why you'd need to have a power up for falling faster... but let's say you were like on another planet and needed to fall faster or slower, then its probably better). So to sum it up, you can store it in a variable in the beginning or, if it changes during one scene, you have to let it stay like it is in the video. Hope that helped
I've recently solved this problem in Godot 3 in a 3D platformer. I've implemented this differently - the player measures the time between the key press and release and there's a maximum afterburner time defined (about 0.5 s). During that time if the jump key is still depressed I apply additional upward velocity which ramps from 100% to 0% over the maximum afterburner time. This provides a very smooth and natural-looking yet expressive jump, it's pretty flexible to balance and doesn't mess with gravity
Thanks for this video, man, it helped me a lot. I saw the debate in the comments about the way you did it and I wanted to elaborate on the right way to implement this ideas. The thing with implementing acceleration in a simulation is that real life doesn't work in the same way: physics simulations work by taking little steps advancing in time, while time in real life is continuous; there are no steps. It's actually very hard to know where an object is going to be in real life, even if you know it's velocity, acceleration and current position, because its velocity changes every instant. What we do in video games to aproximate that effect, where physics have to be calculated very fast, is to take as many little steps as we can in our simulation in time and sometimes we also try to retroactively interpolate the position based on current acceleration. It's enough, but it's not perfect. So, the problem with doing the acceleration in the update is that, when the number of steps taken (the frame rate) is different, we end up with different positions. In this example, we end up with different short jump heights in different frame rates, which is not nice. So, here's what we can do: We create an additional variable, a boolean for storing the state of the jump button, I'll call it jumpPressed. Then, in Update we only have: void Update() { if (Input.GetButtonDown("Jump")) { //there is no problem with changing velocity once in update, //but addforce is better because it conserves momentum, so you can jump in an elevator GetComponent().AddForce(Vector2.up * jumpVelocity, ForceMode2D.Impulse); } if (Input.GetButton("Jump")) { jumpPressed = true; } else { jumpPressed = false; } } Then in fixed update, we can do the same magic: void FixedUpdate() { //Jump dynamics Code if (rigid.velocity.y < 0) { GetComponent().velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.fixedDeltaTime; } else if (rigid.velocity.y > 0 && !jumpPressed) { GetComponent().velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.fixedDeltaTime; } } And tada!
@@endasil Because even though the acceleration is the same, the increments to the velocity would be distributed differently. Imagine an object that accelerates by 30 meters per second each second. If the simulation was running at 30fps, the first frame the object would move with a velocity of 1, the second frame with a velocity of 2, and the third frame with a velocity of 3. After 1/10 of a second, it would have moved 6/30 of a meter. Now imagine the simulation was running at 60fps. The first frame the velocity would be .5, the second frame 1, the third frame 1.5, the fourth 2, the fifth 2.5, and the sixth 3. After 1/10 of a second, the final velocity is the same, but the object will have moved 10.5/60 of a meter.
I think this works really well when you let the player decide when they want to fall faster. It makes you feel really in control of how you move. Great vid!!!
Absolutely incredible tutorial. so simple, was struggling to figure out why my jump felt "off", then finally found your video. Explanation was on point, very clear and well presented.
It's tricky. Because you're looking at Inputs, Update is preferable, but in general, when affecting physics, FixedUpdate is preferable. You'd probably want to do some optimization before shipping, but for getting you to a better jump feel quickly, I think this is OK in Update.
I would disagree, you should aim to NEVER change physics in Update. Changing the code is as simple as getting the button state in the Update() function and keep the result in a boolean. Then using that in FixedUpdate.
If it were adding force I would agree with you 100%, because you risk adding more or less force based on framerate, but setting the gravity to a flat value is a little less troublesome.
I know updating physics in FixedUpdate is considered best practice, but why would you be adding more or less force in Update w/deltaTime rather than FixedUpdate w/fixedDeltaTime? the force you add should be constant either way (per given time)
It is wrong and you should just accept it. You should detect the inputs in Update and handle them in the fixed. Don't change stuff outside the physics loops. In the best case you are wasting processing, in the worst you are doing stuff that is related to the framerate (or worse).
The four liner as a one liner (to be packed in FixedUpdate since this is where the physics steps are happening): Rigidbody.velocity += Vector3.up * Physics.gravity.y * (Rigidbody.velocity.y < 0 ? (FallMultiplier - 1f) : (JumpMulitplier - 1f) * (UnityEngine.Input.GetButton("Jump") ? 0f : 1f)) * Time.fixedDeltaTime; Good Video btw!
I used this in the opposite, to reduce the effect of gravity. This lets the player glide a bit after the jump. rb.velocity += new Vector3(0, rb.velocity.y * Physics.gravity.y * 0.5f * Time.deltaTime, 0);
This is awesome! I've tried implementing jumping using Phaser (instead of Unity) in a web game, and ran into the same issue. The theory behind this still holds true and perfectly translates over. Thanks!
Nice work, I'd just separate the input in Update, hold the jump button state in a variable and do the physics in fixedupdate otherwise, you risk accelerating too much or too little depending on your frame rate. I'd also use AddForce with ForceMode.velocityChange instead of summing directly to the velocity, since that takes care of collisions in a better way avoiding you to go through things by directly setting the velocity vector.
Thanks for this video. From your implementation, I realized just now that you can have multiple scripts on a single object. This seems like a good way to augment the effects without having a huge character controller.
Holy crap man, I’ve been thinking of trying to recreate Mario World 1-1 as my first project to help me get a better grasp at game development and this helped me out a ton. Every time I wrote some form of jumping mechanic it felt too floaty and unmario like I just couldn’t wrap my head around it. As l was watching your video the ideas and solutions became clear to me. Thanks man.
Excellent analysis of Mario's jump and great video. Did you know this is even easier to implement in the latest version of Unity? Rigidbody2D components actually now have a gravity scale parameter which can be modified at runtime. Great stuff, huh?
Okay, your doing `v += gravity` in the jump and `v += gravity * multiplier` in the fall, but that equals: Jump: v += gravity + jumpHeld ? jumpAcceleration : 0 Fall: v += gravity And just a higher base gravity. You didn't want to add to the velocity in the jump (while jump held, add acceleration) and then spent a whole lot of time just rewriting the problem from a different reference frame. But in the end it's the same thing. Your adding a jump acceleration during the jump if the button is held, by manipulating the gravity afterwards. I suspect you will get a better correlation with marios jump if you just apply a force while the button is held anyways.
OMG Thank you sooooo much. This was just the video I was searching for a few hours now. I had two problems with my jumping and I was hoping it would fix maybe one of those. Not only it fixed both but your code is so simple and shot. You are my todays hero...
Really loved your explanation. I like how you explain the problem and then the solution. Then only give the codes and explaining further about the codes.
In my case, this was actually completely compatible with my current jumping script (stuff added to prevent jumping more than once in the air). All I had to do was slightly alter one line of code, and add another. Pretty fucking sweet. Thanks, mate.
People if you want to make a simple code for the character to jump only in the ground, use Raycasting instead of OnCollisionEnter, i used it and i reduced the amount of code significantly and got a better result
I use the following method to check whether my game character is standing on a solid object. I created the boolean field "grounded" so that the code can check for that to be true before adding any forces to the RigidBody2D. Others might need to change the 1.01 offset on the y position while 0.01 is an appropriate maximum distance for the raycast. void CheckGrounded () { RaycastHit2D hitInfo = Physics2D.Raycast (new Vector2 (transform.position.x, transform.position.y - 1.01f), Vector2.down, 0.01f); grounded = hitInfo.collider != null; }
The issue with your implementation is that when my character is walking up hill it triggers the condition of low jump and makes it very hard to walk up the hill, so maybe there needs to be some tighter condition checks for low jumping.
Hey thanks for the tutorial! Made my jumps a lot nicer, although I had to do some moving around for the "else if" statement as I had animations playing and such :)
Interesting and explained well. Also, I watched your Black Hole shader tutorial and loved it. There aren't really a lot of shader tutorials on RUclips for shader noobs like me. Could you please do more shader tutorials?
Harshit Dubey thanks! I'm honestly not that familiar with shaders myself; I would recommend checking out Making Stuff Look Good for Unity Shader tutorials, though I will try to do a Shader 101 video sometime in the future (just the very basics, like the class structure and some useful keywords)
All we have to do is to put a muncher on tracks and then use the red coin to change the memory into a state where it will overwrite it with a lit bob-omb
I wouldn't recommend directly modifying velocity (for this simple case). When the player/body reaches the highest point and velocity.y < 0.0f, you should apply additional (gravity) force downward (in FixedUpdate of course)
Mario's jump physics is pretty weird. (and complex.) Not only does he go up faster than down, but your rate of descent varies depending on whether you hold the button down or not. (as do other parameters of the jump) And of course, you have a large degree of air control. (now, contrary to what you might think, in reality you also have air control, but mostly over your angular momentum, less so over linear motion.) There's a lot of factors here that aren't based on reality...
Nice trick using gravity scale. This could benefit from some improvements: * no physics updates in update, use FixedUpdate (otherwise the physics is dependent on the framerate) * d̶o̶n̶'̶t̶ ̶m̶a̶n̶i̶p̶u̶l̶a̶t̶e̶ ̶v̶e̶l̶o̶c̶i̶t̶y̶ ̶d̶i̶r̶e̶c̶t̶l̶y̶,̶ ̶a̶l̶w̶a̶y̶s̶ ̶a̶p̶p̶l̶y̶ ̶f̶o̶r̶c̶e̶s̶ ̶(̶o̶t̶h̶e̶r̶w̶i̶s̶e̶ ̶y̶o̶u̶ ̶m̶i̶g̶h̶t̶ ̶g̶e̶t̶ ̶p̶r̶o̶b̶l̶e̶m̶s̶ ̶w̶i̶t̶h̶ ̶t̶h̶e̶ ̶p̶h̶y̶s̶i̶c̶s̶ ̶e̶n̶g̶i̶n̶e̶)̶
+knospi i always thought that Add.force is better used for bullet movements and lunching pads per example meanetime rb.velocity is suited for player movements
Because that would be a utterly disgusting hack that had unintended effects on the rest of the objects in the game? (I've never used Unity so maybe I'm wrong)
this was so helpful! thank you so much..i was always wondering how to achieve this effect..i knew what the other games did but didn't knew how they achieved it...it bothered me so much because i had that exact thinking problem you mentioned at 3:50...god damn why didn't i found that one out? :D thinking outside of the box at it's finest right here :D Thank you for finally solving that little mystery to me x)
I actually felt it wasn't that long. He first identified the problem, made a solution based on a talk, explained the solution and wrote the code. If he just wrote the code, it would have definitely be shorter, but then you would not have understood it as well, or at least less skilled programmers wouldn't
Well I mean he could have just told you what the code was and you could have copied it and learned next to nothing, but noting how impatient you seem to be, I doubt you learned much anyways.
I dont get how you change the velocity... if LowJumpMultiplier - 1 = 1, then youre setting the gravity to the same amount . It shouldnt affect anything!
It's not about how easy it is to type, it's about the actual meaning of the value. In order to multiply gravity by a certain amount, you have to subtract 1 from the multiplier to get what percent *more* gravity you need to add after the Unity engine already applies the gravity. The reason why we don't just subtract 1 in the first place is because the property would no longer have the same meaning; a multiplier of 1 implies that gravity would stay the same, but with your idea that would mean actually doubling the gravity. If you really wanted to, you could have the variable represent the percent change in gravity rather than the multiplier, but it's good practice to have consistency in your code that would make sense to anyone else reading your code.
@@technorazor976 yeah but what he says doesn't make sense anyway and those are just numbers he plugged in, he may think/mean he is doubling the gravity but he isn't. By subtracting 1 he is just multiplying it by 1 which makes the variable there redundant. Same with the 2.5, what he means is not what he is actually doing with the subtraction of 1. It's basic math...
MrScylesToYou The Unity engine already applies 1x gravity, so to double the gravity you have to add 1x the gravity to the velocity again, making 2x gravity total, get it?
MrScylesToYou Also, 2 and 2.5 were arbitrary numbers that he decided felt right. If you wanted to change them, you just have to change the number in the inspector. The variable isnt redundant, it's there to be potentially changed.
I solved this with a slightly different approach, by instantly cutting current upward velocity by a percentage if the player releases the jump button before reaching apex height. After some tweaking the result felt really good imo
iterate a counter every time the key is pressed and you could set a fixed number of mid-air jumps that reset again on floor collisions. you could have double jumps/glides etc with very little work. better than onStay() intersect methods.
Not to nitpick but gravity is not "per second" as stated at 09:53 but is actually an "acceleration" with the unit m/s2 or the rate of change in acceleration. When you multiply gravity by Time.deltaTime, you get the velocity change during the frame (unit m/s same as velocity).
Agreed. Changing the global gravity seems like a sledgehammer solution as it may cause some undesirable effects with other objects, possibly even NPCs. To be honest I'm curious why gravityScale is only for 2D rigidbodies, but whatever.
Another option for a platformer is to write the physics model for the character controller your self and if possible not using unity physics for that at all. Then you have the amount of control you actually need to make the character controller as snappy as possible. When you want to detect collision you use raycasts and other techniques to prevent him to go through wall. If you want him to push objects you apply velocities to other objects and so on.
This was very helpful, I don't even use Unity. I use Java with the LibGDX framework and I just applied the same idea of modifying the players gravity and it worked! 😄
I would solve this behavior by changing the gravity itself on the object during button press and when the button is released or started falling. (see gravityscale) Simple as... ;) The "floating" feeling also comes from the lack of animation. The subject should flatten a bit towards the ground just for a moment before lifting up (like accumulating inertia as a real human would do) and stretch during flight as per the vertical velocity. With these together there's a much satisfactory effect by the end of the day.
The only gotcha on gravityscale is the unity doesn’t support it for 3D rigidbodies, hence why we had to write our own. Agree that animation also helps a great deal with the feel of a jump.
Thanks! Great help to make the jump a lot better! There was no need to make this a whole new script, i just made it a new method inside my already existing script :)
I prefer the physically correct jump model, but I don't mind higher jumps with longer presses of the jump button. It's just a matter of getting the time when the jump button was first pushed and the time that button was released, limiting the maximum height, and then jumping on release.
Only caveat to that approach: most games set the expectation for the jump to start when jump is pressed, not released. Still a valid design choice, just may require adjustment on the player’s part.
At 3:50 you say "we could give him more velocity over time... but that leads to a weird acceleration feel" and then offer an "alternative" implementation that is functionally equivalent. Acceleration is change in velocity over time. Applying an upward velocity over a certain amount of frames is literally equivalent to changing the gravitational constant over that particular delta T. Changing the gravity constant after the jump button is let go of is mathematically equivalent to allowing the jump velocity to be distributed over a larger time step with some maximum cap after X amount of frames with the jump button held.
There's also the Smash Bros. way of doing short jumps, which is to have a jump-squat animation and check if the jump button is still being held at the end of it. It does make your character a bit weighty by comparison, which would be more ideal in 3D than 2D. In 2D you want a nice, fast jump so your strategy is perfect.
I think what it most imitates in the real world would be a jetpack-assisted jump. Instead of an instantaneous force giving you an upward velocity, you'd have a slight continuous force on your way up. This could make you rise slower than you fall. You could imagine a jet pack with just barely enough force to counter gravity. You could slowly rise with it and then fall back down at a quicker pace. The fact Mario can hold down his jump to go even higher I think only further emphasizes the jetpack-like nature of his movement.
That is only because gravity is different in Japan.
It's part of animation principles.You usually want to exaggerate weight, even if it's not realistic per se. It's more about how good it looks or feels.
Can confirm, I've been to Japan.
XD
lmao @@flamurgoxhuli6099
principles.You is a link XD @@mikeluna2026
Very nice explanation. Those who are taunting about video length. Please pay attention his explanation as they were detailed and he pointed the problems with usual unity script.
So keep up the good work dude. :)
Very nice tutorial.
A little optimization tip: You should multiply your scalars first and then multiply by the vector at the end, or use parenthesis to isolate your scalar multiplications, to avoid extra Vector2 creations.
Also, once you're satisfied with your gravity value you can cache Physics2D.gravity.y * (fallMultiplier - 1) and Physics2D.gravity.y * (lowJumpMultiplier - 1) to avoid this unnecessary math on Update.
Cheers!
can you give that as an example for all the beginners? It's too technically spoken. I tried implementing what you said but i break things
@@Gyozamang He means that if you like how your jump is looking, you can just calculate the gravity.y * (fallMultipilier - 1) or (LowJumpMultiplier -1) like done in the code and write it as one number so the program does not have to do this math which is unnecessary because it does it every frame. You could store the calculation in a variable or something like this and let it calculate in Start() so it doesnt do it every Frame. Except you want to change the multipliers during the game like through power ups or such things (dont ask me why you'd need to have a power up for falling faster... but let's say you were like on another planet and needed to fall faster or slower, then its probably better).
So to sum it up, you can store it in a variable in the beginning or, if it changes during one scene, you have to let it stay like it is in the video. Hope that helped
@@Gyozamang Bro just apply brakets around constants . Ex Vector2.up * (speed * factor * Time.deltaTime);
I'm still looking this video up every time I'm trying to make a 2D platformer. So simple and useful.
nice
samee
4 lines of code.
12 minutes 46 seconds = 766 seconds
=
0.005 lines/second
umm no...
191.5 seconds/line
Christian Sarmiento he did lines/second, you did seconds/line. They’re reciprocals. Do 191.5^-1. You’re both right
So just like real life programming?
#Procrastination
Programming is 4 minutes programming and 30 minutes thinking :D
@@rc0d3 correct. Very correct.
I have watched multiple tutorials for Unity, and all of them have been so confusing. Your video here has made so much sense to me. Thank you.
same i now it is 3 years ago you uploaded this but do you still code
@@Beanilikecheeeese I’ve since moved to Godot rather than Unity, but I still code with my favorite web languages. How come?
I don't know how RUclips knew I was having a problem with this but damn, exactly what I needed! Thanks so much!!
wow, rarely do I find code this comprehensible.
Good job explaining not only the code but also the whole jumpiness ^^
You're Awesome
I always thought the jump was weird, and I did the exact same things you said we would probably do. So thanks, this video was a godsend!!!
I've recently solved this problem in Godot 3 in a 3D platformer. I've implemented this differently - the player measures the time between the key press and release and there's a maximum afterburner time defined (about 0.5 s). During that time if the jump key is still depressed I apply additional upward velocity which ramps from 100% to 0% over the maximum afterburner time. This provides a very smooth and natural-looking yet expressive jump, it's pretty flexible to balance and doesn't mess with gravity
Thanks for this video, man, it helped me a lot. I saw the debate in the comments about the way you did it and I wanted to elaborate on the right way to implement this ideas. The thing with implementing acceleration in a simulation is that real life doesn't work in the same way: physics simulations work by taking little steps advancing in time, while time in real life is continuous; there are no steps.
It's actually very hard to know where an object is going to be in real life, even if you know it's velocity, acceleration and current position, because its velocity changes every instant. What we do in video games to aproximate that effect, where physics have to be calculated very fast, is to take as many little steps as we can in our simulation in time and sometimes we also try to retroactively interpolate the position based on current acceleration. It's enough, but it's not perfect.
So, the problem with doing the acceleration in the update is that, when the number of steps taken (the frame rate) is different, we end up with different positions. In this example, we end up with different short jump heights in different frame rates, which is not nice. So, here's what we can do:
We create an additional variable, a boolean for storing the state of the jump button, I'll call it jumpPressed. Then, in Update we only have:
void Update() {
if (Input.GetButtonDown("Jump"))
{
//there is no problem with changing velocity once in update,
//but addforce is better because it conserves momentum, so you can jump in an elevator
GetComponent().AddForce(Vector2.up * jumpVelocity, ForceMode2D.Impulse);
}
if (Input.GetButton("Jump"))
{
jumpPressed = true;
} else
{
jumpPressed = false;
}
}
Then in fixed update, we can do the same magic:
void FixedUpdate()
{
//Jump dynamics Code
if (rigid.velocity.y < 0)
{
GetComponent().velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.fixedDeltaTime;
}
else if (rigid.velocity.y > 0 && !jumpPressed)
{
GetComponent().velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.fixedDeltaTime;
}
}
And tada!
If you're multiplying by time.deltaTime in Update, why would you end up at different heights after x seconds depending on framerate?
@@endasil Because even though the acceleration is the same, the increments to the velocity would be distributed differently.
Imagine an object that accelerates by 30 meters per second each second. If the simulation was running at 30fps, the first frame the object would move with a velocity of 1, the second frame with a velocity of 2, and the third frame with a velocity of 3. After 1/10 of a second, it would have moved 6/30 of a meter.
Now imagine the simulation was running at 60fps. The first frame the velocity would be .5, the second frame 1, the third frame 1.5, the fourth 2, the fifth 2.5, and the sixth 3. After 1/10 of a second, the final velocity is the same, but the object will have moved 10.5/60 of a meter.
Should we really be modifying velocity directly or use forces? Won't forces added that frame be forgotten?
I think this works really well when you let the player decide when they want to fall faster. It makes you feel really in control of how you move. Great vid!!!
Thanks for the tutorial, well explained, without saying a bunch of extra unnecessary/not-quite-on-topic stuff!
This video is perfect for everyone. I'm a beginner in programming and even I could understand it easily. It is very optimised too.
Thanks! I could use it for my lil 3D isometric prototype and jumping feels so much better now!
Plzzz how did you do it ?? :)
How do you change the Physics2d.gravity ?
Thank you !
Absolutely incredible tutorial. so simple, was struggling to figure out why my jump felt "off", then finally found your video. Explanation was on point, very clear and well presented.
Wouldn't it be better if you placed the code in FixedUpdate instead of the regular Update, since you're tampering with the physics?
It's tricky. Because you're looking at Inputs, Update is preferable, but in general, when affecting physics, FixedUpdate is preferable. You'd probably want to do some optimization before shipping, but for getting you to a better jump feel quickly, I think this is OK in Update.
I would disagree, you should aim to NEVER change physics in Update. Changing the code is as simple as getting the button state in the Update() function and keep the result in a boolean. Then using that in FixedUpdate.
If it were adding force I would agree with you 100%, because you risk adding more or less force based on framerate, but setting the gravity to a flat value is a little less troublesome.
I know updating physics in FixedUpdate is considered best practice, but why would you be adding more or less force in Update w/deltaTime rather than FixedUpdate w/fixedDeltaTime? the force you add should be constant either way (per given time)
It is wrong and you should just accept it. You should detect the inputs in Update and handle them in the fixed. Don't change stuff outside the physics loops. In the best case you are wasting processing, in the worst you are doing stuff that is related to the framerate (or worse).
The four liner as a one liner (to be packed in FixedUpdate since this is where the physics steps are happening):
Rigidbody.velocity += Vector3.up * Physics.gravity.y * (Rigidbody.velocity.y < 0 ? (FallMultiplier - 1f) : (JumpMulitplier - 1f) * (UnityEngine.Input.GetButton("Jump") ? 0f : 1f)) * Time.fixedDeltaTime;
Good Video btw!
I used this in the opposite, to reduce the effect of gravity. This lets the player glide a bit after the jump.
rb.velocity += new Vector3(0, rb.velocity.y * Physics.gravity.y * 0.5f * Time.deltaTime, 0);
This is awesome! I've tried implementing jumping using Phaser (instead of Unity) in a web game, and ran into the same issue. The theory behind this still holds true and perfectly translates over. Thanks!
Nice work,
I'd just separate the input in Update, hold the jump button state in a variable and do the physics in fixedupdate otherwise, you risk accelerating too much or too little depending on your frame rate.
I'd also use AddForce with ForceMode.velocityChange instead of summing directly to the velocity, since that takes care of collisions in a better way avoiding you to go through things by directly setting the velocity vector.
Thanks for this video. From your implementation, I realized just now that you can have multiple scripts on a single object. This seems like a good way to augment the effects without having a huge character controller.
It sure is. It also allows you to swap features or abilities in and out dynamically without using extensive condition checking
Holy crap man, I’ve been thinking of trying to recreate Mario World 1-1 as my first project to help me get a better grasp at game development and this helped me out a ton.
Every time I wrote some form of jumping mechanic it felt too floaty and unmario like I just couldn’t wrap my head around it. As l was watching your video the ideas and solutions became clear to me. Thanks man.
Hi.
Do you know me?
I don't think so?
Scoin0
Oh it’s okay. I just want to make a friend .
This is going to come in handy SO MUCH, especially for game jams where I dont have time to program a non-physics based character controller.
Every time I see this type of video it makes me appreciate how genius Nintendo is for figuring this out decades ago, without an engine like Unity.
And they made it in Assembly x86!
the quality of this tutorial is so good
The best jumping tutorial I ever saw in the youtube it made my game even more realistic thanks
Board To Bits Games
It took a while to implement this for me (cause of the existing script) but man, jumping feels a whole lot better now. Thanks.
"Jump into the jump scrpit"
-Board To Bits Games 2017
I can't believe how many tutorials use timers for this, and the jump end up feeling robotic and boring. great video!
Excellent analysis of Mario's jump and great video. Did you know this is even easier to implement in the latest version of Unity? Rigidbody2D components actually now have a gravity scale parameter which can be modified at runtime. Great stuff, huh?
Ik it is 3 years later, but does the 3d rigidbody have a version of that now? If yes how would I use it?
@@book5257 hey there. So, I'm more of a 2D game developer. I don't really work with 3D very much. I also no longer use Unity. Best of luck, though!
@@tonyrigatoni766 it's ok. Thanks for replying though. I never expected a response this fast
Now this is a legendary video
Okay, your doing `v += gravity` in the jump and `v += gravity * multiplier` in the fall, but that equals:
Jump: v += gravity + jumpHeld ? jumpAcceleration : 0
Fall: v += gravity
And just a higher base gravity.
You didn't want to add to the velocity in the jump (while jump held, add acceleration) and then spent a whole lot of time just rewriting the problem from a different reference frame. But in the end it's the same thing. Your adding a jump acceleration during the jump if the button is held, by manipulating the gravity afterwards.
I suspect you will get a better correlation with marios jump if you just apply a force while the button is held anyways.
OMG Thank you sooooo much. This was just the video I was searching for a few hours now. I had two problems with my jumping and I was hoping it would fix maybe one of those. Not only it fixed both but your code is so simple and shot. You are my todays hero...
Wow, these comments are salty! Thanks for idea, I'm going to use it in UE4 :)
Really loved your explanation. I like how you explain the problem and then the solution. Then only give the codes and explaining further about the codes.
how to do this with the new input system? I'm having troubles trying to move and jump using 2D physics
I'm not using the built-in physics (I'm using raycasts) but this solution worked perfectly for my platformer. Can't thank you enough.
I love programming! There’s just something about creating the brain for an awesome project that makes me can’t wait for my future classes in coding
In my case, this was actually completely compatible with my current jumping script (stuff added to prevent jumping more than once in the air). All I had to do was slightly alter one line of code, and add another. Pretty fucking sweet. Thanks, mate.
People if you want to make a simple code for the character to jump only in the ground, use Raycasting instead of OnCollisionEnter, i used it and i reduced the amount of code significantly and got a better result
I use the following method to check whether my game character is standing on a solid object. I created the boolean field "grounded" so that the code can check for that to be true before adding any forces to the RigidBody2D. Others might need to change the 1.01 offset on the y position while 0.01 is an appropriate maximum distance for the raycast.
void CheckGrounded () {
RaycastHit2D hitInfo = Physics2D.Raycast (new Vector2 (transform.position.x, transform.position.y - 1.01f), Vector2.down, 0.01f);
grounded = hitInfo.collider != null;
}
and on what conditions do you set the grounded bool?
You can also just increase Gravity Scale on the Rigidbody. Pretty much same effect
The issue with your implementation is that when my character is walking up hill it triggers the condition of low jump and makes it very hard to walk up the hill, so maybe there needs to be some tighter condition checks for low jumping.
You can set a collider on the character, and make a "GroundCheck" script for it
such a simple fix but man does it ever make a difference. Great work!
Hey thanks for the tutorial! Made my jumps a lot nicer, although I had to do some moving around for the "else if" statement as I had animations playing and such :)
Genius!
Thank you, very much.
You solved one million problems on my brain and gave me a perfect gimmick to implement!
Interesting and explained well.
Also, I watched your Black Hole shader tutorial and loved it. There aren't really a lot of shader tutorials on RUclips for shader noobs like me. Could you please do more shader tutorials?
Harshit Dubey thanks! I'm honestly not that familiar with shaders myself; I would recommend checking out Making Stuff Look Good for Unity Shader tutorials, though I will try to do a Shader 101 video sometime in the future (just the very basics, like the class structure and some useful keywords)
no need anymore, really. download unity 2018 beta, it has visual node-based shader making, similar to UE.
I would have never thought my game would need this so bad... It feels 100x better
4:32 its actually suprisingly simple.
All we have to do is to put a muncher on tracks and then use the red coin to change the memory into a state where it will overwrite it with a lit bob-omb
Wow, I wasn't expecting a Ceave Gaming reference here xD
bruh
Rioni same here lol
Hey I know that reference
Works great!
Searched everywhere for something like this and somehow this popped up on my recommended page.
Creds to you m8!
None of my characters can jump. Still enjoyed learning this technique, thank you.
see if the massssss is tooo high lul mine was doing the reverse it fly for ever and als this progam let my char to jump multiple times
I wouldn't recommend directly modifying velocity (for this simple case). When the player/body reaches the highest point and velocity.y < 0.0f, you should apply additional (gravity) force downward (in FixedUpdate of course)
Mario's jump physics is pretty weird. (and complex.)
Not only does he go up faster than down, but your rate of descent varies depending on whether you hold the button down or not.
(as do other parameters of the jump)
And of course, you have a large degree of air control.
(now, contrary to what you might think, in reality you also have air control, but mostly over your angular momentum, less so over linear motion.)
There's a lot of factors here that aren't based on reality...
This video was so helpful! I used it to add to the Philippe St-Amand Kinematic Character Controller.
how does this work on the new inpute system
I've watched like 8 jump tutorials (brackeys, blackthornprod, code monkey and others) and yours is the best and most reasonable yet (Y)
The amount of views your getting is criminal, something this useful should be way higher.
+Jacob Luiten thanks!
Jacob Luiten you're*
I really enjoyed your detailed explanation on why those jumps feel more natural to us. Nice work!
Nice trick using gravity scale.
This could benefit from some improvements:
* no physics updates in update, use FixedUpdate (otherwise the physics is dependent on the framerate)
* d̶o̶n̶'̶t̶ ̶m̶a̶n̶i̶p̶u̶l̶a̶t̶e̶ ̶v̶e̶l̶o̶c̶i̶t̶y̶ ̶d̶i̶r̶e̶c̶t̶l̶y̶,̶ ̶a̶l̶w̶a̶y̶s̶ ̶a̶p̶p̶l̶y̶ ̶f̶o̶r̶c̶e̶s̶ ̶(̶o̶t̶h̶e̶r̶w̶i̶s̶e̶ ̶y̶o̶u̶ ̶m̶i̶g̶h̶t̶ ̶g̶e̶t̶ ̶p̶r̶o̶b̶l̶e̶m̶s̶ ̶w̶i̶t̶h̶ ̶t̶h̶e̶ ̶p̶h̶y̶s̶i̶c̶s̶ ̶e̶n̶g̶i̶n̶e̶)̶
what u mean by the second part, i shouldn't be using velocity for jumping?
Knospi So no using "rb.velocity += stuff;", huh? Is the safe way to use "rb.ApplyForce(0,stuff,0, ForceMode.velocity);"?
It's also used in unity documentation.
+knospi
i always thought that Add.force is better used for bullet movements and lunching pads per example
meanetime rb.velocity is suited for player movements
nah
Super helpful tutorial. I've still got some fine tuning to do, but it's massively better already.
"We can actually solve both of these things by manipulating one thing...Gravity". The movie. I fucking knew it, never that easy.
I know this is an old video, but it certainly helped to improve my jump. Thank you!
9:37
Why don't just scale the gravity? Rigitbody even have a variale for that
Because that would be a utterly disgusting hack that had unintended effects on the rest of the objects in the game? (I've never used Unity so maybe I'm wrong)
@@TheHuesSciTech No, you can set gravity scale for only one object beacose every object have it's own rigidbody2d component. Sorry for bad english. ^^
@@80ruta89 I stand corrected, thank you. Yours seems like a much more elegant solution with that in mind.
This is the most useful jump script I've seen so far.
Thank you very much
this was so helpful! thank you so much..i was always wondering how to achieve this effect..i knew what the other games did but didn't knew how they achieved it...it bothered me so much because i had that exact thinking problem you mentioned at 3:50...god damn why didn't i found that one out? :D thinking outside of the box at it's finest right here :D
Thank you for finally solving that little mystery to me x)
Happy to help!
Great Video!
I think it could have been shorter but the clear explanations are great too.
This Adds so much To Game Feel and Movement
12 minutes 4 lines of code
More than 4
I actually felt it wasn't that long. He first identified the problem, made a solution based on a talk, explained the solution and wrote the code. If he just wrote the code, it would have definitely be shorter, but then you would not have understood it as well, or at least less skilled programmers wouldn't
Would "take these 4 lines and think for yourself why" be a better video?
Beginner here, thought the video was of good length. :)
Well I mean he could have just told you what the code was and you could have copied it and learned next to nothing, but noting how impatient you seem to be, I doubt you learned much anyways.
I dont get how you change the velocity... if LowJumpMultiplier - 1 = 1, then youre setting the gravity to the same amount . It shouldnt affect anything!
This is good and all but why would you just not make the multipliers 1.5 and 1 instead of having an extra step of subtracting 1 anyway
It's not about how easy it is to type, it's about the actual meaning of the value. In order to multiply gravity by a certain amount, you have to subtract 1 from the multiplier to get what percent *more* gravity you need to add after the Unity engine already applies the gravity.
The reason why we don't just subtract 1 in the first place is because the property would no longer have the same meaning; a multiplier of 1 implies that gravity would stay the same, but with your idea that would mean actually doubling the gravity. If you really wanted to, you could have the variable represent the percent change in gravity rather than the multiplier, but it's good practice to have consistency in your code that would make sense to anyone else reading your code.
@@technorazor976 yeah but what he says doesn't make sense anyway and those are just numbers he plugged in, he may think/mean he is doubling the gravity but he isn't. By subtracting 1 he is just multiplying it by 1 which makes the variable there redundant. Same with the 2.5, what he means is not what he is actually doing with the subtraction of 1. It's basic math...
MrScylesToYou The Unity engine already applies 1x gravity, so to double the gravity you have to add 1x the gravity to the velocity again, making 2x gravity total, get it?
MrScylesToYou Also, 2 and 2.5 were arbitrary numbers that he decided felt right. If you wanted to change them, you just have to change the number in the inspector. The variable isnt redundant, it's there to be potentially changed.
I solved this with a slightly different approach, by instantly cutting current upward velocity by a percentage if the player releases the jump button before reaching apex height. After some tweaking the result felt really good imo
4:31 "...show the what's actually surprisingly simple code..."
My brain: Hears Ceave Gaming: "The answer is *surprisingly simple!*"
This videos was made 6 years ago, and it's still the bes
There's a big problem here. If you keep clicking and letting go of the space bar over and over again you can jump forever.
Do a downward raycast to check if your player is grounded before jumping is allowed
I have points on the bottom of my character that check if they intersect with the ground.
iterate a counter every time the key is pressed and you could set a fixed number of mid-air jumps that reset again on floor collisions. you could have double jumps/glides etc with very little work. better than onStay() intersect methods.
you need add GROUND CHECK for your player
Just check if the player is colliding with the ground with OnCollisionEnter2D(), u might have to play with tags depending on what way u do it
Not to nitpick but gravity is not "per second" as stated at 09:53 but is actually an "acceleration" with the unit m/s2 or the rate of change in acceleration. When you multiply gravity by Time.deltaTime, you get the velocity change during the frame (unit m/s same as velocity).
its not working 4 me
Great tutorial, helped me 6 years after release
you can just use gravityScale of rigitbody for this in 1 line of code
That's what I thought he was gonna do when he started talking about changing gravity XD
Good point! However, you do still need the other lines to cover which gravityScale to apply; but it is a much cleaner approach.
Agreed. Changing the global gravity seems like a sledgehammer solution as it may cause some undesirable effects with other objects, possibly even NPCs. To be honest I'm curious why gravityScale is only for 2D rigidbodies, but whatever.
So many unity tutorials in RUclips leave you with a gajillion errors. This is nice and clean...fixedupdate
What you described had nothing to do with "lines of code".
thanks! this seems like a pretty clean way to do variable jump height
I can write an entire game in 1 line of code...
Yes but that line could be very long (and depending on how your game is complex). An entire game in one line is possible but not practical at all.
print("Hello, world!");
private void Update()
{
UpdateGame();
}
private void UpdateGame()
{
// GAME CODE HERE
}
You can't do that because of #include ....
Beat me to it
Another option for a platformer is to write the physics model for the character controller your self and if possible not using unity physics for that at all.
Then you have the amount of control you actually need to make the character controller as snappy as possible. When you want to detect collision you use raycasts and other techniques to prevent him to go through wall. If you want him to push objects you apply velocities to other objects and so on.
Sebastian Lague has a great series on that approach!
was never a fan of mario 1's jump arc
i play a lot more of castlevania
no air movement gang
@@pedroribeiro9746: i'm fine with either tbh
mario 1's arc does bother me even compared to other marios
General rule of thumb:
Emulation > Simulation for player controls, and often other game elements too.
"Better Jumping in Unity With Four Lines of Code" - 12 minute video
This was very helpful, I don't even use Unity. I use Java with the LibGDX framework and I just applied the same idea of modifying the players gravity and it worked! 😄
4 lines of code in 12 minutes...
I would solve this behavior by changing the gravity itself on the object during button press and when the button is released or started falling. (see gravityscale) Simple as... ;) The "floating" feeling also comes from the lack of animation. The subject should flatten a bit towards the ground just for a moment before lifting up (like accumulating inertia as a real human would do) and stretch during flight as per the vertical velocity. With these together there's a much satisfactory effect by the end of the day.
The only gotcha on gravityscale is the unity doesn’t support it for 3D rigidbodies, hence why we had to write our own. Agree that animation also helps a great deal with the feel of a jump.
12 minutes for four lines, what the fuck is going on?
This is exactly what i've been looking for. Thanks man
Thanks! Great help to make the jump a lot better!
There was no need to make this a whole new script, i just made it a new method inside my already existing script :)
its super good but how do i set a max falling speed so when i jump down a cliff in the game i dont after a little while go super fast
I prefer the physically correct jump model, but I don't mind higher jumps with longer presses of the jump button. It's just a matter of getting the time when the jump button was first pushed and the time that button was released, limiting the maximum height, and then jumping on release.
Only caveat to that approach: most games set the expectation for the jump to start when jump is pressed, not released. Still a valid design choice, just may require adjustment on the player’s part.
@@BoardToBitsGames Then the idea is to make the jump control very time-sensitive to minimize the perceived delay.
Awesome, and simple thanks a lot :) were making a Platformer for our very first game project at University
At 3:50 you say "we could give him more velocity over time... but that leads to a weird acceleration feel" and then offer an "alternative" implementation that is functionally equivalent. Acceleration is change in velocity over time. Applying an upward velocity over a certain amount of frames is literally equivalent to changing the gravitational constant over that particular delta T. Changing the gravity constant after the jump button is let go of is mathematically equivalent to allowing the jump velocity to be distributed over a larger time step with some maximum cap after X amount of frames with the jump button held.
There's also the Smash Bros. way of doing short jumps, which is to have a jump-squat animation and check if the jump button is still being held at the end of it. It does make your character a bit weighty by comparison, which would be more ideal in 3D than 2D. In 2D you want a nice, fast jump so your strategy is perfect.
I think what it most imitates in the real world would be a jetpack-assisted jump. Instead of an instantaneous force giving you an upward velocity, you'd have a slight continuous force on your way up. This could make you rise slower than you fall.
You could imagine a jet pack with just barely enough force to counter gravity. You could slowly rise with it and then fall back down at a quicker pace.
The fact Mario can hold down his jump to go even higher I think only further emphasizes the jetpack-like nature of his movement.
I will keep this in mind when I start learning Unity next week
Thank you for helping me introduce a smooth jump into my puzzle game
I had always wondered why the jumping in my games felt so wrong, thanks for this!