- Home /
Unity 5 - how to add a double jump to the default third person controller script ?
Hey, I've been trying to add a double jump to Unity's default third person controller script for a couple of days now with no success. I've tried to create a boolean to state that double jump is true after performing a normal jump and then false after the double jump but It ends up allowing me to jump and an infinite amount of times, I've also tried the counter method which ended with the same result. I'm going to assume I'm just missing something pretty obvious. but I was just wondering if anyone had a snippet that I could use if they have managed to achieve this I would be very grateful. Or even a bit of advice on something I may be missing. Thanks for your time.
Answer by Loui_Studios · Jan 28, 2017 at 02:59 PM
Ok. Here's a little walkthrough of how to add a simple double jump to the default third person character.
OK. So let's start disecting the third person character!
Open up ThirdPersonCharacter.cs and ThirdPersonUserControl.cs.
Firstly, you'll need to scan through the code and look for where the jump code starts, if you're lucky, there'll be a Jump() method, which makes things very easy. Otherwise, try hitting CTRL + F and searching for "grounded" or "ground". There should be a boolean that states whether the character is touching the ground or not. We can use this to narrow down where the jump code starts.
At line 46 I found the Move() method, which takes in a vector from the user and then moves them in that direction.
Inside the method is this code, which points to another method:
if (m_IsGrounded)
HandleGroundedMovement(crouch, jump);
And inside the HandleGroundedMovement() method, there's also this code:
// check whether conditions are right to allow a jump:
if (jump && !crouch && m_Animator.GetCurrentAnimatorStateInfo(0).IsName("Grounded")) {
// jump!
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
But finally, there's one more thing that should be modfied to achieve the double jump. In the ThirdPersonUserControl.cs script, you'll see that in a simple Update() loop there's an IF statement that detects jump input:
private void Update() {
if (!m_Jump)
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
}
In a nutshell, this script detects user input and then feeds it into the ThirdPersonCharacter.cs script.
So at the top of this code, underneath m_Jump, add a public integer called "jumpState". This will count the amount of jumps we have done in midair. Since it's public, we can also see it in the inspector. Useful for debugging.
public int jumpState;
What we will do is we will have the jumpState integer set to how many jumps you have done in midair. When jumpState goes over a limit, you can no longer jump in the air.
Ok so let's get this code to work. Modify the Update() loop to look like this:
private void Update() {
if (!m_Jump) {
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
if (m_Jump)
jumpState++;
}
if (m_Character.m_IsGrounded)
jumpState = 0;
}
Now open up the ThirdPersonCharacter.cs code and add this argument to the Move() method:
int jumpState = 0
So now the Move() method should look like this:
public void Move(Vector3 move, bool crouch, bool jump, int jumpState = 0) {
Then go back to the ThirdPersonUserContro.csl script, and in the FixedUpdate() loop, add this argument to the line that calls the move function. So now that line should look like this:
m_Character.Move(m_Move, crouch, m_Jump, jumpState);
Finally, go back into ThirdPersonCharacter and make the m_IsGrounded variable public. Like this:
public bool m_IsGrounded;
Now if you test the scene, you should notice that the value of jumpAmount sits at 0 when the character is touching the ground, and when you jump in mid air, that value increases.
Now to make the character jump in mid air!
So in the ThirdPersonCharacter.cs script, go down to the move function and add this line just before the if (m_IsGrounded) statement:
if (jump == true && jumpState < 2) {
HandleGroundedMovement(crouch, jump);
}
Lastly, go down to the HandleGroundedMovement() method, and remove the animation check there, so now it will look like this:
void HandleGroundedMovement(bool crouch, bool jump) {
// check whether conditions are right to allow a jump:
if (jump && !crouch) {
// jump!
m_Rigidbody.velocity = new Vector3(m_Rigidbody.velocity.x, m_JumpPower, m_Rigidbody.velocity.z);
m_IsGrounded = false;
m_Animator.applyRootMotion = false;
m_GroundCheckDistance = 0.1f;
}
}
If done correctly, you will be able to jump a second time in mid air! To increase the number of jumps the character can do in mid air, just increase the number '2' here:
if (jump == true && jumpState < 2) {
HandleGroundedMovement(crouch, jump);
}
If you want to, you can link this number to a variable and then have an upgrade system, or an on screen counter for how many jumps you have left.
Hope this helped. Let me know if the code works for you!
If not, just comment, and I'll help you sort it out!
Thank you so much, you guided me through it perfectly. I realised my mistake was that I wasn't putting it within the User Controls update thank you for all your help.
You're welcome. I'm glad I helped you out! :)
I was just wondering, I understand if you don't want to help me any further, but I am attempting to change it so I can allow movement mid-air as I'm creating a 3D platformer. I handle all the combat in a separate script but currently, it makes the platfor$$anonymous$$g part a bit hard I've been reading through and adjusting the script for a couple of hours trying to get it to work. it's most likely me missing something obvious.
Thanks for helping me out again I've manage to make a lot of progress since inputting the double jump :)
Someone can correct me if I'm wrong, which I probably am, but isn't the default Ethan animations root motion? That means the animations themselves control how he moves and because the falling animation doesn't move it's only controlled by physics at that point which is why he would continue moving but you can't change velocity/direction.
I'd think you should be able to disable the falling animation so he stays in the on-ground state (in the Animator window) and then you just need to be sure that you're still checking for player input and still moving him normally even though he's in the air. Although with doing that, it would look like he's just standing as he's falling through the air. Would take more code and Animator stuff to keep him in the falling animation if you're done moving.
Again, could totally be off the wrong track.
@Ramsden Yes, cryneryan is indeed right.
The default third person character uses root motion to handle movement. Its handled from this method here:
public void OnAnimator$$anonymous$$ove() {
// we implement this function to override the default root motion.
// this allows us to modify the positional speed before it's applied.
if (m_IsGrounded && Time.deltaTime > 0) {
Vector3 v = (m_Animator.deltaPosition * m_$$anonymous$$oveSpeed$$anonymous$$ultiplier) / Time.deltaTime;
// we preserve the existing y part of the current velocity.
v.y = m_Rigidbody.velocity.y;
m_Rigidbody.velocity = v;
}
}
You'll have to remove this method and set m.Rigidbody.velocity yourself.
@Simply$$anonymous$$elee Hey, Sorry to bother you again but I gave your code a go and I couldn't really make it work, the character was floating above the map and I tried some code changes to the code, $$anonymous$$or changes in full honesty but I couldn't get it to work. As mentioned before I'm not the best of coders but I am slowly picking it up.
I was wondering if there was any chance of a hand with the mid-air movement as the default controller works great in every other aspect, and this would be the last change I would need to make for it.
Sorry to bother you once again :(
@Simply$$anonymous$$elee Hi, sorry to bother you but I downloaded the test scene you (the one with the capsule + cowboy hat) and am wondering how can I modify it so that when I turn from side to side, the character rotates as well? Like how when we walk and turn we actually turn to face the we're walking.
You have been a great help though thank you so much!
Answer by KaizerGoreng · Jul 14, 2017 at 02:55 AM
@SimplyMelee Hi, sorry to bother you but I downloaded the test scene you (the one with the capsule + cowboy hat) and am wondering how can I modify it so that when I turn from side to side, the character rotates as well? Like how when we walk and turn we actually turn to face the we're walking.
You have been a great help though thank you so much!
That's not too hard to do. There are a few ways you can do this.
Firstly, you'll need a motion vector. This motion vector is created at the bottom of the script for your convenience:
Vector3 motion = new Vector3(horizontal * horizontalSpeed, jumpSpeed, forward * forwardSpeed); // Take our information and put it into a movement vector.
Afterwards, you'll simply want to adjust your character's y rotation using Quaternion.FromToRotation to calculate the difference between the current direction you're facing and the target direction.
A quick example:
float angleY = Quaternion.FromToRotation(transform.forward, motion).y;
then simply add that rotation to your current y rotation and you should be good.
You may feel like reordering the code a bit so that all of the rotation code happens in one place, rather than in two different parts of the script, and it should work functionally the same. Infact, it's more optimised to batch transformations in that way.
Hey thanks for the fast reply!
I tried and did as you said, but I do not think it works how it should be. I replaced the "rot" Quaternion's y parameter from transform.rotation.y to angleY.
Am I doing it correctly?
Vector3 motion = new Vector3(horizontal * horizontalSpeed, jumpSpeed, forward * forwardSpeed); // Take our information and put it into a movement vector.
// If we move, set the rotation to the direction of the camera.
if (horizontal != 0 || forward != 0)
{
// Set our rotation to the camera's
transform.forward = cam.transform.forward;
float angleY = Quaternion.FromToRotation(transform.forward, motion).y;
//Correct the rotation so that the character is only rotated in the Y axis.
Quaternion rot = new Quaternion(transform.rotation.x, angleY, transform.rotation.z, transform.rotation.w);
rot.x = 0; rot.z = 0;
transform.rotation = rot;
}
Ah, my mistake. I'm not too well versed in quaternion math, and I'm still learning the functions as best I can.
I find it hard to explain what it is that I mean to say, so I'll show you the code that I'm using for one of my projects right now to get the AI enemies to rotate to face their target.
Vector3 rot = transform.eulerAngles;
rot.y += Quaternion.FromToRotation(transform.forward, aiBase.target.position - transform.position).eulerAngles.y;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rot), Time.deltaTime * aiBase.reference.turnSpeed);
In your case, I think the problem is caused by the motion vector being relative to the player's local coordinates and not their world space coordinates, so the player could end up facing a point near to the center of the map depending on their speed.
For this we will want to use:
transform.TransformDirection(motion);
to convert the motion vector into world coordinates for us to use.
Try that out first, and let me know how it works for you. Feel free to use the code example I gave you in your project, or as a reference to help with the scripting.
Also, check out the documentation for Quaternion.FromToRotation() and transform.TransformDirection().
https://docs.unity3d.com/ScriptReference/Quaternion.FromToRotation.html
https://docs.unity3d.com/ScriptReference/Transform.TransformDirection.html
Your answer
Follow this Question
Related Questions
Unity Asset Prefab Bug ThirdPersonController (left rotating bug / Snapping forward Always) 3 Answers
I need help with sliding in infinite Runner please someone help 1 Answer
Help! How do we enable or disable Collider with a specific action? 2 Answers
Third Person Controller Movement on Elevated Terrain 1 Answer
make Ethan (from unity standard assets) like temple run character 0 Answers