Search Unity

Question Need to change Rigidbody player to Character Controller.

Discussion in 'Scripting' started by true_warlock, Mar 29, 2023.

  1. true_warlock

    true_warlock

    Joined:
    Aug 2, 2019
    Posts:
    60
    Several reasons why I am abandoning Rigidbody Character Controller, but one of the main ones is I grew tired of fighting with step detection. What I need help with is minor but I can't find any guidance to restrict some movement on the Character controller to keep it from completely turning around when using the WASD or Arrow Keys. I also need to be able to properly toggle on/off Run better than I currently have it.

    Here is the script I am converting to. There is a note next to what I am trying to resolve:

    Code (CSharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4.  
    5. public class PlayerController : MonoBehaviour
    6. {
    7.     private Animator anim;
    8.     private CharacterController cc;
    9.     public Vector2 inputNormalized;
    10.  
    11.     [Header("Movement")]
    12.     public bool steer;
    13.     public float gravity = -9.10f;
    14.     [Range(0, 10)] public float jH = 1f;
    15.  
    16.     public float moveSpeed;
    17.     [Range(0, 10)] public float runSpeed;
    18.     public float rotSpeed;
    19.     public float jumpSpeed;
    20.     public float jumpButtonGracePeriod;
    21.  
    22.     private float ySpeed;
    23.     private float originalStepOffset;
    24.     private float? lastGroundedTime;
    25.     private float? jumpButtonPressedTime;
    26.  
    27.     public bool isRunning;
    28.  
    29.  
    30.     public void Start()
    31.     {
    32.         CameraControl cameraControl = FindObjectOfType<CameraControl>();
    33.         cameraControl.Init();
    34.     }
    35.     // Start is called before the first frame update
    36.     private void Awake()
    37.     {
    38.         cc = GetComponent<CharacterController>();
    39.         anim = GetComponent<Animator>();
    40.         originalStepOffset = cc.stepOffset;
    41.     }
    42.  
    43.     // Update is called once per frame
    44.     private void Update()
    45.     {
    46.         Move();
    47.     }
    48.     private void Move()
    49.     {
    50.         float x = Input.GetAxis("Horizontal");
    51.         float z = Input.GetAxis("Vertical");// I belive this is where I need something for (< 0 ? -input.x : input.x ) as it is in a rigidbody setup but cannot sort out the equvilant in a Character Controller;
    52.      
    53.         Vector3 movementDirection = new Vector3(x, 0, z);
    54.         float magnitude = Mathf.Clamp01(movementDirection.magnitude) * moveSpeed;
    55.         movementDirection.Normalize();
    56.  
    57.         cc.SimpleMove(movementDirection * magnitude);
    58.  
    59.         if (movementDirection != Vector3.zero)
    60.         {
    61.             Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
    62.             transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotSpeed * Time.deltaTime);
    63.         }
    64. //for the running I have at present this, but am asking for some suggestions to make it transition better as I dont want to use the hold down shift key.
    65.  
    66.         if (Input.GetButtonDown("Run"))
    67.         {
    68.             isRunning = !isRunning;
    69.         }
    70.         if (isRunning)
    71.         {
    72.             moveSpeed = runSpeed;
    73. ;
    74.         }
    75.         else
    76.         {
    77.             moveSpeed = 0.5f;
    78.  
    79.         }
    80.  
    81.         ySpeed += Physics.gravity.y * Time.deltaTime;
    82.  
    83.         if (cc.isGrounded)
    84.         {
    85.             lastGroundedTime = Time.time;
    86.         }
    87.  
    88.         if (Input.GetButtonDown("Jump"))
    89.         {
    90.             jumpButtonPressedTime = Time.time;
    91.         }
    92.  
    93.         if (Time.time - lastGroundedTime <= jumpButtonGracePeriod)
    94.         {
    95.             cc.stepOffset = originalStepOffset;
    96.             ySpeed = -0.5f;
    97.  
    98.             if (Time.time - jumpButtonPressedTime <= jumpButtonGracePeriod)
    99.             {
    100.                 ySpeed = jumpSpeed;
    101.                 jumpButtonPressedTime = null;
    102.                 lastGroundedTime = null;
    103.             }
    104.         }
    105.         else
    106.         {
    107.             cc.stepOffset = 0;
    108.         }
    109.  
    110.         Vector3 velocity = movementDirection * magnitude;
    111.         velocity.y = ySpeed;
    112.  
    113.         cc.Move(velocity * Time.deltaTime);
    114.  
    115.         if (movementDirection != Vector3.zero)
    116.         {
    117.             anim.SetBool("IsMoving", true);
    118.             Quaternion toRotation = Quaternion.LookRotation(movementDirection, Vector3.up);
    119.  
    120.             transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotSpeed * Time.deltaTime);
    121.         }
    122.         else
    123.         {
    124.             anim.SetBool("IsMoving", false);
    125.         }
    126.     }
    127.      
    128. }
    129.  
    130.  
    The Camera that needs a little refinement is:

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class CameraControl : MonoBehaviour
    7. {
    8.     // NOTE:Been also having issues with collission detection to prevent camera from passing through other mesh/objects such as ground
    9.     // and getting Smoothing to work properly when using camera tpo steer player.
    10.  
    11.     //Inputs
    12.  
    13.     KeyCode leftMouse = KeyCode.Mouse0;
    14.     KeyCode rightMouse = KeyCode.Mouse1;
    15.     KeyCode middleMouse = KeyCode.Mouse2;
    16.  
    17.     public CameraState cameraState = CameraState.CameraNone;
    18.     public CameraMoveState camMoveState = CameraMoveState.OnlyWhileMoving;
    19.     public float cameraAdjustSpeed = 1;
    20.  
    21.  
    22.     [SerializeField] [Range(0, 25)] float camMaxDistance;
    23.     [SerializeField] [Range(0, 10)] float camHeight;
    24.  
    25.     [SerializeField] [Range(-90, 90)] float camMaxTilt, camMinTilt;
    26.     [SerializeField] [Range(0, 100)] float camSpeed;
    27.  
    28.  
    29.     [SerializeField] [Range(0, 300)] float scrollSpeed;
    30.     [SerializeField] [Range(0, 10)] float scrollMax;
    31.  
    32.     [SerializeField] [Range(0, 10)] float currentTilt, currentPan, currentDistance;
    33.  
    34.     //Collision
    35.  
    36.     public bool collisionDebug;
    37.     public float collisionCushion = 0.35f;
    38.     public float clipCushion = 1.5f;
    39.     public int rayGridX = 9, rayGridY = 5;
    40.     [SerializeField] float adjustedDistance;
    41.  
    42.  
    43.     Vector3[] camClip, clipDirection, playerClip, rayColOrigin, rayColPoint;
    44.     bool[] rayColHit;
    45.     Ray camRay;
    46.     RaycastHit camRayHit;
    47.  
    48.     //CameraSmoothing //Doesn't work as of yet and haven't sorted out why.
    49.  
    50.     [SerializeField] float panAngle, panOffset;
    51.     bool camXAdjust, camYAdjust;
    52.     [SerializeField] float rotationXCushion = 3, rotationXSpeed = 0;
    53.     [SerializeField] float yRotMin = 0, yRotMax = 20, rotationYSpeed = 0;
    54.  
    55.     //Reference
    56.  
    57.     PlayerController player;
    58.     public Transform tilt;
    59.     Camera mainCam;
    60.  
    61.  
    62.     // Update is called once per frame
    63.     public void Init()
    64.     {
    65.         player = FindObjectOfType<PlayerController>();
    66.         mainCam = Camera.main;
    67.  
    68.         transform.position = player.transform.position + Vector3.up * camHeight;
    69.         transform.rotation = player.transform.rotation;
    70.  
    71.         tilt.eulerAngles = new Vector3(currentTilt, transform.eulerAngles.y, transform.eulerAngles.z);
    72.         mainCam.transform.position += tilt.forward * -currentDistance;
    73.     }
    74.  
    75.     void Update()
    76.     {
    77.         if (!Input.GetKey(leftMouse) && !Input.GetKey(rightMouse) && !Input.GetKey(middleMouse))
    78.             cameraState = CameraState.CameraNone;
    79.         else if (Input.GetKey(rightMouse))
    80.             cameraState = CameraState.CameraRotate;
    81.         else if (!Input.GetKey(leftMouse) && Input.GetKey(rightMouse) && !Input.GetKey(middleMouse)) //if left mouse button is pressed
    82.             cameraState = CameraState.CameraSteer;
    83.  
    84.         CameraClipInfo();
    85.         CameraCollisions();
    86.         CameraInputs();
    87.         ScrollCam();
    88.         CameraTransform();
    89.     }
    90.     void LateUpdate()
    91.     {
    92.         panAngle = Vector3.SignedAngle(transform.forward, player.transform.forward, Vector3.up);
    93.  
    94.         switch (camMoveState)
    95.         {
    96.             case CameraMoveState.OnlyWhileMoving:
    97.                 if (player.inputNormalized.magnitude > 0 || player.rotSpeed != 0)
    98.                 {
    99.                     CameraXAdjust();
    100.                     CameraYAdjust();
    101.                 }
    102.                 break;
    103.  
    104.             case CameraMoveState.OnlyHorizontalWhileMoving:
    105.                 if (player.inputNormalized.magnitude > 0 || player.rotSpeed != 0)
    106.                     CameraXAdjust();
    107.                 break;
    108.  
    109.             case CameraMoveState.AlwaysAdjust:
    110.                 CameraXAdjust();
    111.                 CameraYAdjust();
    112.                 break;
    113.  
    114.             case CameraMoveState.NeverAdjust:
    115.                 CameraNeverAdjust();
    116.                 break;
    117.         }
    118.     }
    119.  
    120.  
    121.     void CameraInputs()
    122.     {
    123.  
    124.         if (cameraState != CameraState.CameraNone)
    125.         {
    126.             if (!camYAdjust && (camMoveState == CameraMoveState.AlwaysAdjust || camMoveState == CameraMoveState.OnlyWhileMoving))
    127.                 camYAdjust = true;
    128.  
    129.             if (cameraState == CameraState.CameraRotate)
    130.                 if(!camXAdjust && camMoveState != CameraMoveState.NeverAdjust)
    131.                     camXAdjust = true;
    132.             if (player.steer)
    133.                 player.steer = false;
    134.  
    135.             currentPan += Input.GetAxis("Mouse X") * camSpeed;
    136.          
    137.  
    138.             currentTilt -= Input.GetAxis("Mouse Y") * camSpeed;
    139.             currentTilt = Mathf.Clamp(currentTilt, camMinTilt, camMaxTilt);
    140.  
    141.         }
    142.         if (!player.steer)
    143.         {
    144.             Vector3 playerReset = player.transform.eulerAngles;
    145.             playerReset.y = transform.eulerAngles.y;
    146.  
    147.             player.transform.eulerAngles = playerReset;
    148.  
    149.             player.steer = true;
    150.         }
    151.      
    152.         //Keyboard & Mouse
    153.         if (Input.GetKey(rightMouse))
    154.         {
    155.             Cursor.visible = false;
    156.             Cursor.lockState = CursorLockMode.Locked;
    157.         }
    158.  
    159.         else if (Cursor.visible == false)
    160.         {
    161.             Cursor.visible = true;
    162.             Cursor.lockState = CursorLockMode.None;
    163.         }
    164.     }
    165.     public void ScrollCam()
    166.     {
    167.         currentDistance -= Input.GetAxis("Mouse ScrollWheel") * scrollSpeed * Time.deltaTime;
    168.         currentDistance = Mathf.Clamp(currentDistance, 0, scrollMax);
    169.     }
    170.  
    171.     public void CameraTransform()
    172.     {
    173.         switch (cameraState)
    174.         {
    175.             case CameraState.CameraNone:
    176.                 currentPan = currentPan = player.transform.eulerAngles.y;
    177.                 currentTilt = 10;
    178.                 break;
    179.         }
    180.  
    181.         transform.position = player.transform.position + Vector3.up * camHeight;
    182.         transform.eulerAngles = new Vector3(transform.eulerAngles.x, currentPan, transform.eulerAngles.z);
    183.         tilt.eulerAngles = new Vector3(currentTilt, transform.eulerAngles.y, transform.eulerAngles.z);
    184.         mainCam.transform.position = transform.position + tilt.forward * -currentDistance;
    185.     }
    186.     void CameraClipInfo()
    187.     {
    188.         camClip = new Vector3[4];
    189.  
    190.         mainCam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), mainCam.nearClipPlane, Camera.MonoOrStereoscopicEye.Mono, camClip);
    191.  
    192.         clipDirection = new Vector3[4];
    193.         playerClip = new Vector3[4];
    194.  
    195.         int rays = rayGridX * rayGridY;
    196.  
    197.         rayColOrigin = new Vector3[rays];
    198.         rayColPoint = new Vector3[rays];
    199.         rayColHit = new bool[rays];
    200.     }
    201.     void CameraCollisions()
    202.     {
    203.         float camDistance = currentDistance + collisionCushion;
    204.  
    205.         for (int i = 0; i < camClip.Length; i++)
    206.         {
    207.             Vector3 clipPoint = mainCam.transform.up * camClip[i].y + mainCam.transform.right * camClip[i].x;
    208.             clipPoint *= clipCushion;
    209.             clipPoint += mainCam.transform.forward * camClip[i].z;
    210.             clipPoint += transform.position - (tilt.forward * camMaxDistance);
    211.  
    212.             Vector3 playerPoint = mainCam.transform.up * camClip[i].y + mainCam.transform.right * camClip[i].x;
    213.             playerPoint += transform.position;
    214.  
    215.             clipDirection[i] = (clipPoint - playerPoint).normalized;
    216.             playerClip[i] = playerPoint;
    217.         }
    218.  
    219.         int currentRay = 0;
    220.         bool isColliding = false;
    221.  
    222.         float rayX = rayGridX - 1;
    223.         float rayY = rayGridY - 1;
    224.  
    225.         for (int x = 0; x < rayGridX; x++)
    226.         {
    227.             Vector3 CU_Point = Vector3.Lerp(clipDirection[1], clipDirection[2], x / rayX);
    228.             Vector3 CL_Point = Vector3.Lerp(clipDirection[0], clipDirection[3], x / rayX);
    229.  
    230.             Vector3 PU_Point = Vector3.Lerp(playerClip[1], playerClip[2], x / rayX);
    231.             Vector3 PL_Point = Vector3.Lerp(playerClip[0], playerClip[3], x / rayX);
    232.  
    233.             for (int y = 0; y < rayGridY; y++)
    234.             {
    235.                 camRay.origin = Vector3.Lerp(PU_Point, PL_Point, y / rayY);
    236.                 camRay.direction = Vector3.Lerp(CU_Point, CL_Point, y / rayY);
    237.                 rayColOrigin[currentRay] = camRay.origin;
    238.  
    239.                 if (Physics.Raycast(camRay, out camRayHit, camDistance))
    240.                 {
    241.                     isColliding = true;
    242.                     rayColHit[currentRay] = true;
    243.                     rayColPoint[currentRay] = camRayHit.point;
    244.  
    245.                     if (collisionDebug)
    246.                     {
    247.                         Debug.DrawLine(camRay.origin, camRayHit.point, Color.cyan);
    248.                         Debug.DrawLine(camRayHit.point, camRay.origin + camRay.direction * camDistance, Color.magenta);
    249.                     }
    250.                 }
    251.                 else
    252.                 {
    253.                     if (collisionDebug)
    254.                         Debug.DrawLine(camRay.origin, camRay.origin + camRay.direction * camDistance, Color.cyan);
    255.                 }
    256.  
    257.                 currentRay++;
    258.             }
    259.         }
    260.  
    261.         if (isColliding)
    262.         {
    263.             float minRayDistance = float.MaxValue;
    264.             currentRay = 0;
    265.  
    266.             for (int i = 0; i < rayColHit.Length; i++)
    267.             {
    268.                 if (rayColHit[i])
    269.                 {
    270.                     float colDistance = Vector3.Distance(rayColOrigin[i], rayColPoint[i]);
    271.  
    272.                     if (colDistance < minRayDistance)
    273.                     {
    274.                         minRayDistance = colDistance;
    275.                         currentRay = i;
    276.                     }
    277.                 }
    278.             }
    279.  
    280.             Vector3 clipCenter = transform.position - (tilt.forward * currentDistance);
    281.  
    282.             adjustedDistance = Vector3.Dot(-mainCam.transform.forward, clipCenter - rayColPoint[currentRay]);
    283.             adjustedDistance = currentDistance - (adjustedDistance + collisionCushion);
    284.             adjustedDistance = Mathf.Clamp(adjustedDistance, 0, camMaxDistance);
    285.         }
    286.         else
    287.             adjustedDistance = currentDistance;
    288.     }
    289.  
    290.     void CameraXAdjust()
    291.     {
    292.         if (cameraState != CameraState.CameraRotate)
    293.         {
    294.             if (camXAdjust)
    295.             {
    296.                 rotationXSpeed += Time.deltaTime * cameraAdjustSpeed;
    297.  
    298.                 if (Mathf.Abs(panAngle) > rotationXCushion)
    299.                     currentPan = Mathf.Lerp(currentPan, currentPan + panAngle, rotationXSpeed);
    300.                 else
    301.                     camXAdjust = false;
    302.             }
    303.             else
    304.             {
    305.                 if (rotationXSpeed > 0)
    306.                     rotationXSpeed = 0;
    307.  
    308.                 currentPan = player.transform.eulerAngles.y;
    309.             }
    310.         }
    311.     }
    312.  
    313.     void CameraYAdjust()
    314.     {
    315.         if (cameraState == CameraState.CameraNone)
    316.         {
    317.             if (camYAdjust)
    318.             {
    319.                 rotationYSpeed += (Time.deltaTime / 2) * cameraAdjustSpeed;
    320.  
    321.                 if (currentTilt >= yRotMax || currentTilt <= yRotMin)
    322.                     currentTilt = Mathf.Lerp(currentTilt, yRotMax / 2, rotationYSpeed);
    323.                 else if (currentTilt < yRotMax && currentTilt > yRotMin)
    324.                     camYAdjust = false;
    325.             }
    326.             else
    327.             {
    328.                 if (rotationYSpeed > 0)
    329.                     rotationYSpeed = 0;
    330.             }
    331.         }
    332.     }
    333.     void CameraNeverAdjust()
    334.     {
    335.         switch (cameraState)
    336.         {
    337.             case CameraState.CameraSteer:
    338.  
    339.                 if (panOffset != 0)
    340.                     panOffset = 0;
    341.  
    342.                 currentPan = player.transform.eulerAngles.y;
    343.                 break;
    344.  
    345.             case CameraState.CameraNone:
    346.                 currentPan = player.transform.eulerAngles.y - panOffset;
    347.                 break;
    348.  
    349.             case CameraState.CameraRotate:
    350.                 panOffset = panAngle;
    351.                 break;
    352.         }
    353.     }
    354.  
    355.     public enum CameraState
    356.     {
    357.         CameraNone,
    358.         CameraRotate,
    359.         CameraSteer
    360.  
    361.     }
    362.     public enum CameraMoveState
    363.     {
    364.         OnlyWhileMoving,
    365.         OnlyHorizontalWhileMoving,
    366.         AlwaysAdjust,
    367.         NeverAdjust
    368.  
    369.     }
    370.  
    371.     public void OnDisabled()
    372.     {
    373.         Cursor.visible = true;
    374.         Cursor.lockState = CursorLockMode.None;
    375.         enabled = false;
    376.  
    377.     }
    378.  
    379. }
    380.  
    As you can see the camera has a lot of features. I been working on it a very long time.
     
    Last edited: Mar 30, 2023
  2. true_warlock

    true_warlock

    Joined:
    Aug 2, 2019
    Posts:
    60
    Note: I was going to use the Free character controller but I dont like all its dependencies. Just thought I'd make note of that. Thanks.