Really solid ground detection
So, as per usual, ground detection is always tricky as you as the developer need to choose between making something ‘solid’ and relatively ‘expensive’ or creating something that is okayish and ‘cheap’.
Usually, we use Raycasts to shoot a ray down and see if there is ground underneath, but this is just a single ray, and it's imprecise when talking to ground detection in character movement. Raycast is made for small objects for example bullet collision checking or raycast shooting.
That's all good but how do we check for the ground then?
Well, there is a number of different options, from collider boxes set as a trigger, shooting X number of rays in raycast, box casts, etc. but for a solid ground detection, we should use something like boxOverlap or sphereOverlap. Essentially this will tell unity to overlap a fictional trigger at our desired position, and the fun thing is — we can control it using code.
First things first
We need to set a few variables starting with LayerMask for our ground layers aka what's walkable, Vector3 for our offset (this is optional but its recommended) and floats for sphere radius and threshold
Also, some private variables such as float for ground angle and Vector3 for sphere position
Setup
The next part is actually declaring and setting up everything. First, create a private void CollisionCheck( ) or whatever do you want to call it and add it to Update( ).
In CollisionCheck( ) function create an array of colliders called colliders
After that, we need to set our sphere position and we will set it as transform position + our Vector3 offset (if you do have it)
Actual ground check
Using our colliders array we’ll do Physics.OverlapSphere and we will pop in our sphere position, sphere radius, and ground layers.
Processing that data
Using if statement with parameter (colliders.Length == 0) we can set that player is not grounded
Now, if our collider array actually has colliders in it we use for each loop to check each of them. We are searching for each Collider named col in our array colliders
Using temporary Vector3 collider position set to col position
Next, now we need to calculate what is our ground angle so we don't consider vertical slopes as ground aka seeing walls as ground. We start by setting our ground angle float to be Vector3 angle between sphere position and collider position. This will return a value in Rad between our two vectors.
Now we check if the ground is in our acceptable values and if yes then we set grounded to true. The coding part is done! Here is my complete function if you are stuck.
Now in Unity, we need to set values for our variables.
Inside Unity
Add this script to the player. On the ground layers player mask, we select everything except player layer.
You can play with values a bit but here are some values that work for me
Hope this helps! :)