I've made an orthographic camera that is moving by dragging a mouse but can't understand how to create a boundaries for it. It seems that I have to use Mathf.Clamp but can't find out how.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamController : MonoBehaviour
{
public Transform cameraTransform;
public float movementSpeed;
public float movementTime;
public Vector3 newPosition;
public Vector3 dragStartPosition;
public Vector3 dragCurrentPosition;
public Camera cam;
public float maxZoom = 5;
public float minZoom = 20;
public float sensitivity = 1;
public float speed = 30;
float targetZoom;
public float minX = 100;
public float maxX = 120;
// Start is called before the first frame update
void Start()
{
newPosition = transform.position;
}
// Update is called once per frame
void Update()
{
HandleMouseInput();
HandleMovementInput();
{
targetZoom -= Input.mouseScrollDelta.y * sensitivity;
targetZoom = Mathf.Clamp(targetZoom, maxZoom, minZoom);
float newSize = Mathf.MoveTowards(cam.orthographicSize, targetZoom, speed * Time.deltaTime);
cam.orthographicSize = newSize;
}
}
void HandleMouseInput()
{
if (Input.GetMouseButtonDown(0))
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float entry;
if (plane.Raycast(ray, out entry))
{
dragStartPosition = ray.GetPoint(entry);
}
}
if (Input.GetMouseButton(0))
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
float entry;
if (plane.Raycast(ray, out entry))
{
dragCurrentPosition = ray.GetPoint(entry);
newPosition = transform.position + dragStartPosition - dragCurrentPosition;
}
}
newPosition = Mathf.Clamp(minX, minX);
}
void HandleMovementInput()
{
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
newPosition += (transform.forward * movementSpeed);
}
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
newPosition += (transform.forward * -movementSpeed);
}
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
newPosition += (transform.right * movementSpeed);
}
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
newPosition += (transform.right * -movementSpeed);
}
transform.position = Vector3.Lerp(transform.position, newPosition, Time.deltaTime * movementTime);
}
}
newPosition = Mathf.Clamp(minX, minX);
You can't clamp with only two parameters .. you need a current, a min and a max value .. And you can't just convert a float which is what Mathf.Clamp returns into a Vector3 (3 floats)
I think what you meant was rather something like e.g.
newPosition.x = Mathf.Clamp(newPosition.x, minX, maxX);
However, right after that in HandleMovementInput you overwrite it anyway so you might want to change the moment when you are clamping and rather do it right before applying the new position.
Related
I want to make a rotating camera on the map around the target object, with the first point I did it. After clicking on another object, which I also want to inspect, my camera shifts and rotates not around the object, but some other point. How to point to an object around which I want the camera to rotate with the mouse
LabsManager lab;
public Transform lookCentre;
public Transform lookZRU;
public Vector3 offset;
public float sensitivity; // чувствительность мышки
public float limit; // ограничение вращения по Y
public float zoom; // чувствительность при увеличении, колесиком мышки
public float zoomMax; // макс. увеличение
public float zoomMin; // мин. увеличение
private float X, Y;
bool activeTarget;
void Start()
{
GameObject activ = GameObject.Find("LabsManager");
lab = activ.GetComponent<LabsManager>();
activeTarget = false;
}
void Update()
{
if (lab.LabName == "Осмотр")
{
if (activeTarget == false)
{
CameraPosition(lookCentre);
MouseLook();
}
LookZRU();
}
}
void CameraPosition(Transform target)
{
if (activeTarget == false)
{
transform.position = transform.localRotation * offset + target.position;
}
MouseLook();
}
void MouseLook()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0) offset.z += zoom;
else if (Input.GetAxis("Mouse ScrollWheel") < 0) offset.z -= zoom;
offset.z = Mathf.Clamp(offset.z, -Mathf.Abs(zoomMax), -Mathf.Abs(zoomMin));
if (Input.GetMouseButton(1))
{
X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity;
}
if (Input.GetMouseButton(0))
{
Y += Input.GetAxis("Mouse Y") * sensitivity;
}
Y = Mathf.Clamp(Y, -limit, limit);
transform.localEulerAngles = new Vector3(-Y, X, 0);
}
void LookZRU()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.gameObject.GetComponent<SelectZRU>())
{
Debug.Log(gameObject.name + " бла бла");
if (Input.GetKeyDown(KeyCode.R))
{
activeTarget = true;
CameraPosition(lookZRU);
}
}
}
if (activeTarget == true)
{
MouseLook();
}
}
You can use rotate around, just update "obj" value with your new clicked object position.
Vector3 obj = target.transform.position; //change this
transform.RotateAround(obj, Vector3.up, 20 * Time.deltaTime);
I had this unity player embedded in android studio activity.
It is a 3d model with animation, which I would like viewer to be able to zoom and view in different angle.
Script are from this link
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MobilemaxCamera : MonoBehaviour {
public Transform target;
public Vector3 targetOffset;
public float distance = 5.0f;
public float maxDistance = 20;
public float minDistance = .6f;
public float xSpeed = 5.0f;
public float ySpeed = 5.0f;
public int yMinLimit = -80;
public int yMaxLimit = 80;
public float zoomRate = 10.0f;
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 Vector3 FirstPosition;
private Vector3 SecondPosition;
private Vector3 delta;
private Vector3 lastOffset;
private Vector3 lastOffsettemp;
//private Vector3 CameraPosition;
//private Vector3 Targetposition;
//private Vector3 MoveDistance;
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);
}
/*
* Camera logic on LateUpdate to only update after all character movement logic has been handled.
*/
void LateUpdate()
{
// If Control and Alt and Middle button? ZOOM!
if (Input.touchCount==2)
{
Touch touchZero = Input.GetTouch (0);
Touch touchOne = Input.GetTouch (1);
Vector2 touchZeroPreviousPosition = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePreviousPosition = touchOne.position - touchOne.deltaPosition;
float prevTouchDeltaMag = (touchZeroPreviousPosition - touchOnePreviousPosition).magnitude;
float TouchDeltaMag = (touchZero.position - touchOne.position).magnitude;
float deltaMagDiff = prevTouchDeltaMag - TouchDeltaMag;
desiredDistance += deltaMagDiff * Time.deltaTime * zoomRate * 0.0025f * Mathf.Abs(desiredDistance);
}
// If middle mouse and left alt are selected? ORBIT
if (Input.touchCount==1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchposition = Input.GetTouch(0).deltaPosition;
xDeg += touchposition.x * xSpeed * 0.002f;
yDeg -= touchposition.y * ySpeed * 0.002f;
yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);
}
desiredRotation = Quaternion.Euler(yDeg, xDeg, 0);
currentRotation = transform.rotation;
rotation = Quaternion.Lerp(currentRotation, desiredRotation, Time.deltaTime * zoomDampening);
transform.rotation = rotation;
if (Input.GetMouseButtonDown (1))
{
FirstPosition = Input.mousePosition;
lastOffset = targetOffset;
}
if (Input.GetMouseButton (1))
{
SecondPosition = Input.mousePosition;
delta = SecondPosition - FirstPosition;
targetOffset = lastOffset + transform.right * delta.x*0.003f + transform.up * delta.y*0.003f;
}
////////Orbit Position
// affect the desired Zoom distance if we roll the scrollwheel
desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
currentDistance = Mathf.Lerp(currentDistance, desiredDistance, Time.deltaTime * zoomDampening);
position = target.position - (rotation * Vector3.forward * currentDistance );
position = position - 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);
}
}
The zoom in and out work perfectly.
But the problem is, the rotate/pan is totally not working.
Anyone can give some help in this?
For the multi-touch, you have to use this script which I have given below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultiTouch: MonoBehaviour
{
float initialFingersDistance;
Vector3 initialScale;
float rotationRate = 0.2f;
int direction = 1;
void LateUpdate()
{
if (Input.touches.Length == 1)
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Touch touch = Input.touches[0];
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = transform.eulerAngles;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
// transform.Rotate(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, 0, Space.World);
Vector3 rot = new Vector3(touch.deltaPosition.y * rotationRate, -touch.deltaPosition.x * rotationRate, transform.eulerAngles.z* rotationRate);
// transform.rotation = Quaternion.EulerAngles(rot);
}
}
else if (Input.touches.Length == 2)
{
Touch t1 = Input.touches[0];
Touch t2 = Input.touches[1];
if (t1.phase == TouchPhase.Began || t2.phase == TouchPhase.Began)
{
initialFingersDistance = Vector2.Distance(t1.position, t2.position);
initialScale = gameObject.transform.localScale;
}
else if (t1.phase == TouchPhase.Moved || t2.phase == TouchPhase.Moved)
{
var currentFingersDistance = Vector2.Distance(t1.position, t2.position);
// Debug.Log(currentFingersDistance);
////if (currentFingersDistance != initialFingersDistance)
//{
var scaleFactor = currentFingersDistance / initialFingersDistance;
gameObject.transform.localScale = initialScale * scaleFactor;
//}
float Dx = t1.position.x - transform.position.x;
float Dy = t1.position.y - transform.position.y;
//var cameraTransform = Camera.main.transform.InverseTransformPoint(0, 0, 0);
//transform.position = Camera.main.ScreenToWorldPoint(new Vector3(t2.position.x, t2.position.y, cameraTransform.z -0.5f));
Vector3 pos = t2.position;
//Vector3 pos = t1.position - t2.position;
Vector3 touchedPos = Camera.main.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 10));
transform.position = Vector3.Lerp(transform.position, touchedPos, Time.deltaTime * 4);
// transform.position += touchedPos;
float pinchAmount = 0;
Quaternion desiredRotation = transform.rotation;
TouchLogic.Calculate();
if (Mathf.Abs(TouchLogic.pinchDistanceDelta) > 0)
{ // zoom
pinchAmount = TouchLogic.pinchDistanceDelta;
}
if (Mathf.Abs(TouchLogic.turnAngleDelta) > 0)
{ // rotate
Vector3 rotationDeg = Vector3.zero;
rotationDeg.z = -TouchLogic.turnAngleDelta;
desiredRotation *= Quaternion.Euler(rotationDeg);
}
// not so sure those will work:
transform.rotation = desiredRotation;
transform.position += Vector3.forward * pinchAmount;
}
}
}
}
For your touch control logic, you have to use this second script which I gave below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TouchLogic: MonoBehaviour
{
const float pinchTurnRatio = Mathf.PI / 2;
const float minTurnAngle = 0;
const float pinchRatio = 1;
const float minPinchDistance = 0;
const float panRatio = 1;
const float minPanDistance = 0;
/// <summary>
/// The delta of the angle between two touch points
/// </summary>
static public float turnAngleDelta;
/// <summary>
/// The angle between two touch points
/// </summary>
static public float turnAngle;
/// <summary>
/// The delta of the distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistanceDelta;
/// <summary>
/// The distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistance;
/// <summary>
/// Calculates Pinch and Turn - This should be used inside LateUpdate
/// </summary>
///
static public Touch LastTouch;
static public void Calculate()
{
pinchDistance = pinchDistanceDelta = 0;
turnAngle = turnAngleDelta = 0;
// if two fingers are touching the screen at the same time ...
if (Input.touchCount == 1)
{
Touch touch1 = Input.touches[0];
turnAngle = Angle(touch1.position, LastTouch.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
LastTouch.deltaPosition + LastTouch.position);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
LastTouch =Input.touches[0];
}
else if (Input.touchCount == 2)
{
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
// ... if at least one of them moved ...
if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
// ... check the delta distance between them ...
pinchDistance = Vector2.Distance(touch1.position, touch2.position);
float prevDistance = Vector2.Distance(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
pinchDistanceDelta = pinchDistance - prevDistance;
// ... if it's greater than a minimum threshold, it's a pinch!
if (Mathf.Abs(pinchDistanceDelta) > minPinchDistance)
{
pinchDistanceDelta *= pinchRatio;
}
else
{
pinchDistance = pinchDistanceDelta = 0;
}
// ... or check the delta angle between them ...
turnAngle = Angle(touch1.position, touch2.position);
float prevTurn = Angle(touch1.position + touch1.deltaPosition,
touch2.position + touch2.deltaPosition);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle)
{
turnAngleDelta *= pinchTurnRatio;
}
else
{
turnAngle = turnAngleDelta = 0;
}
}
}
}
static private float Angle(Vector2 pos1, Vector2 pos2)
{
Vector2 from = pos2 - pos1;
Vector2 to = new Vector2(1, 0);
float result = Vector2.Angle(from, to);
Vector3 cross = Vector3.Cross(from, to);
if (cross.z > 0)
{
result = 360f - result;
}
return result;
}
}
Both scripts are used in a single project. using these scripts you can easily rotate your 3d object.
Note: Please attach this both script in a single 3d object, so you can use this script easily.
I am trying to rotate a GameObject along z-axis using Joystick, but its rotating y-axis. I might missed some math calculation. Any Help??
Reference Image
void FixedUpdate()
{
// get input from joystick
// get input from joystick
rightJoystickInput = rightJoystick.GetInputDirection();
float xMovementRightJoystick = rightJoystickInput.x; // The horizontal movement from joystick 02
float zMovementRightJoystick = rightJoystickInput.y; // The vertical movement from joystick 02
// if there is only input from the right joystick
if (rightJoystickInput != Vector3.zero)
{
// calculate the player's direction based on angle
float tempAngle = Mathf.Atan2(zMovementRightJoystick, xMovementRightJoystick);
xMovementRightJoystick *= Mathf.Abs(Mathf.Cos(tempAngle));
zMovementRightJoystick *= Mathf.Abs(Mathf.Sin(tempAngle));
// rotate the player to face the direction of input
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
if (lookDirection != Vector3.zero)
{
rotationTarget.localRotation = Quaternion.Slerp(rotationTarget.localRotation, Quaternion.LookRotation(lookDirection) * Quaternion.Euler(0, 45f, 0), rotationSpeed * Time.deltaTime);
}
}
}
You don't need most of the code in your question and this is really simple.
1.Find the angle with Mathf.Atan2 then multiple it with Mathf.Rad2Deg.
2.Use Quaternion.Euler(new Vector3(0, 0, angle)) to get the rotation then apply it to the Object.
This should be one in the Update function not FixedUpdate because FixedUpdate is used to move Rigidbody Objects.
public Transform rotationTarget;
public bool flipRot = true;
void Update()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rotationTarget.rotation = Quaternion.Euler(new Vector3(0, 0, angle));
}
If using Rigidbody2D then use Rigidbody2D.MoveRotation in the FixedUpdate function. The rest of the code stays the-same.
public Rigidbody2D rg2d;
public bool flipRot = true;
void FixedUpdate()
{
rightJoystickInput = rightJoystick.GetInputDirection();
float horizontal = rightJoystickInput.x;
float vertical = rightJoystickInput.y;
float angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
EDIT:
But only the problem is when i leave joystick its rotation is setting
to 0 instantly which looks too odd. How can i fix it?
You have to detect when you release the joystick in OnPointerUp then slowly lerp the joystick thump back to the Zero position. You also have to lerp the current target object angle to zero or to its default value and this should be done in a coroutine function. When OnPointerDown is called, stop the current coroutine function. Prevent the code in FixedUpdate from running when finger is released so that it won't interfere with the coroutine function.
For the sake of completeness, below is the combination of a Joystick code and the Rigidbody answer above:
public class VirtualJoystickController : MonoBehaviour,
IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image bgImg;
private Image joystickImg;
public float mas_distance = 7f;
void Start()
{
bgImg = GameObject.Find("JoystickBGImage").GetComponent<Image>(); // the joysticks background
joystickImg = GameObject.Find("Joystickthumb").GetComponent<Image>(); // the joystick object to use
}
private Vector3 _inputDirection = Vector3.zero;
//the movementDirection
public Vector3 joystickInputDirection
{
set
{
//Change only if value is different from old one
if (_inputDirection != value)
{
_inputDirection = value;
Debug.Log("Dir: " + _inputDirection);
}
}
get
{
return _inputDirection;
}
}
public void OnDrag(PointerEventData eventData)
{
dragJoyStick(eventData);
}
void dragJoyStick(PointerEventData eventData)
{
Vector3 tempDir = Vector3.zero;
Vector2 pos = Vector2.zero;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle
(bgImg.rectTransform,
eventData.position,
eventData.pressEventCamera,
out pos))
{
pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x);
pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y);
float x = (bgImg.rectTransform.pivot.x == 1) ? pos.x * 2 + 1 : pos.x * 2 - 1;
float y = (bgImg.rectTransform.pivot.y == 1) ? pos.y * 2 + 1 : pos.y * 2 - 1;
tempDir = new Vector3(x, y, 0);
if (tempDir.magnitude > 1)
{
tempDir = tempDir.normalized;
}
joystickImg.rectTransform.anchoredPosition = new Vector3(
tempDir.x * (bgImg.rectTransform.sizeDelta.x / mas_distance),
tempDir.y * (bgImg.rectTransform.sizeDelta.y / mas_distance));
joystickInputDirection = tempDir;
}
}
public void OnPointerDown(PointerEventData eventData)
{
released = false;
//Stop current coroutine
if (retCoroutine != null)
StopCoroutine(retCoroutine);
if (eventData.pointerCurrentRaycast.gameObject == bgImg.gameObject ||
eventData.pointerCurrentRaycast.gameObject == joystickImg.gameObject)
{
OnDrag(eventData);
}
}
public void OnPointerUp(PointerEventData eventData)
{
released = true;
//Stop current coroutine then start a new one
if (retCoroutine != null)
StopCoroutine(retCoroutine);
retCoroutine = StartCoroutine(SlowReturn(returnTime));
}
IEnumerator SlowReturn(float duration)
{
RectTransform thumbstickTransform = joystickImg.rectTransform;
Vector3 toPosition = Vector3.zero;
float counter = 0;
//Get the current position of the object to be moved
Vector2 currentThumb = thumbstickTransform.anchoredPosition;
while (counter < duration)
{
counter += Time.deltaTime;
//Slowly returns thumbstick
Vector2 tempThumbStickVal = Vector2.Lerp(currentThumb, toPosition, counter / duration);
joystickInputDirection = tempThumbStickVal;
thumbstickTransform.anchoredPosition = tempThumbStickVal;
//Slowly returns the target Object to original pos
float tempTargetObjAngle = Mathf.Lerp(angle, originalAngle, counter / duration);
rg2d.MoveRotation(tempTargetObjAngle);
yield return null;
}
}
public float returnTime = 1.0f;
public Rigidbody2D rg2d;
public bool flipRot = true;
const float originalAngle = 0;
bool released = true;
float angle;
Coroutine retCoroutine;
void FixedUpdate()
{
if (released)
return;
float horizontal = joystickInputDirection.x;
float vertical = joystickInputDirection.y;
angle = Mathf.Atan2(horizontal, vertical) * Mathf.Rad2Deg;
angle = flipRot ? -angle : angle;
rg2d.MoveRotation(angle);
}
}
your function calculates a point where you want to look at:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.z += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
this point is on the XZ plane, that is why the car rotates on Y axis
if you want to rotate on Z axis, calculate a point on XY plane like this:
Vector3 temp = transform.position;
temp.x += xMovementRightJoystick;
temp.y += zMovementRightJoystick;
Vector3 lookDirection = temp - transform.position;
PS: i don't know why you multiply with Quaternion.Euler(0, 45f, 0) - that is a constant angle on Y axis, it just means that each lookDirection will be rotated for 45 degrees - i would have to see your scene to know why you need this...
I have a camera that I want to rotate around a point (0,0,0) in all directions, but I want to put a clamp on it so that it can't go too far above or below the point. I have seen this question answered for the left and right directions before but never for the vertical one.
I have tried converting the code from these two questions (that basically say the same thing) to work in the vertical direction, but it bugs out at some points along the rotation, and I can't figure out why.
First Question, Second Question
And this is how I tried to convert it:
//how much we want to rotate by this frame
float rotX = Input.GetAxis("Mouse X") * rotSpeed;
float rotY = Input.GetAxis("Mouse Y") * rotSpeed; //(before clamping)
//find current direction
Vector3 currentDirection = transform.position - Vector3.zero;
//find current angle between basis for clamp & where we are now
float angle = Vector3.Angle(Vector3.forward, currentDirection);
//finds out if it's up or down
if (Vector3.Cross(Vector3.forward, currentDirection).x < 0) angle = -angle;
//find out how much you can move without violating limits
float newAngle = Mathf.Clamp(angle + rotY, yMinLimit, yMaxLimit);
//grabs how much you are allowed to move the angle from the current angle
rotY = newAngle - angle;
//spinning the garden
transform.RotateAround(Vector3.zero, Vector3.up, rotX);
transform.RotateAround(Vector3.zero, transform.TransformDirection(Vector3.right), -rotY); //vertical rotation
If anyone knows of the correct way to make this work for the Y axis, or a different way to clamp the vertical rotation, I would be super excited to hear it! Ty!
I have a class here that do exactly what you want. It rotates a camera around a target and clamps the Y rotation. It uses the left button to rotate and the scroll press button to translate the target.
You can edit it to adjust to your specific needs - you might want to change the target to a Vector3 so you can set it to (0,0,0) without the need of an object. Hope it helps.
using UnityEngine;
public class RotateAroundCamera : MonoBehaviour
{
Camera cam;
public bool isControlable;
private Vector3 screenPoint;
private Vector3 offset;
public Transform target;
public float distance = 5.0f;
public float xSpeed = 50.0f;
public float ySpeed = 50.0f;
public float yMinLimit = -80f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
public float smoothTime = 2f;
public float rotationYAxis = 0.0f;
float rotationXAxis = 0.0f;
float velocityX = 0.0f;
float velocityY = 0.0f;
float moveDirection = -1;
public void SetControllable(bool value)
{
isControlable = value;
}
// Use this for initialization
void Start()
{
cam = GetComponentInChildren<Camera>();
Vector3 angles = transform.eulerAngles;
rotationYAxis = (rotationYAxis == 0) ? angles.y : rotationYAxis;
rotationXAxis = angles.x;
Rigidbody rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate()
{
if (target)
{
if (Input.GetMouseButton(1) && isControlable)
{
velocityX += xSpeed * Input.GetAxis("Mouse X") * 0.02f;
velocityY += ySpeed * Input.GetAxis("Mouse Y") * 0.02f;
}
if (Input.GetMouseButton(2) && isControlable)
{
Vector3 curScreenPoint = new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = cam.ScreenToWorldPoint(curScreenPoint) + offset;
target.transform.position = curPosition;
}
if (Input.GetKeyDown(KeyCode.R) && isControlable)
{
target.transform.position = Vector3.zero;
}
if (Input.GetKeyDown(KeyCode.T) && isControlable)
{
moveDirection *= -1;
}
if (isControlable)
{
distance -= Input.GetAxis("Mouse ScrollWheel");
if (distance > distanceMax)
{
distance = distanceMax;
}
else if (distance < distanceMin)
{
distance = distanceMin;
}
}
rotationYAxis += velocityX;
rotationXAxis -= velocityY;
rotationXAxis = ClampAngle(rotationXAxis, yMinLimit, yMaxLimit);
Quaternion fromRotation = Quaternion.Euler(transform.rotation.eulerAngles.x, transform.rotation.eulerAngles.y, 0);
Quaternion toRotation = Quaternion.Euler(rotationXAxis, rotationYAxis, 0);
Quaternion rotation = toRotation;
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
velocityX = Mathf.Lerp(velocityX, 0, Time.deltaTime * smoothTime);
velocityY = Mathf.Lerp(velocityY, 0, Time.deltaTime * smoothTime);
screenPoint = cam.WorldToScreenPoint(target.transform.position);
offset = target.transform.position - cam.ScreenToWorldPoint(new Vector3(moveDirection*Input.mousePosition.x, moveDirection*Input.mousePosition.y, screenPoint.z));
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}
}
Here it is. I have a human anatomy, and I would like to rotate the camera when I touch anywhere. but looking at the human anatomy. how can I do that :(
[https://www.youtube.com/watch?v=EfYeL2FYyyA&t=148s] this is what exactly I really wanted to please help me !
`
using UnityEngine;
using System.Collections;
[AddComponentMenu("Camera-Control/Mouse Orbit with zoom")]
public class MouseOrbitImproved : MonoBehaviour {
public Transform target;
public float distance = 5.0f;
public float xSpeed = 120.0f;
public float ySpeed = 120.0f;
public float yMinLimit = -20f;
public float yMaxLimit = 80f;
public float distanceMin = .5f;
public float distanceMax = 15f;
private Rigidbody rigidbody;
float x = 0.0f;
float y = 0.0f;
// Use this for initialization
void Start ()
{
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x; rigidbody = GetComponent<Rigidbody>();
// Make the rigid body not change rotation
if (rigidbody != null)
{
rigidbody.freezeRotation = true;
}
}
void LateUpdate ()
{
if (target)
{
x += Input.GetAxis("Mouse X") * xSpeed * distance * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
y = ClampAngle(y, yMinLimit, yMaxLimit);
Quaternion rotation = Quaternion.Euler(y, x, 0);
distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*5, distanceMin, distanceMax);
RaycastHit hit;
if (Physics.Linecast (target.position, transform.position, out hit))
{
distance -= hit.distance;
}
Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance);
Vector3 position = rotation * negDistance + target.position;
transform.rotation = rotation;
transform.position = position;
}
}
public static float ClampAngle(float angle, float min, float max)
{
if (angle < -360F)
angle += 360F;
if (angle > 360F)
angle -= 360F;
return Mathf.Clamp(angle, min, max);
}}
You could use a trick instead of using too many "math" in this case.
There will be empty gameObjects in each of the element you want your camera to rotate around, lets call those "anchors"
When the element is selected, you simply make the camera child of the anchor.
And then if you just rotate the anchor, your camera will rotate because it is the child.
This will get the effect you want.
Here is a simple example from youtube, for rotating the object.
Here is another one from Unity answers.
Hope this helps! Cheers!