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!

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.

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!