How to properly use CharacterController.Move() to move the character

14,805

Solution 1

The solution is to use a normalized vector for the direction of the movement.

// Get Horizontal and Vertical Input
float horizontalInput = Input.GetAxis ("Horizontal");
float verticalInput = Input.GetAxis ("Vertical");

// Calculate the Direction to Move based on the tranform of the Player
Vector3 moveDirectionForward = transform.forward * verticalInput;
Vector3 moveDirectionSide = transform.right * horizontalInput;

//find the direction
Vector3 direction = (moveDirectionForward + moveDirectionSide).normalized;
//find the distance
Vector3 distance = direction * walkSpeed * Time.deltaTime;

// Apply Movement to Player
myCharacterController.Move (distance);

Performance note:

vector.normalized is obtained from vector/vector.magnitude and vector.magnitude is obtained from sqrt(vector.sqrMagnitude) which is heavy to process. To reduce the processing weight you can use vector/vector.sqrMagnitude instead of vector.normalized but be ware the result is not exactly the same, but still is in the same direction.


now i just need to apply gravity

Subtract moveDirection.y by the gravity multiplied by Time.deltaTime. You can also simplify and reduce the code in the MovePlayer function by using Vector3 and TransformDirection.

public float walkSpeed = 10.0f;
private Vector3 moveDirection = Vector3.zero;
public float gravity = 20.0F;
CharacterController myCharacterController = null;

void Start()
{
    myCharacterController = GetComponent<CharacterController>();
}

void MovePlayer()
{
    moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
    moveDirection = transform.TransformDirection(moveDirection);
    moveDirection *= walkSpeed;

    moveDirection.y -= gravity * Time.deltaTime;
    myCharacterController.Move(moveDirection * Time.deltaTime);
}

Solution 2

You will want to use the normalized vector of the two axes when you multiply by your walkSpeed. The reason being is this will ensure that you always move in any direction with the same magnitude (1) no matter the angle. Whereas your current setup has non-orthogonal movement being being calculated at >1 magnitude. So something like this should work in your situation.

void MovePlayer()
{

    // Get Horizontal and Vertical Input
    float horizontalInput = Input.GetAxis("Horizontal");
    float verticalInput = Input.GetAxis("Vertical");

    // Calculate the Direction to Move based on the tranform of the Player
    Vector3 moveDirectionForward = transform.forward * verticalInput * Time.deltaTime;
    Vector3 moveDirectionSide = transform.right * horizontalInput * Time.deltaTime;

    // Apply Movement to Player
    myCharacterController.SimpleMove((moveDirectionForward + moveDirectionSide).normalized * walkspeed);

Simply move the walkSpeed multiplication to the SimpleMove call against the normalized vector. The image below should help to visualize the problem you're having. By normalizing the vector before applying the walk speed, you're making sure that the direction vector is the same magnitude (effectively distance in this case) no matter what direction before you apply the walk speed.

enter image description here

Share:
14,805
Gerte
Author by

Gerte

Updated on June 05, 2022

Comments

  • Gerte
    Gerte almost 2 years

    I created a basic First Person Controller but my problem is when i move both forward and sideways i move faster.

    How can i add moveDirectionForward and moveDirectionSide in 1 Vector3 to be able to use CharacterController.Move() instead of CharacterController.SimpleMove()?

    void MovePlayer() {
    
        // Get Horizontal and Vertical Input
        float horizontalInput = Input.GetAxis ("Horizontal");
        float verticalInput = Input.GetAxis ("Vertical");
    
        // Calculate the Direction to Move based on the tranform of the Player
        Vector3 moveDirectionForward = transform.forward * verticalInput * walkSpeed * Time.deltaTime;
        Vector3 moveDirectionSide = transform.right * horizontalInput * walkSpeed * Time.deltaTime;
    
        // Apply Movement to Player
        myCharacterController.SimpleMove (moveDirectionForward + moveDirectionSide);
    
  • Programmer
    Programmer almost 6 years
    I think you missed the CharacterController.Move part. Op wants to use that instead of SimpleMove.
  • Gerte
    Gerte almost 6 years
    I can use .Move now i just need to apply gravity. Thanks for help!
  • Gerte
    Gerte almost 6 years
    by reducing the code i get the same problem i move faster
  • PassetCronUs
    PassetCronUs almost 6 years
    I think you have to normalize the direction like Bijan did transform.TransformDirection(moveDirection.normalized); instead of transform.TransformDirection(moveDirection). If that doesn't work, undo what you just did and just replace moveDirection *= walkSpeed; with moveDirection = moveDirection.normalized * walkSpeed;.
  • Gerte
    Gerte almost 6 years
    Yeah adding .normalized to the reduced code version works. Thanks everyone for the help. I got some studying to do now, i learned a lot from this problem.