Raycast is a physics procedure, which essentially traces a line out from a source in a specified direction, and determines what it is touching. You can write a Raycast like this:
if(Physics.Raycast(sourceVector, directionVector, out h, distance))
This looks reasonably complex, but I’ll walk you through it. The first line creates a temporary object that you can use to store a bunch of information about the intersection point, if you need it (this is pointless if you just want to know whether or not it will hit something, but that’s not what you want). Next, we have an if statement. The method
Physics.Raycast will return
true if it hits something, and
false if it doesn’t. This is useful, because it allows you to run code only when a collision occurs (when you can be sure of having collision information). To run this method, you need to define the start point, the direction of the ray, and the distance it will travel. You also need to tell it where to store the collision information, which is the argument I have written as
out h. The
out here is very important, as it labels the argument as being one that will change as a result of the method call.
So, how can we apply this to your problem? First of all, you need to decide the source, direction and distance of your Raycast. A good starting point for the source will be your player’s position, so
transform.position works nicely for that argument. Secondly, you need a direction. Now, since you’re rotating your player, you can’t just use
Vector3.down, because that will give incorrect results when your player rotates more than a few degrees. Instead, you want to use the local down vector of your player, to detect what is at the player’s feet. Transform objects don’t have a
transform.down vector, but since down is always in the opposite direction from up, you can just use
-transform.up, and that deals with the direction. Next you need to decide on the distance from your player to detect ground. This is entirely up to you, but keep in mind that longer Raycasts are more expensive, computationally, while one that is too short may not work correctly (because it will stop before it detects the ground).
Now we know how to describe the Raycast, we need to deal with the result. Fortunately, we have all the information stored in the variable
h. The first thing to do is find out what the Raycast has detected. To do this, you can set a “tag” on the colliders of the objects you want the player to collide against. You can then add to the end of your if statement:
if(Physics.Raycast(sourceVector, directionVector, out h, distance) && h.collider.tag == "Tag")
Where Tag is the name of the tag your object has set. This ensures the following code will only react to the objects you want it to. Now, the two things you want to do are to move the player to the collision position, and to rotate the player away from the ground. You can do this in numerous ways, but the key part is that you can get exactly the information you need from the collision information. The two properties you need to read from this are
h.normal. The first of this gives the world space coordinates of the collision point (which will be a point on the surface of your collider), the second gives the world space direction of the “normal” vector to the collider surface. This is a vector pointing directly away from the surface.
Using this information, you can set the position of your player relative to the
hit.point. That will move your player to the collision point. The next part, the rotation, is a little more awkward. Perhaps the simplest thing to do is to just set the transform’s up vector, like this:
transform.up = h.normal;. This will work, but may end up with your player facing in strange directions on other axes. What you actually want to use is
Quaternion.LookRotation. This allows you to get a rotation, given the desired forward vector of the object. We obvious can’t apply h.normal directly, but we can calculate the desired forward vector, by taking the existing forward vector, and excluding any components in the direction of the collision normal. This will give up a forward vector similar to the current one, but at a right-angle to the new normal vector. Fortunately, this is very easy, as the Vector3 structure has a method built into it called
Vector3.Exclude. You can use this method like this:
Vector3.Exclude(h.normal, transform.forward), and this will give you your desired forward vector. So now all we need to do is apply that to
Quaternion.LookRotation, which is quite easy:
transform.rotation = Quaternion.LookRotation(Vector3.Exclude(h.normal, transform.forward), h.normal);
This should align your player to the ground, and rotate them accordingly.
Please note that I haven’t personally tested this code, and it will have bugs in it. I posted this here not to give you the code, but hopefully to explain the methodology behind solving a problem such as this, and hopefully you’ll be able to understand and solve the problem with this information.