Unity3D. C#. Can can i add max and min values to zoom in this code? - unity3d

In the 3D project I have script and i can rotate/move in the scene without doubts, but i have problem with Zoom, i can do this too close and soo far. I zoom it right to the floor or to far away to sky and i stack then. I use perspective camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class ScrollAndPinch : MonoBehaviour
{
public Camera Camera;
public bool Rotate;
protected Plane Plane;
private void Awake()
{
if (Camera == null)
Camera = Camera.main;
}
private void Update()
{
//Update Plane
if (Input.touchCount >= 1)
Plane.SetNormalAndPosition(transform.up, transform.position);
var Delta1 = Vector3.zero;
var Delta2 = Vector3.zero;
//Scroll
if (Input.touchCount >= 1)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
//Pinch
if (Input.touchCount >= 2)
{
var pos1 = PlanePosition(Input.GetTouch(0).position);
var pos2 = PlanePosition(Input.GetTouch(1).position);
var pos1b = PlanePosition(Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition);
var pos2b = PlanePosition(Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition);
//calc zoom
var zoom = Vector3.Distance(pos1, pos2) /
Vector3.Distance(pos1b, pos2b);
//edge case
if (zoom == 9 || zoom > 10)
return;
//Move cam amount the mid ray
Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, 1 / zoom);
if (Rotate && pos2b != pos2)
Camera.transform.RotateAround(pos1, Plane.normal, Vector3.SignedAngle(pos2 - pos1, pos2b - pos1b, Plane.normal));
}
}
protected Vector3 PlanePositionDelta(Touch touch)
{
//not moved
if (touch.phase != TouchPhase.Moved)
return Vector3.zero;
//delta
var rayBefore = Camera.ScreenPointToRay(touch.position - touch.deltaPosition);
var rayNow = Camera.ScreenPointToRay(touch.position);
if (Plane.Raycast(rayBefore, out var enterBefore) && Plane.Raycast(rayNow, out var enterNow))
return rayBefore.GetPoint(enterBefore) - rayNow.GetPoint(enterNow);
//not on plane
return Vector3.zero;
}
protected Vector3 PlanePosition(Vector2 screenPos)
{
//position
var rayNow = Camera.ScreenPointToRay(screenPos);
if (Plane.Raycast(rayNow, out var enterNow))
return rayNow.GetPoint(enterNow);
return Vector3.zero;
}
private void OnDrawGizmos()
{
Gizmos.DrawLine(transform.position, transform.position + transform.up);
}
}
Sorry for noob question, i've recently started to my journey in unity3D.
How can i set the limits here?

If you mean you want to limit the zoom within a single pinch operation you could probably do e.g.
// Configure these in the Inspector
[SerializeField] private float minZoom = 0.1f;
[SerializeField] private float maxZoom = 10f;
...
var zoom = Vector3.Distance(pos1, pos2) / Vector3.Distance(pos1b, pos2b);
zoom = Mathf.Clamp(minZoom, maxZoom);
...
If you ment you rather want to limit the overall combined zoom you'll have to store and combine the zoom amounts like e.g.
private float finalZoom = 1;
...
var zoom = Vector3.Distance(pos1, pos2) / Vector3.Distance(pos1b, pos2b);
finalZoom *= zoom;
finalZoom = Mathf.Clamp(minZoom, maxZoom);
// And from here use finalZoom instead of zoom
Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, 1 / finalZoom);
...

The answer is to use https://docs.unity3d.com/ScriptReference/Mathf.Clamp.html
Mathf.Clamp(xValue, xMin, xMax);

Related

How to detect finger drag on either x or y axis for mobile?

Anyway to get or recreate this type of input control for mobile touch, I essentially instead of detecting mouse drag on the y I want to detect finger drag on the y, and well honestly x too? Would I have to do this via script and if so what would the code be for that?
Input Manager Mouse Y, but I want finger Y ha :'D
This code is for both drag(pan) and zooming.
I used this code for my game
using UnityEngine;
using UnityEngine.EventSystems;
public class PanZoom : MonoBehaviour
{
Vector3 touchStart;
// Minimum amount pan to move camera
public float panMinX = 2f;
public float panMinY = 2f;
// Minimum and Maximum zoom amount for camera
public float zoomOutMin = 5f;
public float zoomOutMax = 20f;
// Scroll speed of zoom of camera
public float scrollSpeed = 5f;
void Update()
{
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
touchStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
#if UNITY_STANDALONE || UNITY_EDITOR || UNITY_WEBGL
if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
{
Vector3 direction = touchStart - Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Mathf.Abs(direction.x) > panMinX || Mathf.Abs(direction.y) > panMinY)
if (!CameraMovement.Instance.IsCameraInBorder)
{
Camera.main.transform.position += direction;
}
}
Zoom(Input.GetAxis("Mouse ScrollWheel") * scrollSpeed);
#endif
#if UNITY_ANDROID || UNITY_IOS
if (Input.touchCount == 2 && !EventSystem.current.IsPointerOverGameObject())
{
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
Vector2 touchZeroPrevPosition = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPosition = touchOne.position - touchOne.deltaPosition;
float prevMagnitude = (touchZeroPrevPosition - touchOnePrevPosition).magnitude;
float currentMagnitude = (touchZero.position - touchOne.position).magnitude;
float difference = currentMagnitude - prevMagnitude;
Zoom(difference * 0.01f);
}
else if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
{
Vector3 direction = touchStart - Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (Mathf.Abs(direction.x) > panMinX || Mathf.Abs(direction.y) > panMinY)
Camera.main.transform.position += direction;
}
#endif
}
void Zoom(float increment)
{
if(!EventSystem.current.IsPointerOverGameObject())
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize - increment, zoomOutMin, zoomOutMax);
}
}

restrict camera movement, Camera moves out of bounds

I'm creating a simple camera pan and scroll for my mobile game and need some help.
Right now with the code I have a player can scroll of the map I created.
I got the code from this youtube video (for context) https://gist.github.com/ditzel/836bb36d7f70e2aec2dd87ebe1ede432
https://www.youtube.com/watch?v=KkYco_7-ULA&ab_channel=DitzelGames
Do you know how I could fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScrollAndPinch : MonoBehaviour
{
#if UNITY_IOS || UNITY_ANDROID
public Camera Camera;
public bool Rotate;
protected Plane Plane;
public Transform Map;
float distance;
private void Awake()
{
if (Camera == null)
Camera = Camera.main;
Input.multiTouchEnabled = true;
}
private void Update()
{
//Update Plane
if (Input.touchCount >= 1)
Plane.SetNormalAndPosition(transform.up, transform.position);
var Delta1 = Vector3.zero;
var Delta2 = Vector3.zero;
//Scroll
if (Input.touchCount >= 1)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
}
protected Vector3 PlanePositionDelta(Touch touch)
{
//not moved
if (touch.phase != TouchPhase.Moved)
return Vector3.zero;
//delta
var rayBefore = Camera.ScreenPointToRay(touch.position - touch.deltaPosition);
var rayNow = Camera.ScreenPointToRay(touch.position);
if (Plane.Raycast(rayBefore, out var enterBefore) && Plane.Raycast(rayNow, out var enterNow))
return rayBefore.GetPoint(enterBefore) - rayNow.GetPoint(enterNow);
//not on plane
return Vector3.zero;
}
protected Vector3 PlanePosition(Vector2 screenPos)
{
//position
var rayNow = Camera.ScreenPointToRay(screenPos);
if (Plane.Raycast(rayNow, out var enterNow))
return rayNow.GetPoint(enterNow);
return Vector3.zero;
}
#endif
}
You can put in the update a control with the bounds of your area with a bool like this :
if(Camera.transform.position.x > valuexmax || Camera.transform.position.x < valuexmin
|| Camera.transform.position.y > valueymax || Camera.transform.position.y < valueymin)
{
InBounds = false; //just a bool variable set to true in start
}
And then you can put in the scroll something like this
if (Input.touchCount >= 1 && InBounds == true)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
if(InBounds == false)
{
// reset position
}

How to convert keyboard controls to touch screen in Unity

Complete newbie here. Using Unity C#. I'm looking at moving my PONG game from keyboard control to touch screen. Here is my working keyboard code:
// Player 1 => Controls left bat with W/S keys
public GameObject leftBat;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//Defualt speed of the bat to zero on every frame
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, 0f, 0f);
//If the player is pressing the W key...
if (Input.GetKey (KeyCode.W)) {
//Set the velocity to go up 1
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, 8f, 0f);
}
//If the player is pressing the S key...
else if (Input.GetKey (KeyCode.S)) {
//Set the velocity to go down 1 (up -1)
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, -8f, 0f);
}
}
I found this code and been playing around with it but to now avail.
using UnityEngine;
using System.Collections;
public class Player_Input_Controller : MonoBehaviour {
public GameObject leftBat;
public float paddleSpeed = 1f;
public float yU;
public float yD;
private Ray ray;
private RaycastHit rayCastHit;
private Vector3 playerPos = new Vector3(0, -9.5f, 0);
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out rayCastHit)){
Vector3 position = rayCastHit.point;
float yPos = position.y;
playerPos = new Vector3(Mathf.Clamp(yPos, yU, yD), -9.5f, 0f);
transform.position = playerPos;
}
}
}
}
Any one have a touchscreen Pong script I could use, or know how to edit this one?
Again, I'm really new and I'm sorry if I look like the Dummy in the class.
Thanks for any help provided. I REALLY appreciate it. This is the last hurdle in completing my game.
In my opinion, you do not need any raycasting. Because you are working in 2D and you are only concerned about the y value of Input.mousePosition. Therefore, you can calculate the extent of your screen using your camera's z value. If your camera is at (0, 0, -10) lets say your extents in the game will be -5 - BatOffset to 5+BatOffset in your world coordinates. Therefore, you somehow need a function to map Screen.height to your world coordinate extents as you can see from the image.
In conclusion you need to find Input.mousePosition.y divide it to Screen.height. This will give you the ratio where you touch or click. Then find the position in world space.
Note that: you can also use Input.touchPosition.y. Following script will work for you to do this operation:
public GameObject cam;
private Vector3 batPos;
private float minY;
private float maxY;
private int Res;
private float deltaY;
void Start () {
minY = cam.transform.position.z / 2 - gameObject.transform.localScale.y;
maxY = (-cam.transform.position.z / 2) + gameObject.transform.localScale.y;
deltaY = maxY - minY;
Debug.Log(minY + " " + maxY + " " + deltaY);
Res = Screen.height;
batPos = gameObject.transform.position;
}
void Update () {
if(Input.GetMouseButtonDown(0))
{
// we find the height we have to go up from minY
batPos.y =minY + Input.mousePosition.y / Res * deltaY;
gameObject.transform.position = batPos;
}
}
This works for me in the editor when you click on screen with mouse. You just have to change the parts Input.GetMouseButtonDown to Touch commands such as Touch.tapCount > 0. Also this script should be attached to the bat. Good luck!
Also You can use Orthographic camera and Orthographic camera size instead of cam.transformation.z
May be helpfull
create script. for example player.cs
public class PlayerController : MonoBehaviour
{
bool swipeRight = false;
bool swipeLeft = false;
bool touchBlock = true;
bool canTouchRight = true;
bool canTouchLeft = true;
void Update()
{
swipeLeft = Input.GetKeyDown("a") || Input.GetKeyDown(KeyCode.LeftArrow);
swipeRight = Input.GetKeyDown("d") || Input.GetKeyDown(KeyCode.RightArrow);
TouchControl();
if(swipeRight) //rightMove logic
else if(swipeLeft) //leftMove logic
}
void TouchControl()
{
if(Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began )
{
//Jump logic
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved && touchBlock == true)
{
touchBlock = false;
// Get movement of the finger since last frame
var touchDeltaPosition = Input.GetTouch(0).deltaPosition;
Debug.Log("touchDeltaPosition "+touchDeltaPosition);
if(touchDeltaPosition.x > 0 && canTouchRight == true)
{
//rightMove
swipeRight = true; canTouchRight = false;
Invoke("DisableSwipeRight",0.2f);
}
else if(touchDeltaPosition.x < 0 && canTouchLeft == true)
{
//leftMove
swipeLeft = true; canTouchLeft = false;
Invoke("DisableSwipeLeft",0.2f);
}
}
}
void DisableSwipeLeft()
{
swipeLeft = false;
touchBlock = true;
canTouchLeft = true;
}
void DisableSwipeRight()
{
swipeRight = false;
touchBlock = true;
canTouchRight = true;
}
}

Unity: How to limit the zooming out of the camera

Using Unity 2018.3
This camera script allows the user to zoom in and out and move the camera with touch around.
On Start() the script takes the cameras current position and saves it as the out of bounds limit. So if the player is zoomed in and moves the camera to the side, the camera will stop when it reaches the bounds limit.
My problem is that currently the user can zoom out all they want, causing the camera to get shaky as the script is trying to relocate the camera but it doesn't stop the user from increasing the orthographicSize.
How do I limit the user from zooming out passed the out of bound limit it got on Start()?
public class ControlCamera : MonoBehaviour
{
private Vector2?[] oldTouchPositions = {
null,
null
};
private Vector2 oldTouchVector;
private float oldTouchDistance;
private Vector3 bottomLeft;
private Vector3 topRight;
private float cameraMaxY;
private float cameraMinY;
private float cameraMaxX;
private float cameraMinX;
public float maxZoom;
public float minZoom;
private void Start()
{
// Set max camera bounds
topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));
cameraMaxX = topRight.x;
cameraMaxY = topRight.y;
cameraMinX = bottomLeft.x;
cameraMinY = bottomLeft.y;
}
private void Update()
{
// No touches
if (Input.touchCount == 0)
{
oldTouchPositions[0] = null;
oldTouchPositions[1] = null;
}
// 1 Touch
else if (Input.touchCount == 1)
{
if (oldTouchPositions[0] == null || oldTouchPositions[1] != null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = null;
}
else
{
Vector2 newTouchPosition = Input.GetTouch(0).position;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] - newTouchPosition) * GetComponent<Camera>().orthographicSize / GetComponent<Camera>().pixelHeight * 2f));
oldTouchPositions[0] = newTouchPosition;
}
// 2 touches or more
} else {
if (oldTouchPositions[1] == null)
{
oldTouchPositions[0] = Input.GetTouch(0).position;
oldTouchPositions[1] = Input.GetTouch(1).position;
oldTouchVector = (Vector2)(oldTouchPositions[0] - oldTouchPositions[1]);
oldTouchDistance = oldTouchVector.magnitude;
} else {
Vector2 screen = new Vector2(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight);
Vector2[] newTouchPositions = {
Input.GetTouch(0).position,
Input.GetTouch(1).position
};
Vector2 newTouchVector = newTouchPositions[0] - newTouchPositions[1];
float newTouchDistance = newTouchVector.magnitude;
transform.position += transform.TransformDirection((Vector3)((oldTouchPositions[0] + oldTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y));
GetComponent<Camera>().orthographicSize *= oldTouchDistance / newTouchDistance;
transform.position -= transform.TransformDirection((newTouchPositions[0] + newTouchPositions[1] - screen) * GetComponent<Camera>().orthographicSize / screen.y);
oldTouchPositions[0] = newTouchPositions[0];
oldTouchPositions[1] = newTouchPositions[1];
oldTouchVector = newTouchVector;
oldTouchDistance = newTouchDistance;
// --------------------------------------------------------------->>
// Control Zoom In
if (GetComponent<Camera>().orthographicSize > minZoom)
{
//
}
// Control Zoom Out
if (GetComponent<Camera>().orthographicSize < maxZoom)
{
//
}
// --------------------------------------------------------------->>
}
}
// Check if camera is out-of-bounds, if so, move back in-bounds
topRight = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(GetComponent<Camera>().pixelWidth, GetComponent<Camera>().pixelHeight, -transform.position.z));
bottomLeft = GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, 0, -transform.position.z));
if (topRight.x > cameraMaxX)
{
transform.position = new Vector3(transform.position.x - (topRight.x - cameraMaxX), transform.position.y, transform.position.z);
}
if (topRight.y > cameraMaxY)
{
transform.position = new Vector3(transform.position.x, transform.position.y - (topRight.y - cameraMaxY), transform.position.z);
}
if (bottomLeft.x < cameraMinX)
{
transform.position = new Vector3(transform.position.x + (cameraMinX - bottomLeft.x), transform.position.y, transform.position.z);
}
if (bottomLeft.y < cameraMinY)
{
transform.position = new Vector3(transform.position.x, transform.position.y + (cameraMinY - bottomLeft.y), transform.position.z);
}
}
}
You should not use GetComponent repeatedly especially not in Update or any repeatedly called method as this creates a lot unnecessary overhead. Instead get it once
private Camera camera;
private void Awake()
{
camera = GetComponent<Camera>();
}
and reuse that reference -> Everywhere replace GetComponent<Camera>() width camera
If my understanding is correct, orthographicSize is half of the height of the camera in world units.
Since you already get topRight and bottomLeft in world coordinates you should be able to calculate an orthographicSize
maxZoom = (CameraMaxY - CameraMinY) / 2.0f;
however, if anyway you want the original zoom to be the max zoom you could also simply store the original zoom like
maxZoom = camera.orthographicSize;
And later you can simply clamp the value like
camera.orthographicSize = Mathf.Clamp(
camera.orthographicSize * oldTouchDistance / newTouchDistance,
minZoom,
maxZoom);
-> no need for extra if checks

Orthographic camera zoom with focus on a specific point

I have an orthographic camera and would like to implement a zoom feature to a specific point. I.e., imagine you have a picture and want to zoom to a specific part of the picture.
I know how to zoom in, the problem is to move the camera to a position that has the desired zone in focus.
How can I do so?
The camera's orthographicSize is the number of world space units in the top half of the viewport. If it's 0.5, then a 1 unit cube will exactly fill the viewport (vertically).
So to zoom in on your target region, center your camera on it (by setting (x,y) to the target's center) and set orthographicSize to half the region's height.
Here is an example to center and zoom to the extents of an object. (Zoom with LMB; 'R' to reset.)
public class OrthographicZoom : MonoBehaviour
{
private Vector3 defaultCenter;
private float defaultHeight; // height of orthographic viewport in world units
private void Start()
{
defaultCenter = camera.transform.position;
defaultHeight = 2f*camera.orthographicSize;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Collider target = GetTarget();
if(target != null)
OrthoZoom(target.bounds.center, target.bounds.size.y); // Could directly set orthographicSize = bounds.extents.y
}
if (Input.GetKeyDown(KeyCode.R))
OrthoZoom(defaultCenter, defaultHeight);
}
private void OrthoZoom(Vector2 center, float regionHeight)
{
camera.transform.position = new Vector3(center.x, center.y, defaultCenter.z);
camera.orthographicSize = regionHeight/2f;
}
private Collider GetTarget()
{
var hit = new RaycastHit();
Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit);
return hit.collider;
}
}
hope you find this code example useful, should be a copy / paste.
Note: this script assume it's attached to the camera object, otherwise you should adjust the transform to the camera object reference.
private float lastZoomDistance = float.PositiveInfinity; // remember that this should be reset to infinite on touch end
private float maxZoomOut = 200;
private float maxZoomIn = 50;
private float zoomSpeed = 2;
void Update() {
if (Input.touchCount >= 2) {
Vector2 touch0, touch1;
float distance;
Vector2 pos = new Vector2(transform.position.x, transform.position.y);
touch0 = Input.GetTouch(0).position - pos;
touch1 = Input.GetTouch(1).position - pos;
zoomCenter = (touch0 + touch1) / 2;
distance = Vector2.Distance(touch0, touch1);
if(lastZoomDistance == float.PositiveInfinity) {
lastZoomDistance = distance;
} else {
if(distance > lastZoomDistance && camera.orthographicSize + zoomSpeed <= maxZoomOut) {
this.camera.orthographicSize = this.camera.orthographicSize + zoomSpeed;
// Assuming script is attached to camera - otherwise, change the transform.position to the camera object
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
} else if(distance < lastZoomDistance && camera.orthographicSize - zoomSpeed >= maxZoomIn) {
this.camera.orthographicSize = this.camera.orthographicSize - zoomSpeed;
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
}
}
lastZoomDistance = distance;
}
}