Custom Controller Gravity Woes, It weighs heavy...

On this controller I am making, and everything seems to be progressing.
But no matter what I do gravity is pulling me down.
I noticed it fully when I am swimming.

I explicitly turn it off but it still seems to pull me down. Even if it is off.
Messing with mass/drag seems to have no effect.
Messing with isKinematic of course makes me fall.

I am using a mechanim controller with 2d motion, overridden with swim / crouch blendtrees
apply root motion is on.

Any ideas as to what I am not getting/understanding here?

using UnityEngine;
using System.Collections;

namespace DeadWorld.ControllerSystem
{
    [DisallowMultipleComponent]
    [RequireComponent(typeof(Rigidbody))]
    [RequireComponent(typeof(Animator))]
    [RequireComponent(typeof(CharacterController))]
    public class CharController : MonoBehaviour
    {

        [Header("Controller States")]
        [SerializeField]
        private LocomotionType _locomotionType = LocomotionType.Standard;
        public LocomotionType LocomotionType
        {
            get => _locomotionType;
            set => _locomotionType = value;
        }
        [SerializeField]
        private ControllerState _controllerState = ControllerState.Locomotion;
        public ControllerState ControllerState
        {
            get => _controllerState;
            set => _controllerState = value;
        }
        [SerializeField]
        private CharacterStance _characterStance = CharacterStance.Standing;
        public CharacterStance CharacterStance
        {
            get => _characterStance;
            set => _characterStance = value;
        }

        [Header("Movement Checks")]
        [SerializeField]
        private bool _isRunning = false;
        public bool IsRunning
        {
            get => _isRunning;
            set => _isRunning = value;
        }

        [SerializeField]
        private bool _isJumping = false;
        public bool IsJumping
        {
            get => _isJumping;
            set => _isJumping = value;
        }

        [Header("Water Settings")]
        public float maxDistanceToWater = 10;
        [ReadOnly] public float actualDistanceToWater = 0f;
        public LayerMask waterLayer;
        [SerializeField]
        private bool _inWater = false;
        public bool InWater
        {
            get => _inWater;
            set => _inWater = value;
        }
        private bool _wasWater = false;

        [Header("Ground Settings")]
        public float groundCheckDistance = .3f;
        [ReadOnly] public float _actualDistanceToGround = 0f;
        public LayerMask groundLayers;
        [SerializeField]
        private bool _isGrounded = true;
        public bool IsGrounded
        {
            get => _isGrounded;
            set => _isGrounded = value;
        }

        [Header("Movement Amounts")]
        [SerializeField]
        private float _forwardMovement = 0.0f;
        public float ForwardMovement
        {
            get => _forwardMovement;
            set => _forwardMovement = value;
        }
        [SerializeField]
        private float _directionalMovement = 0.0f;
        public float DirectionalMovement {
            get => _directionalMovement;
            set => _directionalMovement = value;
        }
        [SerializeField]
        private float _updownMovement = 0.0f;
        public float UpDownMovement {
            get => _updownMovement;
            set => _updownMovement = value;
        }

        [HideInInspector]
        public Rigidbody rigidBody;
        [HideInInspector]
        public Animator animator;
        [HideInInspector]
        public CharacterController charCollider;
        [HideInInspector]
        public Transform leftFoot;
        [HideInInspector]
        public Transform rightFoot;
        [HideInInspector]
        public Transform hips;
        [HideInInspector]
        public Transform head;
        [HideInInspector]
        public Transform chest;


        [Header("Miscellaneous Info")]
        [ReadOnly] public float _originalCapsuleHeight;
        [ReadOnly] public Vector3 _originalCapsuleCenter;
        [ReadOnly] public bool _animatorInitialized = false;

        public GameObject InteractionPoint;
        private bool _halfColliderSet = false;

        const float K_HALF = 0.5f;

        void Start()
        {

            InitializeController();
            CheckStates();

        }

        void InitializeController()
        {
            if (_animatorInitialized)
            {
                return;
            }

            //Get Components
            rigidBody = GetComponent<Rigidbody>();
            animator = GetComponent<Animator>();
            charCollider = GetComponent<CharacterController>();

            rigidBody.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ | RigidbodyConstraints.FreezeRotationY;

            _originalCapsuleHeight = charCollider.height;
            _originalCapsuleCenter = charCollider.center;

            ////Get Animator Bones for collider, for later
            leftFoot = animator.GetBoneTransform(HumanBodyBones.LeftFoot);
            rightFoot = animator.GetBoneTransform(HumanBodyBones.RightFoot);
            hips = animator.GetBoneTransform(HumanBodyBones.Hips);
            chest = animator.GetBoneTransform(HumanBodyBones.Chest);
            head = animator.GetBoneTransform(HumanBodyBones.Head);

            _animatorInitialized = ValidateController();
            animator.SetBool("Initialized", _animatorInitialized);

        }

        bool ValidateController()
        {
            return rigidBody != null && animator != null && charCollider != null && InteractionPoint != null;
        }
        void Test()
        {
            //CharacterController c;

        }

        private void Update()
        {
            //InitializeController();
        }

        void FixedUpdate()
        {
            CheckStates();
            ScaleCapsule();
            SetAnimatorOnUpdate();
            MoveUpdown();
        }

        void SetAnimatorOnUpdate()
        {
            animator.SetInteger("ControllerState", (int)ControllerState);
            animator.SetInteger("CharacterStance", (int)CharacterStance);

            animator.SetBool("IsGrounded", IsGrounded);
            animator.SetBool("IsRunning", IsRunning);
            animator.SetBool("IsJumping", IsJumping);

            animator.SetFloat(Inputs.FORWARD, ForwardMovement);
            animator.SetFloat(Inputs.ROTATE, DirectionalMovement);
            animator.SetFloat("Updown", UpDownMovement);
        }

        void CheckStates()
        {
            CheckIsSwimming();
            CheckIsGrounded();
        }


        void MoveUpdown()
        {
            if (CharacterStance == CharacterStance.Swimming)
            {
                if (UpDownMovement < 0)
                    transform.position += Vector3.down * Mathf.Abs(UpDownMovement) * Time.deltaTime;
                else if (UpDownMovement > 0)
                    transform.position += Vector3.up * Mathf.Abs(UpDownMovement) * Time.deltaTime;
                else
                {
                    //rigidBody.velocity = Vector3.zero;
                    //rigidBody.angularVelocity = Vector3.zero;
                }
            }

        }

        void ScaleCapsule()
        {
            if ((CharacterStance == CharacterStance.Crouching
                || IsJumping)
                && !_halfColliderSet)
            {
                charCollider.height = _originalCapsuleHeight / 2f;
                charCollider.center = _originalCapsuleCenter / 2f;
            }
            else
            {
                charCollider.height = _originalCapsuleHeight;
                charCollider.center = _originalCapsuleCenter;
                _halfColliderSet = false;
            }
        }

        void CheckIsSwimming()
        {
            Color waterRayColor = Color.blue;

            Vector3 startPos = gameObject.transform.position + Vector3.up;

            //Debug.DrawRay(startPos, Vector3.up * maxDistanceToWater, waterRayColor);

            RaycastHit hit;
            if (Physics.Raycast(startPos, Vector3.up, out hit, maxDistanceToWater, waterLayer))
            {
                if (hit.collider.tag == "Water")
                {
                    InWater = true;
                    actualDistanceToWater = hit.distance;
                }
                else
                {
                    InWater = false;
                    actualDistanceToWater = 0;
                }
            }
            else
            {
                InWater = false;
            }


            if (InWater && CharacterStance != CharacterStance.Swimming && _wasWater == false)
            {
                CharacterStance = CharacterStance.Swimming;
                rigidBody.useGravity = false;
            }
            else if (!InWater && CharacterStance == CharacterStance.Swimming && _wasWater == true)
            {
                CharacterStance = CharacterStance.Standing;
                rigidBody.useGravity = true;
            }

            _wasWater = InWater;
        }

        void CheckIsGrounded()
        {

            Color groundRayColor = Color.green;
            Vector3 startPos = transform.position;
            Vector3 dir = transform.position + (Vector3.down * groundCheckDistance);

            //Debug.DrawLine(startPos, dir, groundRayColor);

            RaycastHit hit;

            //Debug.DrawLine(transform.position + (Vector3.up * 0.1f), transform.position + (Vector3.up * 0.1f) + (Vector3.down * groundCheckDistance), Color.green);

            if (Physics.Raycast(transform.position + (Vector3.up * 0.1f), Vector3.down, out hit, groundCheckDistance, groundLayers))
            {
                IsGrounded = true;
                _actualDistanceToGround = hit.distance;
            }
            else
            {
                IsGrounded = false;
                _actualDistanceToGround = 0;
            }
        }
    }
}

Hello,
I’m not quite sure and haven’t tested, but here are a few observations

• Try putting _wasWater above the if checking its value.

• It seems you’re checking water above your character (Vector3.Up)

if (Physics.Raycast(startPos, Vector3.up, out hit, maxDistanceToWater, waterLayer))

• Is there a parent RigidBody with useGravity = true?

Sorry I don’t help you more, I’m testing it better as soon as friday if nobody else found your issue.

I believe that what I have accurately detects water. The problem is gravity. even when that is off it sinks. And the only place I am turning it of is where and when I detect the water.

The water plane AQUAS has a collider which is above the character at this point.

It was the CharacterController, switched back to RigidBody and CapsuleCollider and gravity works fine. I’ll have to rework the Step Climber script but hey. Gravity > Steps so… progress? :stuck_out_tongue:

Aah Gravity. Always pulling you down.
In a sense I’m reassured it comes from somewhere else because I couldn’t find anything wrong with your script.
Now, even if gravity is a simple force vector pointing down in the perspective of the ground, your RigidBody may help you with other things. I hope fixing your StepClimber won’t be too much of a hassle :slight_smile: Good job so far so I believe you’ll be fine :wink: