- Home /
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.
Answer by victorbisaev · Jan 28, 2018 at 11:50 PM
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.
Just to add some more to this script I added an if to the rotatableTransform script in which the character only rotates if either axis are being pressed. This should fix the special handling mentioned if I don't do this the character will return to a default rotation which isn't something we want. To further add to the script I only want to rotate our character at the X and Z axis because if not our player will tend to lean a bit which isn't something you want.