// Update is called once per frame
	void Update () {
        //grab the forwards vector for when the body is facedown (crawl state)
        Vector3 crawlForwardVector = findForwardCrawlVector();
        //Debug.DrawRay(body.transform.position, crawlForwardVector * 5f, Color.green);

        if (Input.GetKeyDown(KeyCode.I))
        {
            if(!bigBossMode)
            {
                bigBossMode = true;
                print("Invincibility Mode ACTIVATED!");
            } else
            {
                bigBossMode = false;
                print("Invincibility Mode DE-ACTIVATED!");
            }
        }

        if(currState == movementState.run || (inCrouchMode && currState == movementState.crawl) || currState == movementState.sneak)
        {
            if (Input.GetKeyDown(KeyCode.W))
            {
                print("Triangle Button: FPV Cam"); 
                FPVModeControl = true;
                CameraController.S.SwitchCameraTo(CameraType.fpv);
            }
            if (Input.GetKeyUp(KeyCode.W))
            {
                FPVModeControl = false;
                CameraController.S.SwitchCameraTo(CameraType.overhead);
            }
        }

        Vector3 vel = Vector3.zero;
		if (Input.GetKey (KeyCode.UpArrow)) {
			vel.z += 1;
		}
		if (Input.GetKey (KeyCode.DownArrow)) {
			vel.z -= 1;
		}
		if (Input.GetKey (KeyCode.LeftArrow)) {
			vel.x -= 1;
		}
		if (Input.GetKey (KeyCode.RightArrow)) {
			vel.x += 1;
		}

        if(HandController.S.isFighting || HandController.S.isFighting || FPVModeControl)
        {
            vel = Vector3.zero;
        }

        // begin of FPV mode control
        GameObject fpvcamera = CameraController.S.cameras[(int)CameraType.fpv];
        if (FPVModeControl)
        {
            //controls for FPV mode
            if(Input.GetKey(KeyCode.UpArrow))
            {
                Quaternion rot = Quaternion.Euler(-45f, 0f, 0f);
                fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, rot, .05f);
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                Quaternion rot = Quaternion.Euler(45f, 0f, 0f);
                fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, rot, .05f);
            }

            if (Input.GetKey(KeyCode.LeftArrow))
            {
                lastFPVForward = (new Vector3(0f, -FPVRotationSpeedDeg, 0f));
            }
            else if (Input.GetKey(KeyCode.RightArrow))
            {
                lastFPVForward = (new Vector3(0f, FPVRotationSpeedDeg, 0f));
            }
            else
            {
                if (timeTillTurnUpdate <= 0)
                {
                    lastFPVForward *= FPVRotationDecel;
                }
            }

            if (timeTillTurnUpdate > 0)
            {
                timeTillTurnUpdate -= Time.deltaTime;
            }
            else
            {
                timeTillTurnUpdate = 1f / 60f;
                body.transform.Rotate(lastFPVForward);
            }
        }
        if (fpvcamera.transform.localRotation != defaultFPVCameraAngle && !Input.GetKey(KeyCode.UpArrow) && !Input.GetKey(KeyCode.UpArrow))
        {
            fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, defaultFPVCameraAngle, .05f);
        }

        //perform wall stick sneak movements
        if (currState == movementState.sneak) {
			if (Vector3.Dot (vel, gameObject.transform.forward) > 0 && Vector3.Angle (vel, gameObject.transform.forward) < 90) {
				if (inCrouchMode) {
					currState = movementState.crawl;
					gameObject.transform.position += vel.normalized * sneakCrouchWallBuffer;
				} else {
					currState = movementState.run;
				}
				collided = collideToStick;
                collided2 = collideToStick * 2;
            } else if (!doubleRaycast (gameObject.transform.position, -body.transform.forward, (gameObject.transform.lossyScale.z / 2) + .2f)) {
				if (inCrouchMode) {
					currState = movementState.crawl;
					gameObject.transform.position += vel.normalized * sneakCrouchWallBuffer;
				} else {
					currState = movementState.run;
				}
				collided = collideToStick;
                collided2 = collideToStick * 2;
            } else if (inCrouchMode) {
				vel = Vector3.zero;
			} else if (moveLock == movementLock.LR) {
				vel.x = 0;
			} else if (moveLock == movementLock.FB) {
				vel.z = 0;
			} 

			// SNEAK CAM CODE START

			// If sneaking, then check to see if you're at an edge
			Vector3 leftPosition, rightPosition;
			bool leftEdge, rightEdge;
			RaycastHit leftHit, rightHit;
			rightPosition = body.transform.position + body.transform.right + (body.transform.forward * -1);
			leftPosition = body.transform.position + (-1 * body.transform.right) + (body.transform.forward * -1);
			rightPosition.y += 3f;
			leftPosition.y += 3f;

			// Debug rays
			Debug.DrawRay (rightPosition, new Vector3(0f,-4f,0f));
			Debug.DrawRay (leftPosition, new Vector3(0f,-4f, 0f));

			// 	change camera position to sneak cam position
			// If either of the raycasts don't hit anything, then player is at an edge
			leftEdge = Physics.Raycast (leftPosition, new Vector3(0f,-1f,0f), out leftHit, 4f);
			rightEdge = Physics.Raycast (rightPosition, new Vector3(0f,-1f,0f), out rightHit, 4f);

			if (leftEdge) {
				if (leftHit.collider.tag != "Floor")
					leftEdge = false;
			}
			if (rightEdge) {
				if (rightHit.collider.tag != "Floor")
					rightEdge = false;
			}

			if (leftEdge && rightEdge) {
				CameraController.S.GetComponent<CameraFollow> ().activateSneakCam (3, leftPosition+rightPosition);
			} else if (leftEdge) {
				CameraController.S.GetComponent<CameraFollow> ().activateSneakCam (0, leftPosition);
			} else if (rightEdge) {
				CameraController.S.GetComponent<CameraFollow> ().activateSneakCam (1, rightPosition);
			}
			// Otherwise, you're not at an edge
			else {
				// Change camera position back to normal
				CameraController.S.GetComponent<CameraFollow> ().deactivateSneakCam ();
			}

			// SNEAK CAM CODE END
		} 
		// Also make sure that cam is deactivated to default once you leave sneak
		else {
			CameraController.S.GetComponent<CameraFollow> ().deactivateSneakCam ();
		}

		// Save the last known button press direction
		if (vel != Vector3.zero)
			lastVel = vel;

        //CROUCH logic: transform snake back to normal if he moves
        if(inCrouchMode && vel != Vector3.zero)
        {
            body.transform.localScale = defaultPlayerSize;
            //check for nearby walls so we don't clip inside them
            Ray frontray = new Ray(body.transform.position, body.transform.forward);
            //Ray buttray = new Ray(body.transform.position, -body.transform.forward);
            if (Physics.Raycast(frontray, body.transform.lossyScale.y / 2f, wallLayerMask))
            {
                Vector3 safePos = gameObject.transform.position;
                safePos += -body.transform.forward.normalized * ((body.transform.lossyScale.y / 2f) + .1f);
                safePos.y = .2f;
                body.transform.position = safePos;
            }
            else
            {
                body.transform.position = new Vector3(body.transform.position.x, 0.2f, body.transform.position.z);
            }

            body.transform.rotation = Quaternion.LookRotation(vel.normalized);
            body.transform.Rotate(new Vector3(90f, 0f, 0f));

            inCrouchMode = false;
        }

        //CRAWL box collider, shrink down the box collider when in crawl mode
        if(currState == movementState.crawl && !inCrouchMode)
        {
            boxcollider.size = new Vector3(boxcollider.size.x, 1f, boxcollider.size.z);
            boxcollider.center = new Vector3(boxcollider.center.x, .3f, boxcollider.center.z);
        } else
        {
            boxcollider.size = defaultBoxColliderSize;
            boxcollider.center = new Vector3(boxcollider.center.x, .15f, boxcollider.center.z);
        }

        //MOVEMENT of the Character
        // Speed and direction of movement depends on movementState
        if (inFPVModeCrawlTransition > 0 && currState == movementState.crawl)
        {
            inFPVModeCrawlTransition -= Time.deltaTime;
            body.velocity = lastForwardCrawlVector;
        } else if(HandController.S.isFighting || HandController.S.isGrabbing)
        {
            //don't set velocity here
        } else if (currState == movementState.run) {
			body.velocity = vel.normalized * speed;
		} else if(!FPVModeCrawlControl) {
			body.velocity = vel.normalized * slowSpeed;
		} else 
        //first person crawl mode uses a different set of controls
        if(FPVModeCrawlControl)
        {
            if (Input.GetKey(KeyCode.UpArrow))
            {
                body.velocity = crawlForwardVector * slowSpeed;
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                body.velocity = -crawlForwardVector * slowSpeed;
            }

            if (Input.GetKey(KeyCode.LeftArrow))
            {
                lastCrawlTurnVector = (new Vector3(0f, 0f, FPVRotationSpeedDeg));
            }
            else if (Input.GetKey(KeyCode.RightArrow))
            {
                lastCrawlTurnVector = (new Vector3(0f, 0f, -FPVRotationSpeedDeg));
            }
            else
            {
                if(timeTillTurnUpdate <= 0)
                {
                    lastCrawlTurnVector *= FPVRotationDecel;
                }
            }

            if (timeTillTurnUpdate > 0)
            {
                timeTillTurnUpdate -= Time.deltaTime;
            }
            else
            {
                timeTillTurnUpdate = 1f / 60f;
                body.transform.Rotate(lastCrawlTurnVector);
            }
        }// end of FPV mode crawl control

        //ROTATIONS, face character towards the vector of movement:
        //set our foward direction if in run state (run rotation)
        if (currState == movementState.run && !FPVModeControl)
        {
            if (Vector3.Angle(body.transform.forward, lastVel.normalized) > 45f)
            {
                body.velocity = Vector3.zero;
            }

            // Lerp for smooth rotation
            body.transform.rotation = Quaternion.LookRotation(Vector3.Slerp(body.transform.forward, lastVel.normalized, rotationSpeed));
            //body.transform.rotation = Quaternion.LookRotation(lastVel.normalized);	
        }
        else //set look direction in crawl mode, unless snake is backing up, or in FPV Crawl mode
        if (currState == movementState.crawl && !FPVModeCrawlControl && !FPVModeControl && inFPVModeCrawlTransition <= 0)
        {
            if (vel != Vector3.zero)
            {
                body.transform.Rotate(new Vector3(90f, 0f, 0f));

                float velAngleFromCurrent = Vector3.Angle(body.transform.forward, vel);

                //dont turn snake around if its within 45 degrees
                if (Mathf.Abs(velAngleFromCurrent - 0f) <= 50f)
                {
                    //body.transform.Rotate(new Vector3(-90f, 0f, 0f));
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    body.transform.Rotate(new Vector3(90f, 180f, 0f));
                }
                else
                {
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    body.transform.Rotate(new Vector3(90f, 0f, 0f));
                }
            }
        }

        //Crouch toggle behavior
		if(Input.GetKeyDown(KeyCode.A))
		{
            if(inCrouchMode)
            {
                inCrouchMode = false;
                body.transform.localScale = defaultPlayerSize;
                if(currState != movementState.sneak)
                {
                    currState = movementState.run;
                }
            }
			else if (currState == movementState.run || currState == movementState.sneak)
			{
				//body.transform.Rotate(new Vector3(90f, 0f, 0f));

				//				body.transform.Rotate( Vector3.Lerp (Vector3.zero, new Vector3 (90f, 0f, 0f), 0.5f));
				//
				body.transform.position = new Vector3(body.transform.position.x, .25f, body.transform.position.z);

                Vector3 crouchSize = body.transform.localScale;
                crouchSize.y = crouchHeight;
                body.transform.localScale = crouchSize;
                inCrouchMode = true;

                //special case when sneaking against wall
                if(currState == movementState.sneak)
                {
                    currState = movementState.sneak;
                } else
                {
                    currState = movementState.crawl;
                }

			} else if(currState == movementState.crawl && !FPVModeCrawlControl && inFPVModeCrawlTransition <= 0)
			{
				body.transform.Rotate(new Vector3(-90f, 0f, 0f));
				body.transform.position = new Vector3(body.transform.position.x, .5f, body.transform.position.z);
				currState = movementState.run;
			}
		}

        //RAYCAST behaviors:
        //SNEAK Wall Detection
        if (vel != Vector3.zero)
        {
            //check for wall collision to stick to
            if (doubleRaycast(gameObject.transform.position, body.transform.forward, (gameObject.transform.lossyScale.z / 2) + 0.2f) && collided2 > 0)
            {
                collided2 -= Time.deltaTime;
            }
            else if (collided2 < 0 && currState == movementState.run)
            {
                // Flips character
                body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                gameObject.transform.forward *= -1;
                currState = movementState.sneak;

                if (gameObject.transform.forward.x != 0)
                {
                    moveLock = movementLock.LR;
                }
                else if (gameObject.transform.forward.z != 0)
                {
                    moveLock = movementLock.FB;
                }
            }
        }

        //CRAWL modes DETECTION
        if (currState == movementState.crawl && !inCrouchMode)
        {
            //Check FPVModeCrawl State, aka if snake crawls under enclosed space, switch mode and camera
            if (Physics.Raycast(gameObject.transform.position, -body.transform.forward, (gameObject.transform.lossyScale.z / 2) + 1.0f, wallLayerMask))
            {
                if (!FPVModeCrawlControl)
                {
                    // Should only be FPV-Crawl when you cannot stand up aka crawling in a 1 meter tall tunnel
                    CameraController.S.SwitchCameraTo(CameraType.crawl);
                    FPVModeCrawlControl = true;
                    inFPVModeCrawlTransition = ToFPVModeTransitionTime;
                    lastForwardCrawlVector = body.velocity;
                }
            } else {
                if(FPVModeCrawlControl)
                {
                    CameraController.S.SwitchCameraTo(CameraType.overhead);
                    FPVModeCrawlControl = false;
                    inFPVModeCrawlTransition = FromFPVModeTransitionTime;
                    lastForwardCrawlVector = body.velocity;
                }
            }

            if(!FPVModeCrawlControl && !inCrouchMode)
            {
                Ray headray = new Ray(gameObject.transform.position, crawlForwardVector);
                RaycastHit hit;
                //Debug.DrawRay(gameObject.transform.position, crawlForwardVector * ((gameObject.transform.lossyScale.y / 2) + 0.4f), Color.green);
                if (Physics.Raycast(headray, out hit, ((gameObject.transform.lossyScale.y / 2) + 0.4f), wallLayerMask) && collided > 0)
                {
                    collided -= Time.deltaTime;
                }
                else if (collided < 0)
                {
                    // Flips character
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    gameObject.transform.forward = -crawlForwardVector;
                    currState = movementState.sneak;

                    Vector3 newPos = hit.point;
                    if(hit.point != Vector3.zero)
                    {
                        newPos += -crawlForwardVector.normalized * ((gameObject.transform.lossyScale.y / 4));
                    } else
                    {
                        newPos = gameObject.transform.position;
                    }
                    print(hit.point);
                    
                    gameObject.transform.position = newPos;

                    Vector3 crouchSize = body.transform.localScale;
                    crouchSize.y = crouchHeight;
                    body.transform.localScale = crouchSize;
                    inCrouchMode = true;

                    if (gameObject.transform.forward.x != 0)
                    {
                        moveLock = movementLock.LR;
                    }
                    else if (gameObject.transform.forward.z != 0)
                    {
                        moveLock = movementLock.FB;
                    }

                    body.velocity = Vector3.zero;
                }

                Ray buttray = new Ray(gameObject.transform.position, -crawlForwardVector);
                RaycastHit hit2;
                Debug.DrawRay(gameObject.transform.position, -crawlForwardVector * (gameObject.transform.lossyScale.y / 4), Color.green);
                if (Physics.Raycast(buttray, out hit2, (gameObject.transform.lossyScale.y / 4), wallLayerMask) && collided2 > 0)
                {
                    collided2 -= Time.deltaTime;
                }
                else if (collided2 < 0)
                {
                    // Flips character
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    gameObject.transform.forward = crawlForwardVector;
                    currState = movementState.sneak;

                    Vector3 newPos = hit2.point;
                    if(newPos != Vector3.zero)
                    {
                        newPos += crawlForwardVector.normalized * ((gameObject.transform.lossyScale.y / 4));
                    } else
                    {
                        newPos = gameObject.transform.position;
                    }
                    gameObject.transform.position = newPos;

                    Vector3 crouchSize = body.transform.localScale;
                    crouchSize.y = crouchHeight;
                    body.transform.localScale = crouchSize;
                    inCrouchMode = true;

                    if (gameObject.transform.forward.x != 0)
                    {
                        moveLock = movementLock.LR;
                    }
                    else if (gameObject.transform.forward.z != 0)
                    {
                        moveLock = movementLock.FB;
                    }
                }
            }
        }
        //CRAWL modes DETECTION END
    }
Exemple #2
0
    // Update is called once per frame
    void Update()
    {
        //grab the forwards vector for when the body is facedown (crawl state)
        Vector3 crawlForwardVector = findForwardCrawlVector();

        //Debug.DrawRay(body.transform.position, crawlForwardVector * 5f, Color.green);

        if (Input.GetKeyDown(KeyCode.I))
        {
            if (!bigBossMode)
            {
                bigBossMode = true;
                print("Invincibility Mode ACTIVATED!");
            }
            else
            {
                bigBossMode = false;
                print("Invincibility Mode DE-ACTIVATED!");
            }
        }

        if (currState == movementState.run || (inCrouchMode && currState == movementState.crawl) || currState == movementState.sneak)
        {
            if (Input.GetKeyDown(KeyCode.W))
            {
                print("Triangle Button: FPV Cam");
                FPVModeControl = true;
                CameraController.S.SwitchCameraTo(CameraType.fpv);
            }
            if (Input.GetKeyUp(KeyCode.W))
            {
                FPVModeControl = false;
                CameraController.S.SwitchCameraTo(CameraType.overhead);
            }
        }

        Vector3 vel = Vector3.zero;

        if (Input.GetKey(KeyCode.UpArrow))
        {
            vel.z += 1;
        }
        if (Input.GetKey(KeyCode.DownArrow))
        {
            vel.z -= 1;
        }
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            vel.x -= 1;
        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            vel.x += 1;
        }

        if (HandController.S.isFighting || HandController.S.isFighting || FPVModeControl)
        {
            vel = Vector3.zero;
        }

        // begin of FPV mode control
        GameObject fpvcamera = CameraController.S.cameras[(int)CameraType.fpv];

        if (FPVModeControl)
        {
            //controls for FPV mode
            if (Input.GetKey(KeyCode.UpArrow))
            {
                Quaternion rot = Quaternion.Euler(-45f, 0f, 0f);
                fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, rot, .05f);
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                Quaternion rot = Quaternion.Euler(45f, 0f, 0f);
                fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, rot, .05f);
            }

            if (Input.GetKey(KeyCode.LeftArrow))
            {
                lastFPVForward = (new Vector3(0f, -FPVRotationSpeedDeg, 0f));
            }
            else if (Input.GetKey(KeyCode.RightArrow))
            {
                lastFPVForward = (new Vector3(0f, FPVRotationSpeedDeg, 0f));
            }
            else
            {
                if (timeTillTurnUpdate <= 0)
                {
                    lastFPVForward *= FPVRotationDecel;
                }
            }

            if (timeTillTurnUpdate > 0)
            {
                timeTillTurnUpdate -= Time.deltaTime;
            }
            else
            {
                timeTillTurnUpdate = 1f / 60f;
                body.transform.Rotate(lastFPVForward);
            }
        }
        if (fpvcamera.transform.localRotation != defaultFPVCameraAngle && !Input.GetKey(KeyCode.UpArrow) && !Input.GetKey(KeyCode.UpArrow))
        {
            fpvcamera.transform.localRotation = Quaternion.Slerp(fpvcamera.transform.localRotation, defaultFPVCameraAngle, .05f);
        }

        //perform wall stick sneak movements
        if (currState == movementState.sneak)
        {
            if (Vector3.Dot(vel, gameObject.transform.forward) > 0 && Vector3.Angle(vel, gameObject.transform.forward) < 90)
            {
                if (inCrouchMode)
                {
                    currState = movementState.crawl;
                    gameObject.transform.position += vel.normalized * sneakCrouchWallBuffer;
                }
                else
                {
                    currState = movementState.run;
                }
                collided  = collideToStick;
                collided2 = collideToStick * 2;
            }
            else if (!doubleRaycast(gameObject.transform.position, -body.transform.forward, (gameObject.transform.lossyScale.z / 2) + .2f))
            {
                if (inCrouchMode)
                {
                    currState = movementState.crawl;
                    gameObject.transform.position += vel.normalized * sneakCrouchWallBuffer;
                }
                else
                {
                    currState = movementState.run;
                }
                collided  = collideToStick;
                collided2 = collideToStick * 2;
            }
            else if (inCrouchMode)
            {
                vel = Vector3.zero;
            }
            else if (moveLock == movementLock.LR)
            {
                vel.x = 0;
            }
            else if (moveLock == movementLock.FB)
            {
                vel.z = 0;
            }

            // SNEAK CAM CODE START

            // If sneaking, then check to see if you're at an edge
            Vector3    leftPosition, rightPosition;
            bool       leftEdge, rightEdge;
            RaycastHit leftHit, rightHit;
            rightPosition    = body.transform.position + body.transform.right + (body.transform.forward * -1);
            leftPosition     = body.transform.position + (-1 * body.transform.right) + (body.transform.forward * -1);
            rightPosition.y += 3f;
            leftPosition.y  += 3f;

            // Debug rays
            Debug.DrawRay(rightPosition, new Vector3(0f, -4f, 0f));
            Debug.DrawRay(leftPosition, new Vector3(0f, -4f, 0f));

            //  change camera position to sneak cam position
            // If either of the raycasts don't hit anything, then player is at an edge
            leftEdge  = Physics.Raycast(leftPosition, new Vector3(0f, -1f, 0f), out leftHit, 4f);
            rightEdge = Physics.Raycast(rightPosition, new Vector3(0f, -1f, 0f), out rightHit, 4f);

            if (leftEdge)
            {
                if (leftHit.collider.tag != "Floor")
                {
                    leftEdge = false;
                }
            }
            if (rightEdge)
            {
                if (rightHit.collider.tag != "Floor")
                {
                    rightEdge = false;
                }
            }

            if (leftEdge && rightEdge)
            {
                CameraController.S.GetComponent <CameraFollow> ().activateSneakCam(3, leftPosition + rightPosition);
            }
            else if (leftEdge)
            {
                CameraController.S.GetComponent <CameraFollow> ().activateSneakCam(0, leftPosition);
            }
            else if (rightEdge)
            {
                CameraController.S.GetComponent <CameraFollow> ().activateSneakCam(1, rightPosition);
            }
            // Otherwise, you're not at an edge
            else
            {
                // Change camera position back to normal
                CameraController.S.GetComponent <CameraFollow> ().deactivateSneakCam();
            }

            // SNEAK CAM CODE END
        }
        // Also make sure that cam is deactivated to default once you leave sneak
        else
        {
            CameraController.S.GetComponent <CameraFollow> ().deactivateSneakCam();
        }

        // Save the last known button press direction
        if (vel != Vector3.zero)
        {
            lastVel = vel;
        }

        //CROUCH logic: transform snake back to normal if he moves
        if (inCrouchMode && vel != Vector3.zero)
        {
            body.transform.localScale = defaultPlayerSize;
            //check for nearby walls so we don't clip inside them
            Ray frontray = new Ray(body.transform.position, body.transform.forward);
            //Ray buttray = new Ray(body.transform.position, -body.transform.forward);
            if (Physics.Raycast(frontray, body.transform.lossyScale.y / 2f, wallLayerMask))
            {
                Vector3 safePos = gameObject.transform.position;
                safePos  += -body.transform.forward.normalized * ((body.transform.lossyScale.y / 2f) + .1f);
                safePos.y = .2f;
                body.transform.position = safePos;
            }
            else
            {
                body.transform.position = new Vector3(body.transform.position.x, 0.2f, body.transform.position.z);
            }

            body.transform.rotation = Quaternion.LookRotation(vel.normalized);
            body.transform.Rotate(new Vector3(90f, 0f, 0f));

            inCrouchMode = false;
        }

        //CRAWL box collider, shrink down the box collider when in crawl mode
        if (currState == movementState.crawl && !inCrouchMode)
        {
            boxcollider.size   = new Vector3(boxcollider.size.x, 1f, boxcollider.size.z);
            boxcollider.center = new Vector3(boxcollider.center.x, .3f, boxcollider.center.z);
        }
        else
        {
            boxcollider.size   = defaultBoxColliderSize;
            boxcollider.center = new Vector3(boxcollider.center.x, .15f, boxcollider.center.z);
        }

        //MOVEMENT of the Character
        // Speed and direction of movement depends on movementState
        if (inFPVModeCrawlTransition > 0 && currState == movementState.crawl)
        {
            inFPVModeCrawlTransition -= Time.deltaTime;
            body.velocity             = lastForwardCrawlVector;
        }
        else if (HandController.S.isFighting || HandController.S.isGrabbing)
        {
            //don't set velocity here
        }
        else if (currState == movementState.run)
        {
            body.velocity = vel.normalized * speed;
        }
        else if (!FPVModeCrawlControl)
        {
            body.velocity = vel.normalized * slowSpeed;
        }
        else
        //first person crawl mode uses a different set of controls
        if (FPVModeCrawlControl)
        {
            if (Input.GetKey(KeyCode.UpArrow))
            {
                body.velocity = crawlForwardVector * slowSpeed;
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                body.velocity = -crawlForwardVector * slowSpeed;
            }

            if (Input.GetKey(KeyCode.LeftArrow))
            {
                lastCrawlTurnVector = (new Vector3(0f, 0f, FPVRotationSpeedDeg));
            }
            else if (Input.GetKey(KeyCode.RightArrow))
            {
                lastCrawlTurnVector = (new Vector3(0f, 0f, -FPVRotationSpeedDeg));
            }
            else
            {
                if (timeTillTurnUpdate <= 0)
                {
                    lastCrawlTurnVector *= FPVRotationDecel;
                }
            }

            if (timeTillTurnUpdate > 0)
            {
                timeTillTurnUpdate -= Time.deltaTime;
            }
            else
            {
                timeTillTurnUpdate = 1f / 60f;
                body.transform.Rotate(lastCrawlTurnVector);
            }
        }// end of FPV mode crawl control

        //ROTATIONS, face character towards the vector of movement:
        //set our foward direction if in run state (run rotation)
        if (currState == movementState.run && !FPVModeControl)
        {
            if (Vector3.Angle(body.transform.forward, lastVel.normalized) > 45f)
            {
                body.velocity = Vector3.zero;
            }

            // Lerp for smooth rotation
            body.transform.rotation = Quaternion.LookRotation(Vector3.Slerp(body.transform.forward, lastVel.normalized, rotationSpeed));
            //body.transform.rotation = Quaternion.LookRotation(lastVel.normalized);
        }
        else //set look direction in crawl mode, unless snake is backing up, or in FPV Crawl mode
        if (currState == movementState.crawl && !FPVModeCrawlControl && !FPVModeControl && inFPVModeCrawlTransition <= 0)
        {
            if (vel != Vector3.zero)
            {
                body.transform.Rotate(new Vector3(90f, 0f, 0f));

                float velAngleFromCurrent = Vector3.Angle(body.transform.forward, vel);

                //dont turn snake around if its within 45 degrees
                if (Mathf.Abs(velAngleFromCurrent - 0f) <= 50f)
                {
                    //body.transform.Rotate(new Vector3(-90f, 0f, 0f));
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    body.transform.Rotate(new Vector3(90f, 180f, 0f));
                }
                else
                {
                    body.transform.rotation = Quaternion.LookRotation(vel.normalized);
                    body.transform.Rotate(new Vector3(90f, 0f, 0f));
                }
            }
        }

        //Crouch toggle behavior
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (inCrouchMode)
            {
                inCrouchMode = false;
                body.transform.localScale = defaultPlayerSize;
                if (currState != movementState.sneak)
                {
                    currState = movementState.run;
                }
            }
            else if (currState == movementState.run || currState == movementState.sneak)
            {
                //body.transform.Rotate(new Vector3(90f, 0f, 0f));

                //				body.transform.Rotate( Vector3.Lerp (Vector3.zero, new Vector3 (90f, 0f, 0f), 0.5f));
                //
                body.transform.position = new Vector3(body.transform.position.x, .25f, body.transform.position.z);

                Vector3 crouchSize = body.transform.localScale;
                crouchSize.y = crouchHeight;
                body.transform.localScale = crouchSize;
                inCrouchMode = true;

                //special case when sneaking against wall
                if (currState == movementState.sneak)
                {
                    currState = movementState.sneak;
                }
                else
                {
                    currState = movementState.crawl;
                }
            }
            else if (currState == movementState.crawl && !FPVModeCrawlControl && inFPVModeCrawlTransition <= 0)
            {
                body.transform.Rotate(new Vector3(-90f, 0f, 0f));
                body.transform.position = new Vector3(body.transform.position.x, .5f, body.transform.position.z);
                currState = movementState.run;
            }
        }

        //RAYCAST behaviors:
        //SNEAK Wall Detection
        if (vel != Vector3.zero)
        {
            //check for wall collision to stick to
            if (doubleRaycast(gameObject.transform.position, body.transform.forward, (gameObject.transform.lossyScale.z / 2) + 0.2f) && collided2 > 0)
            {
                collided2 -= Time.deltaTime;
            }
            else if (collided2 < 0 && currState == movementState.run)
            {
                // Flips character
                body.transform.rotation       = Quaternion.LookRotation(vel.normalized);
                gameObject.transform.forward *= -1;
                currState = movementState.sneak;

                if (gameObject.transform.forward.x != 0)
                {
                    moveLock = movementLock.LR;
                }
                else if (gameObject.transform.forward.z != 0)
                {
                    moveLock = movementLock.FB;
                }
            }
        }

        //CRAWL modes DETECTION
        if (currState == movementState.crawl && !inCrouchMode)
        {
            //Check FPVModeCrawl State, aka if snake crawls under enclosed space, switch mode and camera
            if (Physics.Raycast(gameObject.transform.position, -body.transform.forward, (gameObject.transform.lossyScale.z / 2) + 1.0f, wallLayerMask))
            {
                if (!FPVModeCrawlControl)
                {
                    // Should only be FPV-Crawl when you cannot stand up aka crawling in a 1 meter tall tunnel
                    CameraController.S.SwitchCameraTo(CameraType.crawl);
                    FPVModeCrawlControl      = true;
                    inFPVModeCrawlTransition = ToFPVModeTransitionTime;
                    lastForwardCrawlVector   = body.velocity;
                }
            }
            else
            {
                if (FPVModeCrawlControl)
                {
                    CameraController.S.SwitchCameraTo(CameraType.overhead);
                    FPVModeCrawlControl      = false;
                    inFPVModeCrawlTransition = FromFPVModeTransitionTime;
                    lastForwardCrawlVector   = body.velocity;
                }
            }

            if (!FPVModeCrawlControl && !inCrouchMode)
            {
                Ray        headray = new Ray(gameObject.transform.position, crawlForwardVector);
                RaycastHit hit;
                //Debug.DrawRay(gameObject.transform.position, crawlForwardVector * ((gameObject.transform.lossyScale.y / 2) + 0.4f), Color.green);
                if (Physics.Raycast(headray, out hit, ((gameObject.transform.lossyScale.y / 2) + 0.4f), wallLayerMask) && collided > 0)
                {
                    collided -= Time.deltaTime;
                }
                else if (collided < 0)
                {
                    // Flips character
                    body.transform.rotation      = Quaternion.LookRotation(vel.normalized);
                    gameObject.transform.forward = -crawlForwardVector;
                    currState = movementState.sneak;

                    Vector3 newPos = hit.point;
                    if (hit.point != Vector3.zero)
                    {
                        newPos += -crawlForwardVector.normalized * ((gameObject.transform.lossyScale.y / 4));
                    }
                    else
                    {
                        newPos = gameObject.transform.position;
                    }
                    print(hit.point);

                    gameObject.transform.position = newPos;

                    Vector3 crouchSize = body.transform.localScale;
                    crouchSize.y = crouchHeight;
                    body.transform.localScale = crouchSize;
                    inCrouchMode = true;

                    if (gameObject.transform.forward.x != 0)
                    {
                        moveLock = movementLock.LR;
                    }
                    else if (gameObject.transform.forward.z != 0)
                    {
                        moveLock = movementLock.FB;
                    }

                    body.velocity = Vector3.zero;
                }

                Ray        buttray = new Ray(gameObject.transform.position, -crawlForwardVector);
                RaycastHit hit2;
                Debug.DrawRay(gameObject.transform.position, -crawlForwardVector * (gameObject.transform.lossyScale.y / 4), Color.green);
                if (Physics.Raycast(buttray, out hit2, (gameObject.transform.lossyScale.y / 4), wallLayerMask) && collided2 > 0)
                {
                    collided2 -= Time.deltaTime;
                }
                else if (collided2 < 0)
                {
                    // Flips character
                    body.transform.rotation      = Quaternion.LookRotation(vel.normalized);
                    gameObject.transform.forward = crawlForwardVector;
                    currState = movementState.sneak;

                    Vector3 newPos = hit2.point;
                    if (newPos != Vector3.zero)
                    {
                        newPos += crawlForwardVector.normalized * ((gameObject.transform.lossyScale.y / 4));
                    }
                    else
                    {
                        newPos = gameObject.transform.position;
                    }
                    gameObject.transform.position = newPos;

                    Vector3 crouchSize = body.transform.localScale;
                    crouchSize.y = crouchHeight;
                    body.transform.localScale = crouchSize;
                    inCrouchMode = true;

                    if (gameObject.transform.forward.x != 0)
                    {
                        moveLock = movementLock.LR;
                    }
                    else if (gameObject.transform.forward.z != 0)
                    {
                        moveLock = movementLock.FB;
                    }
                }
            }
        }
        //CRAWL modes DETECTION END
    }