- Home /
How to make camera rotation relative to target.
I've spliced together a little camera movement script from several others, and all in all it seems to work pretty well... except, i have the script attached to a space ship, and the space ship orbits a planet. the ship rotates on it's y axis as it orbits the planet. the camera stays focused on the ship and rotates around the ship, but is aligned to world space, so if not moved, the ship can be seen rotating around in view, whilst the camera always points in one direction. i'm wondering how i can get the camera to remain aligned with the ship's local space and rotate around it relatively. Here's the script i have so far, the commented out lines of code seemed superfluous and didn't appear to change the operation of the script, but since i'm a noob, i left them in just in case. Also, "Namespace 'UnityEditor' not found" keeps showing up at the top of a lot of my scripts, i think i may have messed something up. i don't know if that'll effect the function of the scripts, but it's really annoying. it doesn't seem to matter what folder i to put them in. some help on that would be appreciated too.
var target : Transform;
var distance = 5.0;
var xSpeed = 20.0;
var ySpeed = 20.0;
var yMinLimit = -90;
var yMaxLimit = 90;
var distanceMin = 5;
var distanceMax = 500;
private var x = 0.0;
private var y = 0.0;
var smoothTime = 0.2;
private var xSmooth = 0.0;
private var ySmooth = 0.0;
private var xVelocity = 0.0;
private var yVelocity = 0.0;
//private var posSmooth = Vector3.zero;
//private var posVelocity = Vector3.zero;
@script AddComponentMenu("Camera-Control/Mouse Orbit")
function Start () {
// var angles = transform.eulerAngles;
//x = angles.y;
//y = angles.x;
// Make the rigid body not change rotation
if (rigidbody)
rigidbody.freezeRotation = true;
}
function LateUpdate ()
{
if (target)
{
if(Input.GetMouseButton(0))
{
x += Input.GetAxis("Mouse X") * xSpeed;
y -= Input.GetAxis("Mouse Y") * ySpeed;
y = Mathf.Clamp(y, yMinLimit, yMaxLimit);
}
xSmooth = Mathf.SmoothDamp(xSmooth, x, xVelocity, smoothTime);
ySmooth = Mathf.SmoothDamp(ySmooth, y, yVelocity, smoothTime);
var rotation = Quaternion.Euler(ySmooth, xSmooth, 0);
//var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
//posSmooth = target.position;
distance = Mathf.Clamp(distance + Input.GetAxis("Mouse ScrollWheel")*distance, distanceMin, distanceMax);
transform.rotation = rotation;
transform.position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
}
}
/*static function ClampAngle (angle : float, min : float, max : float) {
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp (angle, min, max);
}*/
Answer by Celestium · Aug 20, 2013 at 10:34 PM
OMG, I FIGURED IT OUT!!!. thanks Helios, the solution wasn't exactly as you said, but it was close enough to give you some credit. i made the camera a child of the space ship, and then used trial and error to find the correct combination of transform.rotation and transform.localRotation. the final script looks like this, paying special attention to the last two active lines. thanks again for all your help!
var target : Transform;
var distance = 5.0;
var xSpeed = 20.0;
var ySpeed = 20.0;
var yMinLimit = -90;
var yMaxLimit = 90;
var distanceMin = 5;
var distanceMax = 500;
private var x = 0.0;
private var y = 0.0;
var smoothTime = 0.2;
private var xSmooth = 0.0;
private var ySmooth = 0.0;
private var xVelocity = 0.0;
private var yVelocity = 0.0;
//private var posSmooth = Vector3.zero;
//private var posVelocity = Vector3.zero;
@script AddComponentMenu("Camera-Control/Mouse Orbit")
function Start () {
//var angles = transform.eulerAngles;
//x = angles.y;
//y = angles.x;
// Make the rigid body not change rotation
if (rigidbody)
rigidbody.freezeRotation = true;
}
function LateUpdate ()
{
if (target)
{
if(Input.GetMouseButton(0))
{
x += Input.GetAxis("Mouse X") * xSpeed;
y -= Input.GetAxis("Mouse Y") * ySpeed;
y = Mathf.Clamp(y, yMinLimit, yMaxLimit);
}
xSmooth = Mathf.SmoothDamp(xSmooth, x, xVelocity, smoothTime);
ySmooth = Mathf.SmoothDamp(ySmooth, y, yVelocity, smoothTime);
//var rotation = Quaternion.Euler(ySmooth, xSmooth, 0);
//transform.localRotation = Quaternion.identity;
//var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
//posSmooth = target.position;
distance = Mathf.Clamp(distance + Input.GetAxis("Mouse ScrollWheel")*distance, distanceMin, distanceMax);
transform.localRotation = Quaternion.Euler(ySmooth, xSmooth, 0);
transform.position = transform.rotation * Vector3(0.0, 0.0, -distance) + target.position;
}
}
/*static function ClampAngle (angle : float, min : float, max : float) {
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp (angle, min, max);
}*/
Answer by fred_gds · Aug 20, 2013 at 12:58 PM
So you want the camera to rotate around the ship right? If so then you could simply use
transform.RotateAround(spaceship.position,Vector3.up,speed*Time.deltaTime);
Just add this line in your code and it should keep rotating around the spaceship.
http://docs.unity3d.com/Documentation/ScriptReference/Transform.RotateAround.html
that would just make the camera rotate around the target. what i want is the camera's y axis rotation to be relative to the targets y axis rotation, so the camera still moves around the target with the mouse in addition to the target's position around the y axis. the ship's rotating, but when it breaks orbit, it won't be.
Answer by HeliosDoubleSix · Aug 20, 2013 at 01:08 PM
Regarding Namespace 'UnityEditor' not found, AddComponentMenu is an Editor specific command and wont run when published to an app. Editor only stuff should be put inside a folder called 'Editor' then it will only be compiled and ran in the editor. That or use 'defines' eg:
#if UNITY_EDITOR
@script AddComponentMenu("Camera-Control/Mouse Orbit")
#endif
Generally what is easiest with cameras is to take advantage of Unity's Transform by nesting various empty gameobjects together with different pivot points and placing the camera inside those. Then when you move or rotate one object all the rest move with it, taking care of all the complicated math for you.
Below would have the camera rotate around the ship when you want it to, and whenever the ship rotate or moves it moves exactly with it )
Empty Object 1 - ( set to 0,0,0 position ) ( move and rotate this to move the ship around )
Ship ( leave this at 0,0,0 position )
Empty Object 2 ( set to 0,0,0 position, rotate this left to right to swing the camera around the ship )
Empty Object 3 ( set to 0,0,500 position so it is placed behind the ship )
Camera ( set to 0,0,0 position ) ( attach a script on the camera to make it rotate/face towards the Ship )
If you wanted the Camera to stay still as the ship rotates but merely follow it and looks at it then:
Empty Object 1 - ( set to 0,0,0 position ) ( move this to move the ship around ( do not rotate ) )
Ship ( leave this at 0,0,0 position ) ( rotate this to rotate the ship ( do not move ) )
Empty Object 2 ( set to 0,0,0 position, rotate this left to right to swing the camera around the ship )
Empty Object 3 ( set to 0,0,500 position so it is placed behind the ship )
Camera ( set to 0,0,0 position ) ( attach a script on the camera to make it rotate/face towards the Ship )
And so on for different kinds of anchoring/following, the nested Transforms help you manipulate things
i don't think that answer's gonna work for me. make yourself a large sphere, then make a little horizontal capsule. i have the capsule rotating around the sphere using
#pragma strict
var orbitSpeed : float = 7.0;
function Update ()
{
transform.RotateAround(Vector3(3000, 0, 3000), Vector3.up, orbitSpeed * Time.deltaTime);
}
where (3000, 0, 3000) are the coordinates of the sphere. If you attach the camera script up top to the main cam, and click and drag the capsule transform to the public variable "target", you'll see the camera movement. I got real close when i multiplied Transform.rotation by target.rotation, the x axis movement on the camera got all wonky, seemed like a combination of x*y. i'm pretty sure all i need to do is multiply the rotation of the camera around the y axis by the rotation of the ship around the y axis, probably using Quaternions or eularAngles, i'm just not sure how.
yeah, i tried that empty gameObject thing, but if you look at the camera script, it uses transform.rotation to define the camera movement, which relates to world space and seems to supercede or negate any nested transform action.
Thats why they invented localRotation ;-)
this.transform.localRotation = new Vector3( 0, 0, 0 );
and localScale, and localPosition