Camera to Stay Behind an Aircraft

I recently started Unity and have very little scripting knowledge. I am trying to create a camera script for a spaceship that will follow vertically and horizontally. For example, if the ship flies up, the camera will stay behind the ship.

I am currently using the WOW camera script located in this thread: http://forum.unity3d.com/viewtopic.php?t=18073&postdays=0&postorder=asc&start=30

Everything works fine with this, but the camera will only follow on a horizontal level. Is there any way to keep the features of this camera script while integrating a vertical stay behind on my object?

Any input is appreciated.

The C# script attached to my main camera

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 xSpeed = 200.0f; 
    public float ySpeed = 200.0f; 

    public int yMinLimit = -80; 
    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 (rigidbody) 
            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 (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); 
        } 

        yDeg = ClampAngle (yDeg, yMinLimit, yMaxLimit); 

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

        // calculate the desired distance 
        desiredDistance -= Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs (desiredDistance); 
        desiredDistance = Mathf.Clamp (desiredDistance, minDistance, maxDistance); 
        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 + targetHeight, target.position.z); 

        // 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); 
    } 
}

A camera that stays behind the ship can be achieved without code. Just move the camera where you want it, and parent it to the ship in the scene browser. :slight_smile:

Since you are using the (very advanced) WoW style camera, I take it you want it to have more functionality than just staying in the same local coordinates? What should the camera do exactly? How should it move, and when?

You could add some code that modifies the Y component of the position vector the camera-script uses. The simplest thing is to just add the transform.position.y of your ship to the camera’s transform.y component.

1 Like

Thanks for responding. The camera should have dampening. Meaning, it should not immediately move with the turning ship, but instead have a small amount of lag. It should also allow the player to use left click to rotate the camera around the ship and stay behind the ship when it starts moving forward, no matter the direction. Zoom in and out with mouse wheel. All of the features of the WoW camera system.

Sorry, but I’m really new at this. I have no idea how to integrate this into the current code. Will it allow me to keep the features stated above?

I see that the current code uses vector3 position for the camera position under “//calculate desired camera position.” I’m assuming the Vector3 position needs to take into account the pitch of the ship, but have no idea how to do this.

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

Working on a spaceship game right now, here’s my camera…it’s basically just the SmoothFollowCamera in the standard assests folder with a few adjustments. If you want the camera DIRECTLY behind the ship, set height to zero.

var target : Transform;
var distance = 5.0;
var height = 4.0;

var rotationDamping = 3.0;


function LateUpdate () {
	if (!target)
		return;
		
	wantedRotationAngleSide = target.eulerAngles.y;
	currentRotationAngleSide = transform.eulerAngles.y;
	
	wantedRotationAngleUp = target.eulerAngles.x;
	currentRotationAngleUp = transform.eulerAngles.x;
	
	currentRotationAngleSide = Mathf.LerpAngle(currentRotationAngleSide, wantedRotationAngleSide, rotationDamping * Time.deltaTime);
	
	currentRotationAngleUp = Mathf.LerpAngle(currentRotationAngleUp, wantedRotationAngleUp, rotationDamping * Time.deltaTime);
	
	currentRotation = Quaternion.Euler(currentRotationAngleUp, currentRotationAngleSide, 0);
	
	transform.position = target.position;
	transform.position -= currentRotation * Vector3.forward * distance;
	
	transform.LookAt(target);
	
	transform.position += transform.up * height;
}

Thanks! It runs great. I will definitely be using this if I cant get the WoW camera to work the way I want. Much appreciated! :smile:

Thank you for the script Iron-Warrior. your tweaks were really helpful. i’ve just started working on unity 3 days ago. there is just one thing i couldnt manage in the previous script i was using and also this script. that is when you try to do a 360 Degrees rotation with your plane in upward direction, it rotates the camera completely once it reaches 180 degrees. that rotation kind of seems bad… currently trying to figure out what can be done about it…
and Syflux thanks for your script as well its really useful for a top down game.

Thanks much for share…If you want mirror like effect or camera ahead of player then change,

    transform.position -= currentRotation * Vector3.forward * distance;

to

    transform.position -= currentRotation * target.transform.forward * distance;