8-Axis 3D Top Down Movement

Hi there, I’ve been trying to create an 8-axis top down style movement in which the player object moves in the direction of the pressed key and simultaneously (however still smoothed) rotates to the direction it is moving in. I had a version of it prior that used a rigidbody but I’m trying to use a CharacterController instead since it for the most part is more fluid and less physics based for acceleration and friction. Using the base Controller.Move script provided on the API:

    public float speed = 6.0F;
    public float jumpSpeed = 8.0F;
    public float gravity = 20.0F;
    private Vector3 moveDirection = Vector3.zero;
    void Update() {
        CharacterController controller = GetComponent<CharacterController>();
        if (controller.isGrounded) {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
            moveDirection = transform.TransformDirection(moveDirection);
            moveDirection *= speed;
            if (Input.GetButton("Jump"))
                moveDirection.y = jumpSpeed;
            
        }
        moveDirection.y -= gravity * Time.deltaTime;
        controller.Move(moveDirection * Time.deltaTime);
    }

I then attempted to simply add a: transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection), 0.15f);

However, that doesn’t work as it just causes the controller to spin forever to it’s right or left in place and not even begin to move towards the right or left direction. It basically functions like Resident Evil 4’s tank controls.

All I want is to have the player object rotate to the right and rotate to face to the right when pressing “D” and so on. Any help would be greatly appreciated I’ve been at this for a few hours.

What you can do is to split a hierarchy for your player object into “movable” and “rotatable” parts and put “rotatable” into “movable” so the hierarchy to be like the following:

  • (parent) “player” (with CharacterController
    attached)
  • (child) “rotatable transform” - Transform to rotate separately from
  • (child of the child) “player” visual component(s) like mesh, etc.

Then just use your slightly modified code:

[SerializeField]
private Transform rotatableTransform = null;  // link the reference in editor to "rotatable transform"

     void Update() {
         CharacterController controller = GetComponent<CharacterController>();
         if (controller.isGrounded) {
             moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
             moveDirection = transform.TransformDirection(moveDirection);
             moveDirection *= speed;
             if (Input.GetButton("Jump"))
                 moveDirection.y = jumpSpeed;
             
         }
         moveDirection.y -= gravity * Time.deltaTime;
         controller.Move(moveDirection * Time.deltaTime);

         rotatableTransform.rotation = Quaternion.Slerp(rotatableTransform.rotation, Quaternion.LookRotation(moveDirection), 0.15f);
     }

Problem you will meet: special handling of “moveDirection” = 0 required.