Camera problem: -40/+40 degrees relative to another object...

I am having a lot of trouble getting a portion of my script to work correctly.
To set up the script to see precisely what the problem is all you should have to do is provide the same transform for Dragon, Camera Attachment Point, and link the Main Camera to a camera.

// Set variables
var dragon : Transform;
var mainCamera : Transform;
var cameraAttachmentPoint : Transform;
var horizontalAimingSpeed : float = 270;
var verticalAimingSpeed : float = 270;
var maxHorizontalAngle : float = 40;
var minHorizontalAngle : float = -40;
var maxVerticalAngle : float = 30;
var minVerticalAngle : float = -40;
var smoothingTime : float = 5.0;

var cameraOffset : Vector3 = Vector3(0, 1, -4);
var lowAimPosition : Vector3 = Vector3(0, 6, -1);
var highAimPosition : Vector3 = Vector3(0, -1.25, 0.75);

@System.NonSerialized
var lowAimPositionPercentage : Vector3;
@System.NonSerialized
var highAimPositionPercentage : Vector3;

@System.NonSerialized
var angleH : float;
@System.NonSerialized
var angleV : float;
@System.NonSerialized
var aimRotation : Quaternion;
@System.NonSerialized
var aimPosition : Vector3;
@System.NonSerialized
var dragonRotation : Quaternion;

var reticle : Texture;

function Update () {
		
	// Set dragonRotation
	dragonRotation = dragon.rotation;
	
	// Make sure input axis dont go beyond -1 or 1
	angleH += Mathf.Clamp(Input.GetAxis("Mouse X"), -1, 1) * horizontalAimingSpeed * Time.deltaTime;
	angleV += Mathf.Clamp(Input.GetAxis("Mouse Y"), -1, 1) * verticalAimingSpeed * Time.deltaTime;
	
	// Limit angles to min and max
	angleH = Mathf.Clamp(angleH, minHorizontalAngle + dragonRotation.eulerAngles.y, maxHorizontalAngle + dragonRotation.eulerAngles.y);
	angleV = Mathf.Clamp(angleV, minVerticalAngle, maxVerticalAngle);
	
	// Determine if angleV is low
	if (angleV < 0) {
		lowAimPositionPercentage = dragonRotation * (angleV / minVerticalAngle * lowAimPosition);
	}
	else {
		lowAimPositionPercentage = Vector3.zero;
	}
	
	// Determine if angleV is high
	if (angleV > 0) {
		highAimPositionPercentage = dragonRotation * (angleV / maxVerticalAngle * highAimPosition);
	}
	else {
		highAimPositionPercentage = Vector3.zero;
	}
	
	// Set aimPosition
	aimPosition = (cameraAttachmentPoint.position + (dragonRotation * cameraOffset)) + (lowAimPositionPercentage + highAimPositionPercentage);
	
	// Set aimRotation
	aimRotation = Quaternion.Euler(-angleV, angleH, 0);
	
	// Set mainCamera position
	mainCamera.position = Vector3.Lerp(mainCamera.position, aimPosition, smoothingTime * Time.deltaTime);
	
	// Set mainCamera rotation
	mainCamera.rotation = aimRotation;
	
}

function OnGUI () {
	
	// Draw the reticle
	GUI.DrawTexture(new Rect(Screen.width / 2 -(reticle.width*0.5), Screen.height / 2 -(reticle.height*0.5), reticle.width, reticle.height), reticle);
	
}

The issue is with the follow portion of the code.

When the dragon transform rotates <> 0/360 the camera pops due to euler angles.

What Im trying to do is limit the cameras rotation to be within -40 and +40 degrees of the dragons rotation.

The script performs as I intend with the exception of the camera ‘pop’.

Here’s the problem area:

	// Limit angles to min and max
	angleH = Mathf.Clamp(angleH, minHorizontalAngle + dragonRotation.eulerAngles.y, maxHorizontalAngle + dragonRotation.eulerAngles.y);
	angleV = Mathf.Clamp(angleV, minVerticalAngle, maxVerticalAngle);

Really need the help, spent hours on it yesterday and today with no results, very demoralizing :face_with_spiral_eyes:

Up in the Standard Scripts is a MouseOrbit.js script. Within that script is this function:

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

is this what you are looking for?

Im not sure how that is going to help me.

That function doesnt look like a solution to my problem, or I dont know how to implement it.

If you run the script you can see precisely what my problem is.

Rotate the ‘dragon’ transform in the inspector along its Y axis and youll see the cam ‘pop’ to the opposite min/max angle.

Hey, would transform.InverseTransformPoint help you out?

Basically gives you any point in relation to the given transform, eg:

var relativeToDragon:Vector3=dragon.InverseTransformPoint(somepoint);

This would get you a Vector3, where for example if relativeToDragon.x was less than 0 the object was to the left, if it’s >0 it’s to your right (sorry if I have that backwards).

Then you could rotate your dragon with dragon.Rotate(), probably using the Up axis, and using the sign of relativeToDragon.x

I am not trying to rotate the dragon. I am trying to rotate the camera.

The camera should only rotate when the user uses the mouse, or the relationship between the camera and the dragon exceeds either -40 or +40 degrees.

The dragon will rotate to the cameras direction in another script. What I am trying to do is regardless of the dragons rotation the camera will never exceed -40 or +40 degrees to the left or right of the dragon.

The camera can move freely within that range via the mouse. The only time the camera is forced to rotate with the dragon is when the dragons rotation moves beyond the set degrees in relation to the camera.

How about something like this:

  • record cameras old position
  • set cameras new position
  • now you do your tests…if the test fails, set camera back its old position set the camera back to its old position

The tests:

  • Get camera’s position relative to the dragon with itp=dragon.InverseTransformPoint(camera)
  • itp.z must be less than 0
  • now I have to rush to work…but if you take the Inverse Sin of itp.x, and account for whether x>0 or x<0 you should be able to get the angle you need to test against, if the angle is out of range then the camera is in an illegal position

edit: hmm, I think you might want the arctan(itp.x/itp.z)

Okay here’s a script that should as an example (thought I’d work this out for myself), attach to your camera and assign the dragon to the transform. It’ll let you know when the camera is outside of the proper range…you should be able to work with the code from there.

var target:Transform;
var angleLimit:float=40;
private var angleLimitRad:float;

function Start(){
	angleLimitRad=angleLimit* 0.0174532925;
}
function Update () {
	var itp=target.InverseTransformPoint(transform.position);
	if (itp.z>=0){
		Debug.Log("Whoops I'm out in front");
	}
	else {
		var angle=Mathf.Abs(Mathf.Atan(itp.x/itp.z));
		if (angle>=angleLimitRad){Debug.Log("Whoops I'm to far off angle");}
		else {Debug.Log("I'm in the zone.");}
	}
}

So basically you need to get the proposed position of the camera and run it through that test…or set the position of the camera, saving its old position and doing this test, and if it fails resetting the position.

EDIT: AH CRAP JUST REALIZED YOU WANTED TO RESTRICT ROTATION NOT POSITION

Is the camera at a fixed position behind the dragon?

Detection could be done something like this:

public Camera target;
public Transform observed;

private float maxAngle = 40.0f;
private Vector3 standardVector;


void Start ()
{
	if (target == null || observed == null)
	{
		Debug.LogError ("You missed a reference.", this);
		enabled = false;
		return;
	}
	
	standardVector = target.transform.position - observer.transform.position;
}


void Update ()
{
	if (Vector3.Angle (target.transform.position - observer.transform.position, standardVector) > maxAngle)
	{
		// More than maxAngle degrees away from the standard vector - be that right behind the observed or whatever
	}
}