Camera changes movements

Hello everyone, I am 5kyLegend and I’m pretty new with Unity. I made a Sphere object (called MainCharacter) move (with success), and a camera (called myCamera) that follows the sphere, and that rotates using the mouse. The problem is this: when the camera changes position, the Sphere doesn’t follow Camera direction (if I press “Up” the Sphere goes up for the level, not at the camera’s up). I hope you understood what am I trying to say, and… Well, thank you!

If it could be useful, here you have the code I’m using:

var target : Transform;

var distance = 10.0;

var cameraSpeed = 5;

 

var xSpeed = 175.0;

var ySpeed = 75.0;

 

var yMinLimit = 20; //Lowest vertical angle in respect with the target.

var yMaxLimit = 80;

 

var minDistance = 5; //Min distance of the camera from the target

var maxDistance = 20;

 

private var x = 0.0;

private var y = 0.0;

 

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  camera) {

 

   //Zooming with mouse

   distance += Input.GetAxis("Mouse ScrollWheel")*distance;

   distance = Mathf.Clamp(distance, minDistance, maxDistance);

 

   //Detect mouse drag;

   if(Input.GetMouseButton(0))   {

   

        x += Input.GetAxis("Mouse X") * xSpeed * 0.02;

        y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;       

      }

      y = ClampAngle(y, yMinLimit, yMaxLimit);

              

        var rotation = Quaternion.Euler(y, x, 0);

        var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;

         

   transform.position = Vector3.Lerp (transform.position, position, cameraSpeed*Time.deltaTime);

      transform.rotation = rotation;      

    }

}

 

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

}

translationVertical = Input.GetAxis ("Vertical");

translationVertical = translationVertical * cameraSpeed;

translationVertical *= Time.deltaTime;

 

translationHorizontal = Input.GetAxis ("Horizontal");

translationHorizontal = translationHorizontal * cameraSpeed;

translationHorizontal *= Time.deltaTime;

 

var cameraRelative : Vector3 = camera.main.transform.TransformDirection (0, 0, -1);

rigidbody.position -= Vector3((cameraRelative.x * translationVertical), 0,(cameraRelative.z * translationVertical) );

cameraRelative = camera.main.transform.TransformDirection (-1, 0, 0);



rigidbody.position -= Vector3((cameraRelative.x * translationHorizontal), 0,(cameraRelative.z * translationHorizontal) );

hmmm… perhaps a good lesson in 3d concepts will help you here.

You have two basics “spaces” which you can work with. World and Self. World, is the global world that everything is in, Self is where everything comes from how an object is positioned and rotated and scaled.

So, when you move the camera “up”, the question are you moving it in “World” or “Self”?

I ask, since the code that you have provided appears to mostly be the MouseOrbit script from the standard scripts.

Now, here is an important lesson.

transform.position += Vector3.up; // moves an object in "World" space
transform.position += transform.up; // move an object in "Self" space

Self, is also relative. observe:

transform.position += Camera.main.transform.up; // moves an object in the Camera's "Self" Space

So, as it applies to the bottom part of your code.

var move:Vector3 = new Vector3(Input.GetAxis ("Horizontal"),0,Input.GetAxis ("Vertical"));
move *= cameraSpeed * Time.deltaTime;

transform.position += Camera.main.transform.TransformDirection(move);

Now, this code basically moves an object, forward, backward left and right according to the Camea’s “Self” space. By using TransformDirection, we take the x, y and z from our “move” and direct it to match the camera’s direction.

TransformDirection, takes Vector3.forward, and turns it into Transform.forward. (as well as all the other directions to match teh object that you are coming from.)
InverseTransformDirection takes the Transform.forward and turns it into Vector3.forward.

Using these, you can go back and forth between World and Self space of any object.

OK, now in your code you are specifying a rigidbody. Generally, I never use rigidbody.position. This has bad effects in the physics world in Unity. I would suggest, for the moment, learning moving and stuff like that before jumping into physics.

transform.Translate() does stuff very much like what is listed here, and also, allows you to set the space you are working in.

transform.Translate(move, Space.Self);

Ok, so now I have replaced

var cameraRelative : Vector3 = camera.main.transform.TransformDirection (0, 0, -1);
rigidbody.position -= Vector3((cameraRelative.x * translationVertical), 0,(cameraRelative.z * translationVertical) );
cameraRelative = camera.main.transform.TransformDirection (-1, 0, 0);
rigidbody.position -= Vector3((cameraRelative.x * translationHorizontal), 0,(cameraRelative.z * translationHorizontal) );

with

var move:Vector3 = new Vector3(Input.GetAxis ("Horizontal"),0,Input.GetAxis ("Vertical"));
move *= cameraSpeed * Time.deltaTime;
transform.position += Camera.main.transform.TransformDirection(move);
transform.Translate(move, Space.Self);

But now Unity gives me, while testing, a NullReferenceException and the Sphere movements are still based on the world.

Anyway, thank you for the help :smile:

OK, here is how your scripts could be. The problem is, I dont know exactly what you are doing. Don’t really care at this point. This is just one way to accomplish it.

// placed on camera
// Smooth Orbit
var target : Transform;
var distance = 10.0;
var cameraSpeed = 5;

var xSpeed = 175.0;
var ySpeed = 75.0;

var yMinLimit = 20; //Lowest vertical angle in respect with the target.
var yMaxLimit = 80;

var minDistance = 5; //Min distance of the camera from the target
var maxDistance = 20;

private var x = 0.0;
private var y = 0.0;

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  camera) {
		//Zooming with mouse
		distance += Input.GetAxis("Mouse ScrollWheel")*distance;
		distance = Mathf.Clamp(distance, minDistance, maxDistance);
		
		//Detect mouse drag;
		if(Input.GetMouseButton(0)){
			x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
			y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;	
		}
		y = ClampAngle(y, yMinLimit, yMaxLimit);
		
		var rotation = Quaternion.Euler(y, x, 0);
		var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
		
		transform.position = Vector3.Lerp (transform.position, position, cameraSpeed*Time.deltaTime);
		transform.rotation = rotation;	
	}
}

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);
}
// placed on the sphere
var speed:float = 5;

function Update(){
	var move:Vector3 = new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
	move *= speed * Time.deltaTime;
	transform.position += Camera.main.transform.TransformPoint(move);
}