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
}
}
Answer by Resdin · Mar 04, 2017 at 08:19 PM
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.