- Home /
Rubber banding camera (help!)
Okay, so this code segment is supposed to move the camera (which is the otherGameObject) after I select the object to which the script is attached.
It works perfectly about 2/3s of the time. The other time, it will create what seems to be what seems to be a small box around the object out of which I can't move the camera.
Any thoughts? I can't imagine its update being called too slowly.
Updated: Full code below
public var otherGameObject : GameObject;
private var moveTheCamera = false;
public var smooth : float;
private var targetPosition : Vector3;
private var targetRotation : Quaternion;
private var targetPosition2 : Vector3;
function Awake () {
}
function Start () {
}
function Update () {
if ((targetPosition2.z - otherGameObject.transform.position.z < .05) && (targetPosition2.z - otherGameObject.transform.position.z > 0))
{
moveTheCamera = false;
}
else if (moveTheCamera == true)
{
if (Mathf.Approximately(transform.eulerAngles.y, 0))
{
targetPosition2 = (transform.position + (targetPosition * -5));
}
if (Mathf.Approximately(transform.eulerAngles.y, 180))
{
targetPosition2 = (transform.position + (targetPosition * -5));
}
otherGameObject.transform.position = Vector3.Lerp(otherGameObject.transform.position, targetPosition2, smooth * Time.deltaTime);
otherGameObject.transform.rotation = Quaternion.Slerp(otherGameObject.transform.rotation, targetRotation, smooth * Time.deltaTime);
}
}
function OnMouseDown ()
{
moveTheCamera = true;
targetPosition = Vector3.forward;
targetRotation = Quaternion.Euler(otherGameObject.transform.eulerAngles.x, transform.eulerAngles.y, otherGameObject.transform.eulerAngles.z);
Debug.Log(targetRotation);
Debug.Log(targetPosition);
}
function OnMouseUp()
{
//moveTheCamera = false;
Debug.Log(targetPosition2.z);
Debug.Log(otherGameObject.transform.position.z);
Debug.Log(targetPosition2.z - otherGameObject.transform.position.z);
Debug.Log(Mathf.Abs(targetPosition2.z - otherGameObject.transform.position.z));
}
Answer by aldonaletto · Aug 18, 2013 at 07:58 PM
I really didn't get what your script is trying to do, but reading eulerAngles isn't reliable: it may return values totally different from what you expect. Anyway, this seems too complicated - you could simply place an empty game object with the desired position and rotation, assign it to target and let the camera lerp to it continuously:
var target: Transform; // assign the target empty to this variable
var smooth: float = 3.0;
function Update () {
if (target){ // if some target defined, lerp to it:
otherGameObject.transform.position = Vector3.Lerp(otherGameObject.transform.position, target.position, smooth * Time.deltaTime);
otherGameObject.transform.rotation = Quaternion.Slerp(otherGameObject.transform.rotation, target.rotation, smooth * Time.deltaTime);
}
}
EDITED: Ok, so you want the camera to get free after reaching the desired position. In this case, I would use a trick similar to yours: calculate the back position, lerp to it and let the camera free once the position is reached - but I would use the object's forward direction to guide the rotation, and the distance to the target in order to finish the auto movement, like this:
function Update () {
if (moveTheCamera){
// target position is 5 units behind target object:
targetPosition2 = transform.position - 5 * transform.forward;
// target rotation is the same of the target object:
targetRotation = transform.rotation;
otherGameObject.transform.position = Vector3.Lerp(otherGameObject.transform.position, targetPosition2, smooth * Time.deltaTime);
otherGameObject.transform.rotation = Quaternion.Slerp(otherGameObject.transform.rotation, targetRotation, smooth * Time.deltaTime);
}
// free the camera when it gets closer than 0.05:
if (Vector3.Distance(targetPosition2, otherGameObject.transform.position) < .05){
moveTheCamera = false;
}
}
I suppose that this script is attached to each possible target, and moveTheCamera is set in the desired object in order to "attract" the camera.
Hey thanks for the reply Aldonaletto! I guess I didn't do a good job explaining why I wanted this script. Our game the units will be arranged like a chess board (which means the units will be rotated either 0 or 180 on the Y).
I want this script to tell the camera to move behind the unit selected. So it sets a targetposition behind the unit, and then the camera flies there. The problem is that sometimes the "fly there" script doesn't end, so when you try and free-move the camera away from the select unit, it gets "rubber banded" back to the target position.
Are you suggesting putting a child empty gameobject behind each unit and use that as the target position? The problem is that I don't want to change the "zoom" of the camera as it flies.
Thanks, and I hope this makes sense. I'm trying to self-$$anonymous$$ch here, to varying degrees of success. :)
I edited my answer to include a code that may do what you want (I hope)
Thanks aldonaletto. As I alluded to my comment to meat5000, I've editted my original question to include my full code.
Three thoughts/questions on your answer:
The use of transform.forward didn't seem to work when I first used it in my code(which is why I changed it to check the rotation of the object). Is there an easier way to do this?
I've avoided using the targetRotation = transform.rotation code because I was afraid of changing the 'angle' of the camera . It's currently at a fixed 40 degree angle from the seperate free-move script.
The vector 3 distance sounds promissing, is there something about my use of the float (z position) that makes it unreliable? The script DOES free the camera 2 out of 3 times, so I know it's working - what's the difference using the vector3.distance method?
Also, if I could upvote you, I would! I'll upvote as soon as I earn the reputation points. Thanks for putting in the time with a novice.
1- transform.forward works fine if the object's forward direction points in its local Z - many 3D editors scramble the axes, and frequently we import models whose forward direction is aligned to X or Y. If your models all face the X direction, for instance, use transform.right ins$$anonymous$$d of transform.forward;
2- You're right: assu$$anonymous$$g the object rotation may be a disaster when the object has scrambled axes or when you want to have a particular inclination. If your solution is working fine (I mean: if it's looking at the desired direction), keep it - rotations are too tricky to abandon a solution that's working!
3- $$anonymous$$easuring things directly along the axes is a bad idea in a 3D space due to the object rotation: the Z axis may be aligned to any direction relative to the object. In this particular case, you're only checking whether the Z coordinate is closer than -0.05 to the target position - if it's co$$anonymous$$g from the other side, the loop will never end. Vector3.Distance evaluates the unsigned distance in any direction, thus you would not have this problem.
Answer by meat5000 · Aug 19, 2013 at 12:44 AM
You may be getting stuck in moveTheCamera == true condition and so the Lerp is locking you in to target.position
As time has progressed and t >= 1 your Lerp is locked at target.position as t=1;
Your use of Mathf.Approximately and eulerAngles could explain why this happens only some of the time. When the numbers are slightly out of your bounds you get locked in.
Avoid approximation and use something other than eulerAngles. Alternatively, detect when the Lerp is completed (i.e when t=1) and manually set
moveTheCamera = false;
within the braces of
else if (moveTheCamera == true)
I suspect you are correct that I am getting stuck in the "true" condition for moveTheCamera.
I don't think it relates to the use of eulerAngles, as this script also got stuck with lerp before I added the support for units "on the other side" of the chess board.
I'd love to detect when the Lerp is complete (in fact, that's what I'm trying to do with the first if statement). Can you offer other suggestions as to how to detect this?
Again, as a novice, I appreciate both your patience and your help. I also realized I only posted a portion of my code in the original answer, I'm editing to include the full script.
The Lerp is complete when the Lerp 't' factor is 1.
static function Lerp(from: Vector3, to: Vector3, t: float): Vector3;
Despite whatever anyone puts into the t field, Lerp only works between t = 0 -> 1. When t = 0 Lerp returns the From field. When it is 1 it returns the To field and a value in between will give you a value/Vector3 between From and To. The Lerp is complete when, in your case, the object position = To or when t = 1.
There are other conditions your could use, for example, when the camera has arrived at its position the speed/velocity should be 0. You could even use some kind of Position Array (a procedural script or a predefined table) to store all the positions of the camera as there are a set amount. You can even reference them by index in that scenario.
Thanks for the help meat5k - I'll upvote you when I get the rep. You were very helpful!
Your answer
Follow this Question
Related Questions
Move speed decrease stoping object problem. 1 Answer
Sync Camera and Object 1 Answer
Endless runner, road segments spawn speed 0 Answers
Camera Rotation Script Totally Screwed Up 1 Answer
Stop a enemy by pointing a light at it. 4 Answers