Third person WOW like camera

So maybe it was me not finding a solution for it on the forums, but since I didn’t, I will post it here for you.

My problem was, that the new standard third person controller didn’t have a WOW like camera nor could I attach it properly to like the previous, older standard one. There is a very good thread about a working WOW like camera written by several developers, and I wanted to implement that to Ethan. The problem was, whenever I attached the camera, you could move the camera fine, but Ethan would move pretty strange for himself, so I wanted to find a solution.

It might sound pretty trivial, but maybe it will come handy for new comers. I’ll post my solution as an answer below.

I will post the WOW camera script at the bottom, but for now I’ll explain the hierarchy.

The first thing you need of course is Ethan a.k.a the standard third person controller prefab. Attach a camera to his prefab and name it Main Camera and also don’t forget to set its tag to MainCamera.

[114269-screen-shot-2018-04-04-at-221619.png|114269]

Then attach the WOW camera script to the Main Camera as a component.

[114271-screen-shot-2018-04-04-at-221631.png|114271]

It will throw an error in the ThirdPersonCharacter.cs script, that there was a null reference somewhere. If that happens, just open the script and edit the Start() {…} function to Awake() {…} and there won’t be any errors.

It doesn’t seem a big kind of a deal, but I’m sure for a lot of people this is a pretty easy way to have a good type of camera for your 3rd person RPG.

Here’s the WOW camera script, what you will need for this:

using UnityEngine;
using System.Collections;

public class WowCamera : MonoBehaviour
{
	public Transform target;

	public float targetHeight = 1.7f;
	public float distance = 5.0f;
	public float offsetFromWall = 0.1f;

	public float maxDistance = 20;
	public float minDistance = .6f;
	public float speedDistance = 5;

	public float xSpeed = 200.0f;
	public float ySpeed = 200.0f;

	public int yMinLimit = -40;
	public int yMaxLimit = 80;

	public int zoomRate = 40;

	public float rotationDampening = 3.0f;
	public float zoomDampening = 5.0f;

	public LayerMask collisionLayers = -1;

	private float xDeg = 0.0f;
	private float yDeg = 0.0f;
	private float currentDistance;
	private float desiredDistance;
	private float correctedDistance;

	void Start ()
	{
		Vector3 angles = transform.eulerAngles;
		xDeg = angles.x;
		yDeg = angles.y;

		currentDistance = distance;
		desiredDistance = distance;
		correctedDistance = distance;

		// Make the rigid body not change rotation
		if (this.gameObject.GetComponent<Rigidbody>())
			this.gameObject.GetComponent<Rigidbody>().freezeRotation = true;
	}

	/**
     * Camera logic on LateUpdate to only update after all character movement logic has been handled.
     */
	void LateUpdate ()
	{
		Vector3 vTargetOffset;

		// Don't do anything if target is not defined
		if (!target)
			return;

		// If either mouse buttons are down, let the mouse govern camera position
		if (GUIUtility.hotControl == 0) {
			if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
			{
				xDeg += Input.GetAxis ("Mouse X") * xSpeed * 0.02f;
				yDeg -= Input.GetAxis ("Mouse Y") * ySpeed * 0.02f;
			}

			// otherwise, ease behind the target if any of the directional keys are pressed
			else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
			{
				float targetRotationAngle = target.eulerAngles.y;
				float currentRotationAngle = transform.eulerAngles.y;
				xDeg = Mathf.LerpAngle (currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
			}
		}


		// calculate the desired distance
		desiredDistance -= Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs (desiredDistance) * speedDistance;
		desiredDistance = Mathf.Clamp (desiredDistance, minDistance, maxDistance);

		yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);

		// set camera rotation
		Quaternion rotation = Quaternion.Euler(yDeg, xDeg, 0);
		correctedDistance = desiredDistance;

		// calculate desired camera position
		vTargetOffset = new Vector3 (0, -targetHeight, 0);
		Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + vTargetOffset);

		// check for collision using the true target's desired registration point as set by user using height
		RaycastHit collisionHit;
		Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y, target.position.z) - vTargetOffset;

		// if there was a collision, correct the camera position and calculate the corrected distance
		bool isCorrected = false;
		if (Physics.Linecast (trueTargetPosition, position, out collisionHit, collisionLayers.value))
		{
			// calculate the distance from the original estimated position to the collision location,
			// subtracting out a safety "offset" distance from the object we hit.  The offset will help
			// keep the camera from being right on top of the surface we hit, which usually shows up as
			// the surface geometry getting partially clipped by the camera's front clipping plane.
			correctedDistance = Vector3.Distance (trueTargetPosition, collisionHit.point) - offsetFromWall;
			isCorrected = true;
		}

		// For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
		currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp (currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;

		// keep within legal limits
		currentDistance = Mathf.Clamp (currentDistance, minDistance, maxDistance);

		// recalculate position based on the new currentDistance
		position = target.position - (rotation * Vector3.forward * currentDistance + vTargetOffset);

		transform.rotation = rotation;
		transform.position = position;
	}

	private static float ClampAngle (float angle, float min, float max)
	{
		if (angle < -360)
			angle += 360;
		if (angle > 360)
			angle -= 360;
		return Mathf.Clamp (angle, min, max);
	}
}

Your code is great ! But I don’t know why, when i’m turning left, camera is not following…