Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

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:
    56
    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:
    56
    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.