Rotate Character towards Movement Direction

Might seem like a relatively simple thing but it’s just not working for me, all the answers I’ve found online do not work.

I want my character to face the direction he moves when strafing, moving forwards, or backwards. Quaternion.LookRotation causes him to spin rapidly and I can’t feed a transform.Rotate(moveDirection) into Y only when he needs to move for both X and Z

using UnityEngine;
using System.Collections;

[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Rigidbody))]
public class PlayerMovement : MonoBehaviour
{
	public CharacterController characterController;
	public Animator anim;
	public Camera cam;

	public float moveSpeed = 5f;
	public float turnSpeed = 15f;
	public float gravity = 21f;
	
	private float h;
	private float v;
	private float s;
	private float mh;
	private float mv;
	private float deadZone = 0.1f;
	private Vector3 moveDirection = Vector3.zero;
	private Vector3 turnDirection = Vector3.zero;

	void Awake()
	{
		//need access to the character controller and animator
		anim = GetComponentInChildren<Animator> ();
		characterController = GetComponent<CharacterController> ();
		cam = Camera.main;
	}

	void Update()
	{
		//cache the inputs
		h = Input.GetAxis ("Horizontal");
		v = Input.GetAxis ("Vertical");
		s = Input.GetAxis ("Strafe");
		mh = Input.GetAxis ("Mouse X");
		mv = Input.GetAxis ("Mouse Y");

		moveDirection = Vector3.zero;

		//check if it's grounded, otherwise player cannot move, also check for the deadzone
		if(characterController.isGrounded)
		{
			ProcessVerticalMovement(v);
			ProcessHorizontalMovement(h, mh, s);

			//normalize the diagonal inputs to prevent values above 1
			if (moveDirection.magnitude > 1)
			{
				moveDirection.Normalize ();
			}

			moveDirection = transform.TransformDirection(moveDirection);
		}

		//set the animator's Speed float to the magnitude of the moveDirection to allow for the run animation to play
		anim.SetFloat ("Speed", moveDirection.magnitude);

		//calculate gravity
		moveDirection.y -= gravity * Time.deltaTime;

		//move the character

		characterController.Move (moveDirection * moveSpeed * Time.deltaTime);
		transform.Rotate(turnDirection * Time.deltaTime);
		transform.Rotate (0f, moveDirection.x, 0f);
		//transform.rotation = Quaternion.LookRotation(moveDirection);
	}

	void ProcessVerticalMovement(float v)
	{
		if (v > deadZone || v < -deadZone)
		{
			moveDirection = new Vector3 (0f, 0f, v);

		}
	}
	
	void ProcessHorizontalMovement(float h, float mh, float s)
	{
		
		//if player is holding RMB while horizontal input then strafe
		if((s > deadZone || s < -deadZone) || (Input.GetButton("CameraTurn") && (h > deadZone || h < -deadZone)))
		{
			Debug.Log ("strafing");
			if(s > deadZone || s < -deadZone)
			{
				moveDirection.x = s;
			}else
				moveDirection.x = h;

		}
		//if player is pressing horizontal input then turn, or if player has RMB down (but not horizontal input) then turn
		if(Input.GetButton("CameraTurn") && (mh > deadZone || mh < -deadZone))
		{
			turnDirection = new Vector3(0f, mh * 200f, 0f);

		}else if(!Input.GetButtonDown("CameraTurn") && (h > deadZone || h < -deadZone))
		{
			turnDirection = new Vector3(0f, h * turnSpeed, 0f);

		}else
			turnDirection = Vector3.zero;

	}
}

The problem is probably that your user input is interpreted relative to the transform, and on the basis of that input you also update the transform’s orientation - which means that on the next frame, the user’s input is interpreted differently again. Unless the user input is straight up, it’s going to spin on the spot really quickly.

If this really is the behaviour you want, but you want it to happen slower, then you could use Quaternion.LookRotation in the way you are now to work out which way you’d like the character to face, then use Quaternion.RotateTowards or similar to limit the rate at which the character actually turns. This means that an input that’s slightly to the side will still cause the character to turn continuously, but at a much slower rate, and the player will have ample opportunity to control the turning and straighten up when the character has turned enough.

Quaternion wanted_rotation = Quaternion.LookRotation(moveDirection);
transform.rotation = Quaternion.RotateTowards(transform.rotation, wanted_rotation, MaxTurnSpeed * Time.deltaTime);

MaxTurnSpeed is measured in degrees per second - try starting with something like 200 and see how it feels.