- Home /
Character motor ground detection problems
I'm using a script to control the player character, who has a rigidbody. I don't want to use the standard character controller because it doesn't work with a rigidbody, and I want forces to interact with the player.
The issue is that I have been unable to find a reliable method to see if the player is on the ground or not.
One approach I've tried is to simply a isGrounded bool that is set to false whenever the player jumps, and is set to true whenever the player collides with anything with the OnCollisionStay method. However, this has poor results. Since isGrounded will be set to be true if anything at all is in contact with the player, the player is able to jump up walls, as long as the player maintains contact with the wall. Additionally, since the isGrounded bool is only set to false when that player jumps, if they player falls of something without jumping, they will be able to jump once in midair.
Another approach I tried is to use raycasting to set the isGrounded bool. I raycasted in Vector3.down direction and the length of slightly more than half of the player's height every frame. When it contacted anything, I set isGrounded to true, and otherwise set it to false. This had poor results as well. Since the ray cast is a 2 dimensional line, if the player is touching the ground, but not directly where the ray cast is, for example if the player is on the edge of a cliff, isGrounded will be false, resulting in the player being unable to jump. Additionally, since they raycast goes slightly below where the player touches the ground, sometimes isGrounded will not immediately be set to false when the player jumps, since they player hasn't been jumped far enough away from the ground yet. This can result on the player jumping again on the next frame, making jumps be higher than they should be. I tried modifying the ray casting approach to include multiple ray casts in different areas on the bottom of the player. However, I cannot have an infinite number of ray casts, so there are still situations where the player wasn't able to jump. It also doesn't solve the problem of multiple jumps.
Another problem I have is that the player cannot jump while in contact with a wall, likely due to the friction between the player and wall. This can be prevented by making the player be a very low friction material. However, doing so would make the player have low friction towards everything, which would cause the player to slide down hills.
Another approach could be to use the standard character controller, but somehow simulate physics with it. This sounds like a very convoluted approach, and I doubt the results would be very good, although I have yet to try it.
So how can I fix these issues? Any advice would be appreciated.
Also, the Unity Answers gods have been smiting me, resulting in me being unable to comment on anything. Because of this, I need to post new answers in order to reply to anything.
Cheers.
Answer by iwaldrop · Dec 25, 2013 at 10:55 PM
Check this page. Not only does Aldo provide some source, a second answer by Setsuki suggests that doing a Capsulecast solved his problem of uneven ground which I think address your standing on the edge of a cliff problem.
As for the problem of jumping against walls, using different PhysicMaterials for the walls and floors should allow jumping while against a wall to 'feel' as you desire it.
Answer by Kyth'Pth3hk · Dec 26, 2013 at 05:29 PM
Thank you for the suggestion. When I tried it, it didn't work.
My first approach of using it was to perform a capsule cast starting at the bottom of the player, and ending at 0.1f below the bottom. This resulted in isGrounded being true every frame. It likely returned true every time because the capsule cast started at the very bottom of the player, and therefore intersects with them.
To fix the first approach, I tried was to have the capsule cast start 0.01f below the player, so that it wouldn't come in contact with them. This resulted in the capsule cast always returning true. I am unsure of why, but it may be because the capsule cast may actually begin slightly above the Vector3 inputted for the start of the capsule cast, so as to give the capsule it's domed top.
In order to fix this, I tried making the beginning of the capsule cast further below the player, in order to compensate for the domed top. This resulted in the capsule cast always returning false when on flat terrain. The reason why is likely because the capsule cast doesn't hit the terrain, since when the player is on the flat terrain, the terrain's collider under the player is directly touching the player. Since the capsule cast starts slightly below the player, it misses the terrain.
A solution to this would be to have the capsule cast only return true if the collider it intersects with is not the player. However, since capsule casting only returns a bool, and no information on the collider, I don't know how I could implement this approach. I don't know how the poster in the other topic managed to get it to work. Do you have an suggestions?
TLDR: The capsule cast returns true every time because it intersects with the bottom of the player.