- Home /
Click and Drag 3D Camera, like Anno
I'm trying to create a 3D camera that works just like in Anno and many other building/strategy games. I've been only learning Unity and C# for a couple of weeks so any extra help and clarifications would be very appreciated.
The basic logic for the camera: 1. Calculate mouse position on a ground layer with Ray. 2. On the right mouse click record the old mouse position. 3. While dragging, record the new mouse position by subtracting the old mouse position from the current mouse position. 4. Set GameObjects position (the parent of the Camera) by adding a new mouse position and multiplying it by Time.deltaTime.
The problem with my approach is that the position keeps adding up as long as the MRB is pressed down, even if the mouse isn't moving. Plus, the movement smoothing applies at the beginning and not when the mouse is released (ideally, no smoothing while dragging, and some subtle smoothing when released).
The only solution that I can imagine is seeing if the new mouse position actually updates or stays the same, but I have no idea how to do it as it is in the Update and keeps updating rapidly. So I imagine there must be a better way to do this.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraHandler : MonoBehaviour
{
// For MousePosition3D
[SerializeField] private Camera mainCamera;
[SerializeField] private LayerMask layerMask;
// For Position
private Vector3 oldMousePosition;
private Vector3 newMousePosition;
private void Start() {
transform.position = transform.position;
transform.position = Vector3.zero;
}
private void Update() {
// Position
if (Input.GetMouseButtonDown(1)) {
oldMousePosition = GetMouseWorldPosition();
}
if (Input.GetMouseButton(1)) {
newMousePosition = GetMouseWorldPosition() - oldMousePosition;
transform.position += newMousePosition * Time.deltaTime;
}
}
private Vector3 GetMouseWorldPosition() {
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit raycastHit, float.MaxValue, layerMask)) {
return raycastHit.point;
} else {
return Vector3.zero;
}
}
}
Answer by buroks44 · Dec 13, 2021 at 09:41 PM
Ok, so I added Vector3 initialTransform, set it to transform.position on GetMouseButtonDown and then calculated transform.position = initialTransform + newMousePosition * cameraMovementSpeed. Now the camera stops moving when I stop moving the mouse.
However, new issue is that the values on transform get way too accurate and starts causing errors. If I hold the RMB and don't move the house transform values keep changing with tiny changes and at some point the camera starts shaking. I think its accuracy is due to how the mouse position is calculated with Ray. How do I simplify that to a less accurate vector?