Trouble with correcting "sinking issue"

Hi all!

I’m pretty new to coding, and I’m trying to practice some concepts by making a character controller. Right now I’m trying to write a method for “gravity” to translate the character downward. I’m running into an issue where the character is indeed falling, but it always happens where the character is partially in the ground. I’m not sure why this is, but I thought I would remedy this by shooting another ray up from the pivot point of the character, get that distance, and move the character up as needed.

Here’s what I’ve got (please go easy on me ;), I’ve been commenting a lot of this stuff for my own education:
Please see the Gravity() method

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/*
* This class is a basic third person character controller
*
* ASSUMPTIONS - READ THIS BEFORE USING
* 1) Character has a transform component at the bottom center - For future reference, box collider for cat has center @ 0, 1.75, 0, Size is 1.5, 3.5, 5
* 2) Character has two speeds: not moving, and moving
* 3) Character will be running around a scene that is made up of objects with basic colliders
* 4) Character will have a camera script applied on it separately
*/

public class ThirdPersonCharacterController : MonoBehaviour
{
    // Setting up our variables for this controller
    #region Variables
    // public variables available in the Unity inspector
    [Header("Speed")]
    public float moveSpeed;
    public float rotationSpeed;

    [Header("Physics & Collisions")]
    public float gravity;
    public float jumpStrength;
    public BoxCollider characterEnvelope;

    [Header("Surface Control")]
    public float slopeClimbSpeed;
    public float slopeDescendSpeed;

    [Header("LayerControl")]
    public LayerMask discludePlayer;

    // private variables manipulated only within this script
    private bool grounded;
    private float jumpHeight = 0F;
    private Vector3 sensorOneCoordinate;
    private Vector3 moveTranslationValue;
    private Vector3 turnAngularValue;
    #endregion

    /*
     * This built-in Unity method initializes any components required that belong to the character
     */
    private void Start()
    {
        characterEnvelope = GetComponent<BoxCollider>();
    }

    /*
     * This built-in Unity method simply calls a series of functions to populate the position information of this character frame-by-frame, and then drives the characters' position
     * Rotation
     * UpDown (Vertical) Position
     * ForwardBackward (Horizontal) Position
     * driveCharacter
     */
    private void Update()
    {

        updateRotation();
        Jump();
        Gravity();
        updateForwardBackwardPosition();
        driveCharacter();
    }

    /*
     * This method updates the sensor location attached to the character transform by "moving" it relative to the character transform
     */
    private void updateSensorLocation()
    {
        sensorOneCoordinate = transform.TransformPoint(0F, 0.4F, 1F); // set the sensor coordinate to 0 units (x), 0.4 units (y), and 1 unit (z) relative to the character transform
    }

    /*
     * This method updates the rotation vector of the character
     */
    private void updateRotation()
    {
        turnAngularValue.y = Input.GetAxis("Horizontal") * rotationSpeed; // set the rotation about the Y-axis by the user input for "A" & "D" scaled by the rotation speed
    }

    /*
     * This method checks to see if the user is grounded, and if not, pulls the character back down to the ground
     */
    private void Gravity()
    {
        RaycastHit hit = retrieveRayCastHit(sensorOneCoordinate, Vector3.down, Mathf.Infinity, Color.blue);

        if (hit.distance < 0.45)
        {
            grounded = true;
            moveTranslationValue.y = 0;

            RaycastHit neededRaise = retrieveRayCastHit(transform.position, Vector3.up, Mathf.Infinity, Color.black);
            print(neededRaise.distance);
            moveTranslationValue.y += neededRaise.distance;

        }
        else
        {
            grounded = false;
            moveTranslationValue.y -= gravity;
        }
    }

    /*
    * This method updates the vertical position based on if the user decides to jump or not
    */
    private void Jump()
    {

        if (grounded)
        {

        }
        else
        {

        }
    }

    private void updateForwardBackwardPosition()
    {
        moveTranslationValue.z = Input.GetAxis("Vertical") * moveSpeed;
        retrieveRayCastHit(sensorOneCoordinate, transform.forward, 1F, Color.red);
    }

    private void driveCharacter()
    {
        transform.Translate(moveTranslationValue);
        transform.Rotate(turnAngularValue);
        updateSensorLocation();
    }

    private RaycastHit retrieveRayCastHit(Vector3 rayStartCoordinate, Vector3 rayDirection, float detectionDistance, Color rayColor)
    {
        Ray ray = new Ray(rayStartCoordinate, rayDirection); // send out a ray from the specified start in the direction specified by the argument
        Debug.DrawRay(rayStartCoordinate, rayDirection * 20, rayColor, 0.4F); // draw the ray (with specified color) in the scene view. elongate it by a factor of 20, and make it stay there for 0.4 seconds
        RaycastHit hit; // Create a container to catch the raycast hit

        if (Physics.Raycast(ray, out hit, detectionDistance, discludePlayer)) // if our ray hits something at a length of <= than our detection distance (not including the child objects of our player)
        {
            return hit; // return the information of the object we hit (i.e the wall details)
        }

        return hit; // return the information of the object we hit (i.e the wall details)
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawSphere(sensorOneCoordinate, 0.2F);
       
    }
}

I attached an image of what I’m seeing!

It is saying the neededRaise.Distance = 0 in Unity… so something funky is happening with the ray for sure. I just can’t figure it out. Been doing a lot of youtubing and searching the Unity documentation :frowning:

Thanks in advance!
Cheers!

Your code looks good to me. Are you sure that the transform origin is at the bottom of your model, and not (say) in the middle?

The pivot point/transform of the model is located at the bottom of the character. I verified this by drawing the ray from the transform of the model. I had a thought that maybe the ray was hitting the collider of the model (which I realize I need to remove anyway, it’s not being used), but that shouldnt be the case, because I’m applying a layerMask on the ray to exclude the “player” layer, which is applied on the model object.