- Home /
How to Set Variable to Camera's Current Local Rotation After Movement
ISSUE Here's what I'm trying to make in a 3D game: 1. The player can rotate the camera with the mouse to look around. 2. The player can see an item in the distance. 3. The player can click on the item in the distance. 4. The player flies over to that item, landing in front of it and looking at. 5. The player can look around some more as in Step 1.
PROBLEM All of that is working ok. Here's the problem, in the transition from Step 4 to Step 5, when the player has landed and is looking at the object, and first clicks the mouse, the camera "jumps" and looks in the direction it was looking just before "flying" over to the object.
HOW I'M DOING THIS I have two scripts: - A script to let the player drag the mouse and look around. - A script to let the player click on the object, which makes the player fly over there: - Use a raycast to detect the distant object. - Use transform.position to fly (lerp) to the distant object. - Use transform.LookAt to turn the camera and look at the (no longer distant) object.
WHAT I THINK IS GOING ON The two scripts are in conflict about which way the camera is pointed:
The "look-around" script thinks the camera is pointed at whatever it was pointed at just before the distant object was selected, and this is no longer true.
The "fly-over-and-look-at-it" script thinks it is looking at the object, and it is correct.
When you try to drag the mouse again to "look around" that script jumps the camera back to the position it was in before moving it around. This causing a jarring visual effect.
WHAT I'VE TRIED TO FIX THIS I would think I could tell the "look around" script, "Hey! The position of the camera has changed. You need to get the camera's current rotation, then rotate it FROM THAT SETTING. NOT from the setting you last recorded."
That approach is not working. What am I missing?
Can anyone tell me the mistake I'm making?
Here is my "Look around Script" public class MouseDragRotCamInXY : MonoBehaviour { [SerializeField] private float mouseDragSpeed = 1.0f; [SerializeField] private float maxAngleUp = 45; [SerializeField] private float maxAngleDown = -45; [SerializeField] private float dragInverterX = -1; [SerializeField] private float dragInverterY = 1;
public bool somethingElseIsWorking;
private Quaternion _camRotation;
void Start()
{
_camRotation = transform.localRotation;
}
void Update()
{
if (!somethingElseIsWorking)
{
if (Input.GetMouseButton(0))
{
if (_camRotation != transform.localRotation)
{
_camRotation = transform.localRotation; //This line does NOT seem to do what I think it would do.
}
_camRotation.x += Input.GetAxis("Mouse Y") * mouseDragSpeed * dragInverterX;
_camRotation.y += Input.GetAxis("Mouse X") * mouseDragSpeed * dragInverterY;
_camRotation.x = Mathf.Clamp(_camRotation.x, maxAngleDown, maxAngleUp);
transform.localRotation = Quaternion.Euler(_camRotation.x, _camRotation.y, _camRotation.z);
}
}
else
{
_camRotation = transform.localRotation;
}
}
}
Here is my "Fly Over There" script: public class MouseClickMovesCamera : MonoBehaviour {
[SerializeField] private string selectedObjTag = "MapPin";
[SerializeField] private string colliderTag;
[SerializeField] private float minDistX = 0.1f;
[SerializeField] private float minDistY = 0.1f;
[SerializeField] private float minDistZ = 0.1f;
[SerializeField] private float speed = 0.0f;
[SerializeField] private bool camNeedsToMove = false;
private GameObject moveTarget;
private GameObject lookTarget;
[SerializeField] private Vector3 startPosition = new Vector3(20, 20, 20); // This is where the camera will start
[SerializeField] private Vector3 framedPosition; // This is where the camera will move when object is clicked
// Update is called once per frame
void Update()
{
//Mouse Click happens
if (Input.GetMouseButtonDown(0))
{
//Create variables to cast a ray from the camera to wherever the mouse clicked
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Debug.DrawRay(ray.origin, ray.direction * 500, Color.red, 2.0f);
//Detect if ray hit object
if (Physics.Raycast(ray, out hit, 1000)) //Will need to test whether all map pins can be hit by a ray of this length (1000 units) from anywhere inside the villa
{
//Get the tag of whatever you hit
colliderTag = hit.collider.tag;
//If what you hit was a map pin then you'll need to move the camera
if (colliderTag == selectedObjTag)
{
moveTarget = hit.transform.GetChild(0).gameObject;
lookTarget = hit.transform.GetChild(1).gameObject;
colliderTag = "";
camNeedsToMove = true;
}
}
}
if (camNeedsToMove)
{
MoveTheCam();
}
}
public void MoveTheCam()
{
//Capture the Camera's current position
startPosition = Camera.main.transform.position;
framedPosition = moveTarget.transform.position;
//If the Camera has not moved to its new position
if ((Mathf.Abs(framedPosition.x - Camera.main.transform.position.x)) > (minDistX) ||
((Mathf.Abs(framedPosition.y - Camera.main.transform.position.y)) > (minDistY) ||
((Mathf.Abs(framedPosition.z - Camera.main.transform.position.z)) > minDistZ)))
{
//Move the camera into position
Camera.main.transform.position = Vector3.Lerp(startPosition, framedPosition, speed);
Camera.main.transform.LookAt(lookTarget.transform.position);
Debug.Log("MapPin is moving the camera: " + Camera.main.transform.position);
}
else
{
camNeedsToMove = false;
}
}
}