Proper Way to Implement Jump for Character

Hi, I am currently trying to add a jump function to my “PlayerMovement” script. It works fine as far as jumping goes, but I noticed that I can jump on things that I shouldnt be able to(sides of walls, for example)

I know that it has to do with the OnCollisionStay and Exit functions, but I cant figure out what to replace them with to make it work, I have had to resort to using a tag to forbid the player from being able to jump on certain objects, but it makes things more of a hassle than anything

Here is my code! Any help would be greatly appreciated! Thanks again!

var direction : Vector3 = new Vector3(0,0,0);
var Speed : float = 0.0;
var gravity : float;
var jumpSpeed : float;
var letJump = false;
var letMove = true;
var jumpSound : AudioClip;
var target : Transform;

function Jump()
{
	if(letJump)
	{
		if (Input.GetKey(KeyCode.Space))
			{	
				audio.PlayOneShot(jumpSound);
				rigidbody.AddForce(0, jumpSpeed, 0);			
			}
	}
}

function OnCollisionStay(other : Collision)
{
	if(other.gameObject.tag == "NoJump")
	{
		Debug.Log("Cant Jump Here!");
		letJump = false;
	}
	
	if(other.gameObject.tag != "NoJump")
	{
	letJump = true;
	}
}

function OnCollisionExit(col : Collision)
{
	letJump = false;
}

function Update()
{
	if (letMove == true)
	{
		direction.x = Input.GetAxis("Horizontal");
		direction.z = Input.GetAxis("Vertical");
	}
	
	direction.Normalize();
	rigidbody.AddForce( direction * Speed );

	direction.y -= gravity * Time.deltaTime;
		
	if(Input.GetButtonDown("Jump"))
	{
		Jump();
	}
	
	if(Input.GetButtonUp("Jump"))
	{
		direction.y -= gravity;
	}

}

As far as I understood you, you want to jump only if the user presses the space bar and some ground is under the avatar.

In this case, you should send a Ray on the negative Y axis (Vector3.down), to check if it collides with something. If yes, then the avatar is on or near the ground and may jump.

You can controll the maximum distance from the ground through the rayDistance.
For help with rays, check this article.

Greetings
Chillersanim

If you just want to make sure you can only jump of non-vertical surfaces you are colliding with, you can check the collision point normals:

collision.contacts

to get the contact points, then:

contactPoint.normal

to get the normals. You can get an average if there are multiple points, or just require a single point to be facing up to allow a jump etc.

However there are a number of issues with using collisions in this way. You may be close but not quite touching the ground so the collider isn’t triggered, even though the player thinks they should be able to jump. There may be multiple collisions (ground + wall) that will fight over the let_jump flag.

These issues can be worked around, but overall you’re probably better off doing something like the downwards raycast as suggested by others. You can still check the normals of the raycast collision in case ‘down’ isn’t directly down, or if you only want to jump if the angle is < 45 degrees etc. You will need to limit the range of the ray to ensure it doesn’t go below your character (with a small amount of tolerance), and you could also use SphereCast with a small radius to ensure you don’t have near misses. You can do the ‘cast’ from the center of the player, or one cast from each foot etc.

I can’t answer your question with code examples but have you considered ray-casting downward from your character? Then you’d know if there is something “below” the character. This might prevent you jumping off of walls and things that are to the side of you.