- Home /
Force Of Jump Determined By Collision.Contacts
Hey guys, I'm a tad stuck here, I need some guidance on how to go about making my jump force be directly associated with the angle of the wall it's bouncing off of.
I have the angles right, using contacts.normal, but when it's bouncing off of say a 45 degree slope, it will have the same force it's using when it jumps upwards, which isn't what I want since on flat ground, it's fighting against gravity, so it only goes so high, but it's only half gravity effect when jumping from a slope.
So what I need is to be able to have my variable called 'jumpDistY' to vary depending on the angle it's jumping from, so if it's on 45 degrees I only want about half strength, if it's 90 degrees I want it to only be about 10-20% of it's total strength.
And every degree in-between should be covered somehow, because I will be creating levels that have varying degrees of slopes so it needs to be able to work on all degrees.
Here is what I have for my jumping and collisions so-far:
void Update()
{
if (Input.GetButton("Jump") && canJump)
{
canJump = false;
GetComponent<Rigidbody>().AddForce(normalDirection* jumpDistY * Time.deltaTime);
}
}
void OnCollisionStay(Collision theCollision)
{
if (theCollision.gameObject.tag == "Ground")
{
onGround = true;
canJump = true;
normalDirection = theCollision.contacts[0].normal;
}
}
If you might know how I could achieve this I'd very much appreciate it, thank you!
Answer by Metastable · Nov 20, 2015 at 07:40 AM
Well you have the normal so all you really need is to get the magnitude of it in the y direction (0, 1, 0), or Up. We know that normals have a magnitude of 1 so you could just do normalDirection * normalDirection.y. This gets you partially there because when the normal is Up (0, 1, 0) you'll be multiplying by 1 and when the normal is pointing right/left or horizontal the y component will be 0 and thus give you no jump distance. Depending on what you're looking for beyond 45 degrees you could just normalize your jump force such as (.6 * normalDirection.y) + .2 which will give you half strength at 45 degrees because y will be .5, so .6 * .5 = .3, and then add in the extra 20 percent, .3 + .2 = .5, and give you just 20 percent at 90 degrees when the y component is zero. This of course doesn't cover every case because when the floor is completely flat you'd only get 80% full force.
I see, that's a very good idea, thank you, I'll give the first part a shot, but I'm confused on how I might intuitively set 20% for say the 90 degree angle, would you know what function I could use to achieve this?
Thanks for the answer too, I really appreciate it!
Answer by rutter · Nov 20, 2015 at 07:02 AM
Most likely you'll need to start with a function like Vector3.Angle or Vector3.Dot to compare against Vector3.up
.
For example, you could use lerp to create a linear falloff as the angle approaches 90 degrees:
float angle = Vector3.Angle(Vector3.up, normalDirection);
angle = Mathf.Clamp(angle, 0f, 90f);
//angle between 0 and 90, so express it as ratio from 0 to 1
float jumpPerc = angle / 90f;
float jumpForce = maxJumpForce * jumpPerc;
rigidbody.AddForce(normalDirection * jumpForce, ForceMode.Impulse);
That's relatively simple.
Some developers like to compare vectors using dot products. The dot product of vectors will range from 1 (same direction) to 0 (perpendicular) to -1 (opposite direction). This is handy when you need to check if one character is looking at or away from another character.
For any two vectors A
and B
with angle theta
between them, the dot product is a float that equals |A| * |B| * cos(theta)
. Since we're comparing unit vectors, here, the dot product is really giving us cos(theta)
. That's handy because it's a smoother falloff:
float jumpPerc = Vector3.Dot(Vector3.up, normalDirection);
float jumpForce = maxJumpForce * jumpPerc;
rigidbody.AddForce(normalDirection * jumpForce, ForceMode.Impulse);
The math behind this method is a bit more complex to understand, but it's simpler and more consistent in practice.
You can use anything along those lines. Once you've got a jumpPerc
from 0 to 1, there are plenty of mathematical functions you could use to modify the jump strength -- you just need to find one that suits your needs!
Hey thanks a lot, that's an extremely detailed answer, I really appreciate that!
So what you're saying is I could use either one of those code block principals to get this to work?
This is a lot to wrap my head around, the last code option you wrote looks a bit easier to understand, I think I get it, but what would I need a math function for? (I assume you mean a $$anonymous$$athf.something, right?)
Happy to help!
Either code block should work -- I prefer the second one, personally, but if one works for you over the other, they're both viable.
As far as the extra math function, that mainly matters if you want to manipulate the relationship between angle and jump force. $$anonymous$$aybe you're happy with the output as-is, or maybe you want to make the difference more dramatic.
For example, this would make vertical jumps much stronger, and horizontal jumps much weaker, while still keeping both jumps within the power range you've already set:
//numbers from 0 to 1 are interesting
//if you multiply them together, the result stays between 0 and 1
//consider the curve x^2 from 0 to 1, for example
jumpPerc = jumpPerc * jumpPerc;
Programmers often use a whole bunch of "interpolation" functions to work on these sorts of values. It's a subtle design thing, but it gives you a lot of control.
Am I supposed to set a float of jumpPerc up above the Update functions as a specific number, or do I just have it set as you've got it already?
Because it's really weird at the moment, using the second method the wall doesn't give any force at all, but it didn't change anything for angles in-between 0 and 90.
I wonder if I'm doing things correctly though (most likely not given my history), since I can jump on a platform that's say 5 ball lengths wide and if I'm on say the bottom 66.7% of it, it will be a really powerful jump (2x regular it seems) but if I'm just towards the edge, in about the top 33.3% of it, it will give me a nice small jump like I want it.
I think this was happening even before applying your code method too though.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Kicking object with random direction and force 2D 0 Answers
[C#, 2D] How do I apply force to a player using vector 3 velocity to move 1 Answer
Problems with velocity 0 Answers