Question by 
               hejlskov · Nov 09, 2020 at 12:56 PM · 
                movementcharactercontrollerfps controllerjitter  
              
 
              Frustrating Problem with Character Controller in FPS
I am trying to make an FPS using the character controller based on a simplified version of the MicroFPS project with wall running etc, but I have run into a frustrating problem. When moving around, the charatcer suddenly starts jittering and zig-zagging, both on ground and when in the air. I have attached the two scripts below. PLEASE HELP!
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
 public class WallRun : MonoBehaviour
 {
     public float wallSpeedMultiplier = 1.25f;
     public float wallBouncing = 3.0f;
     public float maximumAngleRoll = 20.0f;
     public float jumpDuration = 1.0f;
     private PlayerCharacterController playerCharacterControllerComponent;
     private Camera cameraComponent;
     private Vector3[] directions;
     private RaycastHit[] raycastHits;
     private Vector3 lastWallPosition = Vector3.zero;
     private Vector3 lastWallNormal = Vector3.zero;
     private bool isWallRunning = false;
     private bool isJumping = false;
     private float elapsedTimeSinceJump = 0.0f;
 
     public bool IsWallRunning() => isWallRunning;
 
     // Start is called before the first frame update
     private void Start()
     {
         playerCharacterControllerComponent = GetComponent<PlayerCharacterController>();
         cameraComponent = GetComponentInChildren<Camera>();
 
         directions = new Vector3[] { Vector3.right, Vector3.right + Vector3.forward, Vector3.forward, Vector3.left + Vector3.forward, Vector3.left };
     }
 
     // Update is called once per frame
     private void Update()
     {
         
     }
 
     private void LateUpdate()
     {
         isWallRunning = false;
 
         if (!playerCharacterControllerComponent.IsGrounded() && playerCharacterControllerComponent.GetJumpInputDown())
         {
             isJumping = true;
         }
 
         if (CanAttach())
         {
             raycastHits = new RaycastHit[directions.Length];
 
             for (int i = 0; i < directions.Length; i++)
             {
                 Vector3 direction = transform.TransformDirection(directions[i]);
                 Physics.Raycast(transform.position, direction, out raycastHits[i], 1.0f);
 
                 if (raycastHits[i].collider != null)
                 {
                     Debug.DrawRay(transform.position, direction, Color.green);
                 }
                 else
                 {
                     Debug.DrawRay(transform.position, direction, Color.red);
                 }
             }
 
             if (CanWallRun())
             {
                 raycastHits = raycastHits.ToList().Where(h => h.collider != null).OrderBy(h => h.distance).ToArray();
 
                 if (raycastHits.Length > 0)
                 {
                     OnWall(raycastHits[0]);
                     lastWallPosition = raycastHits[0].point;
                     lastWallNormal = raycastHits[0].normal;
                 }
             }
         }
     }
 
     private bool CanWallRun()
     {
         if (playerCharacterControllerComponent != null)
         {
             return !playerCharacterControllerComponent.IsGrounded() && playerCharacterControllerComponent.GetMovementInput().z > 0;
         }
 
         return false;
     }
 
     bool CanAttach()
     {
         if (isJumping)
         {
             elapsedTimeSinceJump += Time.deltaTime;
 
             if (elapsedTimeSinceJump > jumpDuration)
             {
                 elapsedTimeSinceJump = 0.0f;
                 isJumping = false;
             }
 
             return false;
         }
 
         return true;
     }
 
     private void OnWall(RaycastHit raycastHit)
     {
         if (Vector3.Dot(raycastHit.normal, Vector3.up) >= -0.1f && Vector3.Dot(raycastHit.normal, Vector3.up) <= 0.1f)
         {
             isWallRunning = true;
             Vector3 targetVelocity = Vector3.Cross(raycastHit.normal, Vector3.up);
 
             if (Vector3.Dot(transform.TransformDirection(Vector3.forward), targetVelocity) < 0.0f)
             {
                 targetVelocity *= -1.0f;
             }
 
             targetVelocity *= 10.0f * wallSpeedMultiplier;
             playerCharacterControllerComponent.characterVelocity = targetVelocity;
         }
     }
 
     private float CalculateSide()
     {
         if (isWallRunning)
         {
             return Vector3.Dot(Vector3.Cross(transform.forward, (lastWallPosition - transform.position)), transform.up);
         }
 
         return 0.0f;
     }
 
     public float CameraRoll()
     {
         float currentAngle = cameraComponent.transform.eulerAngles.z;
         float targetAngle = 0.0f;
 
         if (CalculateSide() != 0.0f)
         {
             targetAngle = Mathf.Sign(CalculateSide()) * maximumAngleRoll;
         }
 
         return Mathf.LerpAngle(currentAngle, targetAngle, Time.deltaTime * 5.0f);
     }
 
     public Vector3 GetWallJumpDirection()
     {
         if (isWallRunning)
         {
             return lastWallNormal * wallBouncing + Vector3.up;
         }
 
         print("HI");
 
         return Vector3.zero;
     }
 }
 
               AND
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.InteropServices;
 using UnityEngine;
 
 public class PlayerCharacterController : MonoBehaviour
 {
     [HideInInspector] public Vector3 characterVelocity = Vector3.zero;
     public float speedOnGround = 10.0f;
     public float movementSharpnesOnGround = 15.0f;
     public float sprintSpeedMultiplier = 2f;
     public float jumpForce = 4.0f;
     public float gravityDownForce = 10.0f;
     private CharacterController characterControllerComponent;
     private bool isGrounded = false;
     private bool canDoubleJump = false;
 
     public float rotationSpeed = 5.0f;
     private Camera cameraComponent;
     private float cameraVerticalRotation = 0.0f;
 
     //private bool isGrappling = false;
     //private Vector3 grapplePoint = Vector3.zero;
     //private GameObject grappleAnchor;
     //private LineRenderer lineRendererComponent;
     //private float targetFieldOfView = 0.0f;
 
     private WallRun wallRunComponent;
 
     public bool IsGrounded() => isGrounded;
 
     // Start is called before the first frame update
     private void Start()
     {
         characterControllerComponent = GetComponent<CharacterController>();
         cameraComponent = GetComponentInChildren<Camera>();
         //lineRendererComponent = GetComponent<LineRenderer>();
         wallRunComponent = GetComponent<WallRun>();
 
         //lineRendererComponent.enabled = false;
         //targetFieldOfView = 60.0f;
     }
 
     // Update is called once per frame
     private void Update()
     {
         isGrounded = false;
         isGrounded = characterControllerComponent.isGrounded;
 
         HandleMovement();
      }
 
     private void HandleMovement()
     {
         cameraVerticalRotation -= GetLookInputVertical() * rotationSpeed;
         cameraVerticalRotation = ClampAngle(cameraVerticalRotation, -60.0f, 60.0f);
 
         if (wallRunComponent == null)
         {
             cameraComponent.transform.localEulerAngles = new Vector3(cameraVerticalRotation, 0.0f, 0.0f);
         }
         else
         {
             cameraComponent.transform.localEulerAngles = new Vector3(cameraVerticalRotation, 0.0f, wallRunComponent.CameraRoll());
         }
 
         transform.Rotate(new Vector3(0.0f, ClampAngle(GetLookInputHorizontal() * rotationSpeed, -360.0f, 360.0f), 0.0f), Space.Self);
 
         bool isSprinting = GetSprintInputHeld();
         float speedModifier = isSprinting ? sprintSpeedMultiplier : 1.0f;
 
         Vector3 worldSpaceMoveInput = transform.TransformVector(GetMovementInput());
 
         if (isGrounded || (wallRunComponent != null & wallRunComponent.IsWallRunning()))
         {
             if (isGrounded)
             {
                 Vector3 targetVelocity = worldSpaceMoveInput * speedOnGround * speedModifier;
 
                 characterVelocity = Vector3.Lerp(characterVelocity, targetVelocity, movementSharpnesOnGround * Time.deltaTime);
             }
 
             if ((isGrounded || (wallRunComponent != null && wallRunComponent.IsWallRunning())) && GetJumpInputDown())
             {
                 if (isGrounded)
                 {
                     characterVelocity = new Vector3(characterVelocity.x, 0.0f, characterVelocity.z);
                     characterVelocity += Vector3.up * jumpForce;
                 }
                 else
                 {
                     characterVelocity = new Vector3(characterVelocity.x, 0.0f, characterVelocity.z);
                     characterVelocity += wallRunComponent.GetWallJumpDirection() * jumpForce;
                 }
 
                 isGrounded = false;
             }
         }
         else
         {
             if (wallRunComponent == null || (wallRunComponent != null & !wallRunComponent.IsWallRunning()))
             {
                 //characterVelocity += worldSpaceMoveInput * 25.0f * Time.deltaTime;
                 characterVelocity += Vector3.down * gravityDownForce * Time.deltaTime;
             }
         }
 
         characterControllerComponent.Move(characterVelocity * Time.deltaTime);
     }
 
     private float ClampAngle (float angle, float minimum, float maximum)
     {
         if(angle < -360.0f)
         {
             angle += 360.0f;
         }
         else if (angle > 360.0f)
         {
             angle -= 360.0f;
         }
 
         return Mathf.Clamp(angle, minimum, maximum);
     }
 
     public float GetLookInputHorizontal()
     {
         return Input.GetAxisRaw("Mouse X");
     }
 
     public float GetLookInputVertical()
     {
         return Input.GetAxisRaw("Mouse Y");
     }
 
     public Vector3 GetMovementInput()
     {
         Vector3 movementInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0.0f, Input.GetAxisRaw("Vertical"));
         movementInput = Vector3.ClampMagnitude(movementInput, 1.0f);
 
         return movementInput;
     }
 
     public bool GetSprintInputHeld()
     {
         return Input.GetKey(KeyCode.LeftShift);
     }
 
     public bool GetJumpInputDown()
     {
         return Input.GetButtonDown("Jump");
     }
 }
 
 
              
               Comment
              
 
               
              Your answer
 
             Follow this Question
Related Questions
Moving left to right and after the level ends move character right to left 1 Answer
Ghost car movement jitters when replaying previous race 1 Answer
try to rotate a character controller when translating on z only 0 Answers
Jump logic issues 0 Answers
how to make player movement be based on direction its facing 1 Answer