Search Unity

Question Need help setting character movement by camera reference.

Discussion in 'Scripting' started by krnlvr666, Sep 22, 2021.

  1. krnlvr666

    krnlvr666

    Joined:
    Jan 15, 2013
    Posts:
    1
    I have tried multiple ways to add character movement by camera reference to the current code I have (using camera.main.transform / transform.right / forward etc..) without any success.

    I am using a Quaternion equation right now to handle the rotation of the player, but it is set to use movements that are referencing the x and z axis.

    I removed a few ways I tried to implement this change to keep the game running the way it did before, so things might look messy right now. Sorry.

    Any help would be appreciated.

    (The intended behavior I am looking for is that the camera will be able to be controlled, and that the player will move according to the camera direction, without changing the other behaviors I have set.)


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class AnimationAndMovementController : MonoBehaviour
    7. {
    8.     //declare reference variables
    9.     PlayerInput playerInput;
    10.     CharacterController characterController;
    11.     Animator animator;
    12.  
    13.     //variables to store optimized setter/getter parameter IDs
    14.     int isWalkingHash;
    15.     int isRunningHash;
    16.    
    17.  
    18.     //variables to store player input values
    19.     Vector2 currentMovementInput;
    20.     Vector3 currentMovement;
    21.     Vector3 currentRunMovement;
    22.     bool isMovementPressed;
    23.     bool isRunPressed;
    24.  
    25.     //constants
    26.     [SerializeField] float rotationFactorPerFrame = 15.0f;
    27.     [SerializeField] float runMultiplier = 4.0f;
    28.     [SerializeField] float walkMultiplier = 1.5f;
    29.     [SerializeField] float groundedGravity = -0.5f;
    30.     [SerializeField] float gravity = -9.8f;
    31.  
    32.     //jumping variables
    33.     bool isJumpPressed = false;
    34.     float initialJumpVelocity;
    35.     [SerializeField] float maxJumpHeight = 6.0f;
    36.     [SerializeField] float maxJumpTime = 1.0f;
    37.     bool isJumping = false;
    38.     int isJumpingHash;
    39.     bool isJumpAnimating = false;
    40.  
    41.     //Camera variables
    42.     private Transform cameraMainTransform;
    43.     Vector2 cameraMainMovementInput;
    44.     Vector3 cameraMainMovement;
    45.     bool isCamMoving = false;
    46.  
    47.     //Awake is called earlier than Start in Unity's event life cycle
    48.     void Awake()
    49.     {
    50.         //initially set reference variable
    51.         playerInput = new PlayerInput();
    52.         characterController = GetComponent<CharacterController>();
    53.         animator = GetComponent<Animator>();
    54.  
    55.         isWalkingHash = Animator.StringToHash("isWalking");
    56.         isRunningHash = Animator.StringToHash("isRunning");
    57.         isJumpingHash = Animator.StringToHash("isJumping");
    58.  
    59.         //set the player input callbacks
    60.         playerInput.CharacterControls.Move.started += onMovementInput;
    61.         playerInput.CharacterControls.Move.canceled += onMovementInput;
    62.         playerInput.CharacterControls.Move.performed += onMovementInput;
    63.         playerInput.CharacterControls.Run.started += onRun;
    64.         playerInput.CharacterControls.Run.canceled += onRun;
    65.         playerInput.CharacterControls.Jump.started += onJump;
    66.         playerInput.CharacterControls.Jump.canceled += onJump;
    67.  
    68.         setupJumpVariables();
    69.  
    70.         //Cam move input callbacks test
    71.         playerInput.CharacterControls.CamMove.started += onCamMove;
    72.         playerInput.CharacterControls.CamMove.canceled += onCamMove;
    73.         playerInput.CharacterControls.CamMove.performed += onCamMove;
    74.         // had to disable this since it broke movement
    75.         // cameraMainTransform = Camera.main.transform;
    76.  
    77.     }
    78.  
    79.     void setupJumpVariables()
    80.     {
    81.         float timeToApex = maxJumpTime / 2;
    82.         gravity = (-2 * maxJumpHeight) / Mathf.Pow(timeToApex, 2);
    83.         initialJumpVelocity = (2 * maxJumpHeight) / timeToApex;
    84.     }
    85.  
    86.     void handleJump()
    87.     {
    88.         if (!isJumping && characterController.isGrounded && isJumpPressed)
    89.         {
    90.             animator.SetBool(isJumpingHash, true);
    91.             isJumping = true;
    92.             isJumpAnimating = true;          
    93.             currentMovement.y = initialJumpVelocity * .5f;
    94.             currentRunMovement.y = initialJumpVelocity * .5f;
    95.         } else if (!isJumpPressed && isJumping && characterController.isGrounded)
    96.         {
    97.             isJumping = false;
    98.         }
    99.     }
    100.  
    101.     void onJump (InputAction.CallbackContext context)
    102.     {
    103.         isJumpPressed = context.ReadValueAsButton();
    104.         Debug.Log(isJumpPressed);
    105.     }
    106.  
    107.     void onRun (InputAction.CallbackContext context)
    108.     {
    109.         isRunPressed = context.ReadValueAsButton();
    110.     }
    111.  
    112.     //Camera movement attempt
    113.     void onCamMove (InputAction.CallbackContext context)
    114.     {
    115.         cameraMainMovementInput = context.ReadValue<Vector2>();
    116.         Debug.Log(cameraMainMovementInput);
    117.         cameraMainMovement.x = cameraMainMovementInput.x;
    118.         cameraMainMovement.y = cameraMainMovementInput.y;
    119.  
    120.         isCamMoving = cameraMainMovementInput.x != 0 || cameraMainMovementInput.y != 0;
    121.     }
    122.  
    123.     void onMovementInput (InputAction.CallbackContext context)
    124.     {      
    125.         currentMovementInput = context.ReadValue<Vector2>();      
    126.         currentMovement.x = currentMovementInput.x * walkMultiplier;
    127.         currentMovement.z = currentMovementInput.y * walkMultiplier;
    128.         currentRunMovement.x = currentMovementInput.x * runMultiplier;
    129.         currentRunMovement.z = currentMovementInput.y * runMultiplier;
    130.  
    131.         isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
    132.     }
    133.  
    134.     void handleRotation()
    135.     {
    136.        
    137.         Vector3 positionToLookAt;
    138.         // the change in position our character should point to
    139.         positionToLookAt.x = currentMovement.x;
    140.         positionToLookAt.y = 0.0f;
    141.         positionToLookAt.z = currentMovement.z;
    142.         //current rotation of the character
    143.         Quaternion currentRotation = transform.rotation;
    144.  
    145.         //creates a new rotation based on where the player is pressing
    146.         if (isMovementPressed)
    147.         {
    148.             Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
    149.             transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactorPerFrame * Time.deltaTime);
    150.         }
    151.  
    152.     }
    153.  
    154.     void handleAnimation()
    155.     {
    156.         bool isWalking = animator.GetBool(isWalkingHash);
    157.         bool isRunning = animator.GetBool(isRunningHash);
    158.  
    159.         if (isMovementPressed && !isWalking)
    160.         {
    161.             animator.SetBool(isWalkingHash, true);
    162.         }
    163.  
    164.         else if (!isMovementPressed && isWalking)
    165.         {
    166.             animator.SetBool(isWalkingHash, false);
    167.         }
    168.  
    169.         if ((isMovementPressed && isRunPressed) && !isRunning)
    170.         {
    171.             animator.SetBool(isRunningHash, true);
    172.         }
    173.         else if ((!isMovementPressed || !isRunPressed) && isRunning)
    174.         {
    175.             animator.SetBool(isRunningHash, false);
    176.         }
    177.     }
    178.  
    179.     void handleGravity()
    180.     {
    181.         bool isFalling = currentMovement.y <= 0.0f || !isJumpPressed;
    182.         float fallMultiplier = 2.0f;
    183.  
    184.         if (characterController.isGrounded)
    185.         {
    186.             if (isJumpAnimating)
    187.             {
    188.                 animator.SetBool(isJumpingHash, false);
    189.             }
    190.             currentMovement.y = groundedGravity;
    191.             currentRunMovement.y = groundedGravity;
    192.         } else if (isFalling) {
    193.             float previousYVelocity = currentMovement.y;
    194.             float newYVelocity = currentMovement.y + (gravity * fallMultiplier * Time.deltaTime);
    195.             float nextYvelocity = Mathf.Max((previousYVelocity + newYVelocity) * .5f, -20.0f);
    196.             currentMovement.y = nextYvelocity;
    197.             currentRunMovement.y = nextYvelocity;
    198.         } else {
    199.             float previousYVelocity = currentMovement.y;
    200.             float newYVelocity = currentMovement.y + (gravity * Time.deltaTime);
    201.             float nextYvelocity = (previousYVelocity + newYVelocity) * .5f;
    202.             currentMovement.y = nextYvelocity;
    203.             currentRunMovement.y = nextYvelocity;
    204.         }
    205.     }
    206.  
    207.     // Update is called once per frame
    208.     void Update()
    209.     {
    210.         handleRotation();
    211.         handleAnimation();
    212.  
    213.      
    214.         if (isRunPressed)
    215.         {
    216.             characterController.Move(currentRunMovement * Time.deltaTime);
    217.         }
    218.         else
    219.         {
    220.             characterController.Move(currentMovement * Time.deltaTime);
    221.         }
    222.                
    223.         handleGravity();
    224.         handleJump();
    225.     }
    226.  
    227.     void OnEnable()
    228.     {
    229.         playerInput.CharacterControls.Enable();
    230.     }
    231.  
    232.     private void OnDisable()
    233.     {
    234.         playerInput.CharacterControls.Disable();
    235.     }
    236. }
    237.  
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    You can see some functioning code for this here:

    https://github.com/kurtdekker/proxi...edControls/RotatedControlsPlayerController.cs

    Look at around lines 126 and 128 for where it makes a rotation according to camera heading and then rotates the raw inputs (pre-stored in X/Z, not X/Y!!! See line 110 for example) to align before using the inputs to move the player.

    Download the whole thing and run the
    DemoCameraRotatedControls.unity
    scene.

    The code kinda chops it all up, gives explicit and implicit controls to the camera.
     
  3. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,859
    CatlikeCoding has a good tutorial that covers this in their orbiting camera tutorial: https://catlikecoding.com/unity/tutorials/movement/orbit-camera/

    Way down in section 3 it covers how to get a direction based on the camera. It primarily involves getting the forward and right vectors of the camera, flattening/normalising them them, and acting based on that.

    I personally make a small component attached to the camera that calculates these vectors and sets those values on a pair of scriptable objects that just hold a vector3. The player controller references these SO's too and can act based on the values they have.
     
    krnlvr666 and Kurt-Dekker like this.