Why does my character can't touch the terrain?

Now I am writing a control code, and my code doesn’t use the Velocity that some tutorials used. It use character.transform.position and change it to move character. It works well, but when I begin applying gravity, the character fall through the terrain, even I used the controller.isGrounded, it fall off the terrain. I have checked it already, like this:

if (!controller.isGrounded)

{print(“In air”); character.transform.position.y -= 3;}

else print (“On ground”); // and some stuff to disable the gravity

And, when I play, the character fall off, and the console screen only show “In air” message, that mean the Unity’s isGrounded doesn’t work correctly.

My terrain has a terrain collider, my character has rigibody, CharacterController and my own script. There are no trigger is ticked, I checked it. And I disable Unity’s default Gravity in Rigibody, I use my own gravity code (like above). That is my status now.

Could you please help me? Thank you for reading.

I believe your controller is just falling to fast to even register the collision.

You are subtracting 3 units per frame, so from one frame to the next, your character could have gone entirely through the terrain, and it would never detect a collision.

Try smoothing your transform

character.transform.position.y -= 3 * Time.deltaTime;

like so, and you should be fine.

First, start with following EVERY step in this post:

It’s my holy grail reference if I run into the problem of things falling through the ground.

If the problem is still there then it’s probably your method of grounding your character. I’m going to assume that your Rigidbody is just there for collision detection. If not, and there’s physics involved then transform.position updates are never going to work nicely with a character controller added.

Can I suggest you handle gravity and ground detection along these lines?
Don’t use .IsGrounded, use your own script that does something like this (untested code! may work):

C# code - assumes root of your characters GameObject is at the base (not in the middle);

  int Gravity = 3;
    if(!CustomIsGrounded && HigherThanGravity)
    {
      print("In air"); character.transform.position.y -= Gravity;
    }
    
    if(CustomIsGrounded)
    {
      //onground code
    }
    
    if(!CustomIsGrounded && !HigherThanGravityUnit)
    {
      float groundHeight = Terrain.activeTerrain.terrainData.GetHeight(character.transform.position.x, character.transform.position.z);
      print("In air"); character.transform.position.y = groundHeight;
    }
    
    
    private bool CustomIsGrounded()
    {
      // Use your rigidbody to detect for a collision with the ground, or check that your character position.y = groundHeight.  There's lots of examples in answers for these.
    }
    
    // If the character is less than 1 unit of "Gravity" off the ground, then return false;
    private bool HigherThanGravityUnit()
    {
      float groundHeight = Terrain.activeTerrain.terrainData.GetHeight(character.transform.position.x, character.transform.position.z);
    if((character.transform.position.y - groundHeight) < Gravity)) return false;
        return true;
        }

Or if you are happy to make slightly bigger changes, change gravity to apply over time (multiply by Time.deltaTime), and this will smoothly drop your character to the ground instead of stepping it down in large increments. It will also alleviate the need for the “HigherThanGravityUnity” code.

Thank you everyone. Now I know why. You were right, my character “fall” too fast, or you can say that is not “falling”, that is “teleporting”. I changed the code, like this:

character.transform.position.y -= 3 * Time.deltaTime/const;

First, I choose the const to be 10, and it work! So I reduced it, and the smallest value make the code’s right is 7.

You helped me a lot, thank you very much. I hope I can see you later.

try
if(!controller.isGrounded)
{print(“in air”); character.transform.position -=3;}
else
{print(“on ground”)}