Hi all,
I could definatelly use some help on a 3D camera controller script that i want to copy/paste together.
What i want my camera to do is:
Pan, zoom, and orbit around the center of the screen. For this i googled a script and found this: http://wiki.unity3d.com/index.php?title=MouseOrbitZoom that is a decent start.
However, it orients around target you have to set or it creates it’s own camtarget a set distance in front of the camera. Not exactly what i want.
So i thought: with raycasting is can shoot a ray from the camera to the center of the screen and where it hits the ground, that is where i should orient around. I could even live with the idea that it orients around the first thing it hits. Just like lots of 3D program i’ve used.
But then things start to get weird and hop around and i’m lost.
To add to my misery, this needs to be working on a touchscreen later so without mouse or keyboard input. (single finger = orbit, multifinger is pan, pinching is zoom)
But that’s not all, i also do not want my camera to go inside geometry or below y=0 (aka floor)
The rotation of the script can be limited to not go under 0 to avoid rotating under the floor, but panning and zooming still go below zero.
Here is the script i use for now, that still needs hell of a lot of work:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
[AddComponentMenu("Camera-Control/3dsMax Camera Style")]
public class TouchCamera : MonoBehaviour
{
public Transform target;
public LayerMask groundLayerMask; // mask to choose orbitable layers
public Vector3 targetOffset;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public float xSpeed = 200.0f;
public float ySpeed = 200.0f;
public int yMinLimit = 0;
public int yMaxLimit = 80;
public int zoomRate = 40;
public float panSpeed = 0.3f;
public float zoomDampening = 5.0f;
private float xDeg = 0.0f;
private float yDeg = 0.0f;
private float currentDistance;
private float desiredDistance;
private Quaternion currentRotation;
private Quaternion desiredRotation;
private Quaternion rotation;
private Vector3 position;
private bool clicking = false;
public float rayCastDistance = 1000f;
void Start() { Init(); }
void OnEnable() { Init(); }
public void Init()
{
//If there is no target, create a temporary target at 'distance' from the cameras current viewpoint
if (!target)
{
GameObject go = new GameObject("Cam Target");
go.transform.position = transform.position + (transform.forward * distance);
target = go.transform;
}
distance = Vector3.Distance(transform.position, target.position);
currentDistance = distance;
desiredDistance = distance;
//be sure to grab the current rotations as starting points.
position = transform.position;
rotation = transform.rotation;
currentRotation = transform.rotation;
desiredRotation = transform.rotation;
xDeg = Vector3.Angle(Vector3.right, transform.right);
yDeg = Vector3.Angle(Vector3.up, transform.up);
}
//We need to do this in a fixed update or normal update otherwise
void LateUpdate()
{
// If Middle button? ZOOM!
if (Input.GetMouseButton(2) && !EventSystem.current.IsPointerOverGameObject())
{
desiredDistance -= Input.GetAxis("Mouse Y") * Time.deltaTime * zoomRate * 0.125f * Mathf.Abs(desiredDistance);
}
//Reset if mouse is released
if (Input.GetMouseButtonUp(0))
{
clicking = false;
}
// If leftMouse? ORBIT
if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
{
//First we emulate a mouse down event
if (clicking == false)
{
clicking = true;
//Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
RaycastHit hit;
if (Physics.Raycast (ray, out hit, rayCastDistance))
{
//draw invisible ray cast/vector
Debug.DrawLine (ray.origin, hit.point);
//log hit area to the console
//Debug.Log(hit.point);
target.transform.position = hit.point;
}
// Debug.Log("cliik");
}
xDeg += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
yDeg -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
////////OrbitAngle
//Clamp the vertical axis for the orbit
yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);
// set camera rotation
desiredRotation = Quaternion.Euler(yDeg, xDeg, 0);
currentRotation = transform.rotation;
rotation = Quaternion.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomDampening);
transform.rotation = rotation;
}
// otherwise if right mouse is selected, we pan by way of transforming the target in screenspace
else if (Input.GetMouseButton(1) && !EventSystem.current.IsPointerOverGameObject())
{
//grab the rotation of the camera so we can move in a psuedo local XY space
target.rotation = transform.rotation;
target.Translate(Vector3.right * -Input.GetAxis("Mouse X") * panSpeed);
target.Translate(transform.up * -Input.GetAxis("Mouse Y") * panSpeed, Space.World);
}
////////Orbit Position
// affect the desired Zoom distance if we roll the scrollwheel
desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
//clamp the zoom min/max
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
// For smoothing of the zoom, lerp distance
currentDistance = Mathf.Lerp(currentDistance, desiredDistance, Time.deltaTime * zoomDampening);
// calculate position based on the new currentDistance
position = target.position - (rotation * Vector3.forward * currentDistance + targetOffset);
transform.position = position;
}
private static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
I’m starting to think that i’m missing something. I can’t be the fist person on earth to need something like this.
What would you advice me to investigate to get a grip on this? Am i just too noob to get a handle on this?
Are there any (paid) camera controllers in the asset strore that do this that could save me lots of headaches?
I could really use some help from more experienced Unity users so i thought i’d give it a try here. Fingers crossed. Thanks for taking the tim to read through this.