Raycast fall detection and issues with .isGrounded,

Good afternoon. First time asking a question here and first time working with the animator state machine. Thank you in advance.

  1. Get to the edge of a rigid body / collider, the character will get stuck playing the falling animation and not fall or register an infinite fall; seems the characterController collider gets stuck no matter the skin width. Usually if the char is jogging this will not occur and he will fall and land perfectly, it usually happens while walking - particularly walking at angles less than / greater than 90 degrees (holding two keys? ex W,D). If I move the character in scene view he will fall but sometimes will still be stuck in the falling animation or it will not play the landing animation. I tried the relevant fixes I found on google but none worked.

  2. While crouching and moving, my raycast detects the character as falling. Even the charactercontroller .isGrounded registers being ungrounded. You’ll see in the code where I have stepped through the fall detection using the debug log. I have looked at the collider in play mode and everything looks fine, although the collider does not shrink to match the character which I would like to also resolve but that is for later.

Anyway to improve the accuracy / efficiency of this code? Should I do fall detection from a different script? Any advice would be greatly appreciated. It’s currently in my movement script attached to the player rather than a separate fall detection script.

I’ve made two state machines, one which controls the character out of combat, and one while in combat – “unlockedMachine” and “lockedMachine” respectively.

void Start () { //I have also put this in Awake()
		var dist = 0f; 
		GetHitDistance (out dist); 
		initialDistance = dist; 
	}
		bool GetHitDistance (out float distance){ 
			distance = 0f;
			Ray downRay = new Ray (transform.position, -Vector3.up); //cast a downward ray
			if (Physics.Raycast (downRay, out hit)) { //if the ray collides
				distance = hit.distance; //store the distance
				return true; //return true, that the ray has collided
			}
			return false; // else return false
		}
	void Update () //I have put this into FixedUpdate, did not help.
	{
		Vector3 cameraForward = new Vector3 (cameraPivot.forward.x, 0.0F, cameraPivot.forward.z).normalized;
		Vector3 cameraRight = new Vector3 (cameraPivot.right.x, 0.0F, cameraPivot.right.z).normalized;
		Vector3 movement = new Vector3 (Input.GetAxisRaw ("Horizontal"), Input.GetAxisRaw ("Vertical"), 0.0F);

		var dist = 0f;
		if (controller.isGrounded) {
			Debug.Log ("registering as grounded");
			/*UnlockedMachine*/
			if (anim.GetBool ("locking") == false) { //if you are not locked on
				if (Input.GetKeyDown (KeyCode.LeftShift)) { //if you press left shift
					if (anim.GetBool ("sprint") == true) { //if you are sprinting
						anim.SetBool ("sprint", false); //turn sprint to false
						anim.SetBool ("moving", false); //stop the character from sprinting
					} else {							//else
						if (anim.GetBool ("run") == true) { //if the character is running
							anim.SetBool ("sprint", true); //then the player should sprint
							anim.SetBool ("run", false); //stop the character from running
						} else {						//else
							if (anim.GetBool ("run") == false) { // if the character is not running
								anim.SetBool ("run", true); // make him run
							}
						}
					}
				}
				if (anim.GetFloat ("DirectionY") == 0 && anim.GetFloat ("DirectionX") == 0 && anim.GetBool ("sprint") == true) {
					anim.SetBool ("sprint", false); //if the char is not moving reset the sprint bool
				}

				if (anim.GetFloat ("DirectionY") == 0 && anim.GetFloat ("DirectionX") == 0 && anim.GetBool ("run") == true) {
					anim.SetBool ("run", false); //if the char is not moving reset the run bool
				}
				if (Input.GetKeyDown (KeyCode.C)) { //if you press C
					if (anim.GetBool ("crouch") == false) { //if you are not crouching
						anim.SetBool ("crouch", true); //crouch
					} else {						  //else
						if (anim.GetBool ("crouch") == true) { //if you are crouching
							anim.SetBool ("crouch", false); //turn crouch off
						}
					}
				}

			} else { //you must be locked on
				anim.SetBool ("locking", true); //locking true
				anim.SetBool ("run", false); //cannot run
				anim.SetBool ("sprint", false); //cannot sprint
			}

			/*LockedMachine*/
			if (anim.GetBool ("locking") == true) { //if you are locked on
				rotationDamp = .2f; //reduce rotation damping to increase the speed of aiming between targets
				if (Input.GetKeyDown (KeyCode.C)) { //if the player presses C
					if (anim.GetBool ("crouch") == false) { //if the player is not crouching
						anim.SetBool ("crouch", true); //make the player crouch
					} else {						 //else
						anim.SetBool ("prone", true); //make the player go prone
						anim.SetBool ("crouch", false); //and turn off crouch
					}
				}
				if (Input.GetKeyDown (KeyCode.X)) { //if the player presses X
					if (anim.GetBool ("prone") == true) { //and prone is true
						anim.SetBool ("crouch", true); //set crouch true
						anim.SetBool ("prone", false); //set prone false
					} else {							//else
						if (anim.GetBool ("crouch") == true) { //if crouch is true
							anim.SetBool ("crouch", false); // turn crouch off
						}
					}
				}
			} else {                         //else
				anim.SetBool ("prone", false); //turn prone off
				rotationDamp = .5f; //return rotation dampening to normal
			}
		} else {
			Debug.Log ("Registering a Fall");
			if (GetHitDistance (out dist)) { //if the raycast has hit something
				Debug.Log ("Step1");
				if (initialDistance < dist) { //if the distance is greater than 0
					Debug.Log ("Step2");
					var relDistance = dist - initialDistance;//deltatime? Get relitive distance Distance from ground - initial distance
					if (relDistance > fallingThreshold) { //if the distance is greater than the fall sensitivity set above register a fall
						Debug.Log ("Step3");
						if (relDistance > maxFallingThreshold) { //will you take damage?
							Debug.Log ("Step4");
							//Fall dmg or sounds here
							isFalling = true; //falling is true
							anim.SetBool ("falling", true);//change animator state
							anim.SetBool ("locking", false);//change animator state
							anim.SetBool ("crouch", false);//change animator state
							anim.SetBool ("prone", false);//change animator state
							anim.SetBool ("run", false);//change animator state
							anim.SetBool ("sprint", false);//change animator state
							anim.SetBool ("landing", false);//change animator state
						} else { 
							Debug.Log ("Step5-Landing");
							anim.SetBool ("landing", true);//very short fall, skip fall animation and play landing animation
							anim.SetBool ("falling", false);//change animator state
							isFalling = false; //flip the falling bool
						}
					}
				}
			} else {
				Debug.Log ("Infinite Fall");//else there is no ground
			}
		}
//regular movement detection here as well as target locking removed to save space
}

void LateUpdate(){
	if (!isFalling) {
		anim.SetBool ("landing", false); // to reset the landing bool to false after landing
	}
}

After more testing, I have found the issue with the slow / unreliable transitions was due to improper state machine transition settings in the animator.

I still have the issue where the CharacterController gets stuck on edges instead of falling and that the raycast and .isGrounded register a fall while crouching and moving so any help directed at those issues would be very helpful. I will edit the main question to reflect that.