Is there a way to zoom a 2D canvas in Unity? - c#

I am making a 2d mobile app, and I would like to zoom in my screen. I have a Screen Space - Overlay in my canvas. I tried this but it does not zoom my screen.
I have attached this script to my canvas:
Vector3 touchStart;
public float zoomOutMin = 1;
public float zoomOutMax = 8;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (Input.touchCount == 2)
{
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
float prevMagnitude = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float currentMagnitude = (touchZero.position - touchOne.position).magnitude;
float difference = currentMagnitude - prevMagnitude;
zoom(difference * 0.01f);
}
else if (Input.GetMouseButton(0))
{
Vector3 direction = touchStart - Camera.main.ScreenToWorldPoint(Input.mousePosition);
Camera.main.transform.position += direction;
}
zoom(Input.GetAxis("Mouse ScrollWheel"));
}
void zoom(float increment)
{
Camera.main.orthographicSize = Mathf.Clamp(Camera.main.orthographicSize - increment, zoomOutMin, zoomOutMax);
}

Instead of changing camera orthographic size you can try the other way round and change scale of canvas itself in both axis equally something like
Edit : I am editing the script to explain better. Just attach this script to Parent of the objects you want to zoom in to. You must not attach this on canvas as it will have no effect instead you can create an empty parent and move all of the objects to be zoomed in inside that parent as children and attach this script to parent.
public class ZoomTest : MonoBehaviour
{
[SerializeField] private float zoomOutMin;
[SerializeField] private float zoomOutMax;
private void Update()
{
float MouseWheelAxis = Input.GetAxis("Mouse ScrollWheel");
if (MouseWheelAxis != 0)
{
zoom(MouseWheelAxis);
}
}
void zoom(float increment)
{
float ClampX = Mathf.Clamp(transform.localScale.x +
increment,
zoomOutMin, zoomOutMax);
float ClampY = Mathf.Clamp(transform.localScale.y +
increment,
zoomOutMin, zoomOutMax);
transform.localScale = new
Vector2(ClampX ,ClampY);
}
}

Related

UNITY - Camera Orbit, move camera to some fixed positions

i have a scene in which i have a camera that is orbiting around a pivot in a 180° semisphere. All is working like intended but now i would like to point the camera to some fixed coordinates of the semisphere (possibily in a smooth way). Can someone give me some hints? I'll post the code i'm using right now.
public class CameraOrbitTouch : MonoBehaviour {
protected Transform _XForm_Camera;
protected Transform _XForm_Parent;
protected Vector3 _LocalRotation;
protected float _CameraDistance = 10f;
// The rate of change of the field of view in perspective mode.
public float perspectiveZoomSpeed = 0.2f;
public float OrbitDampening = 30f;
public float ScrollDampening = 18f;
public bool CameraDisabled = false;
public bool moving = false;
// Use this for initialization
void Start() {
this._XForm_Camera = this.transform;
this._XForm_Parent = this.transform.parent;
}
void LateUpdate() {
if (Input.GetKeyDown(KeyCode.LeftShift))
CameraDisabled = !CameraDisabled;
if (!CameraDisabled)
{
//Rotation of the Camera based on Mouse Coordinates
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
moving = true;
_LocalRotation.x += Input.touches[0].deltaPosition.x ;
_LocalRotation.y += Input.touches[0].deltaPosition.y;
//Clamp the y Rotation to horizon and not flipping over at the top
if (_LocalRotation.y < 0f)
_LocalRotation.y = 0f;
else if (_LocalRotation.y > 90f)
_LocalRotation.y = 90f;
}
//Zooming Input from our Mouse Scroll Wheel
if ((Input.touchCount == 2)&& (Input.GetTouch(0).phase == TouchPhase.Moved) && (Input.GetTouch(1).phase == TouchPhase.Moved))
{
moving = true;
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = (prevTouchDeltaMag - touchDeltaMag);
//this._CameraDistance += deltaMagnitudeDiff * -1f;
this._CameraDistance += deltaMagnitudeDiff * perspectiveZoomSpeed;
this._CameraDistance = Mathf.Clamp(this._CameraDistance, 1.5f, 100f);
}
}
if (moving)
{
//Actual Camera Rig Transformations
Quaternion QT = Quaternion.Euler(_LocalRotation.y, _LocalRotation.x, 0);
this._XForm_Parent.rotation = Quaternion.Lerp(this._XForm_Parent.rotation, QT, Time.deltaTime * OrbitDampening);
if (this._XForm_Camera.localPosition.z != this._CameraDistance * -1f)
{
this._XForm_Camera.localPosition = new Vector3(0f, 0f,Mathf.Lerp(this._XForm_Camera.localPosition.z, this._CameraDistance * -1f, Time.deltaTime * ScrollDampening));
}
moving = false;
}
}
}
I tought i could use somethig like this
string selectedObj = "CameraPivot";
camera = GameObject.Find(selectedObj);
camera.transform.rotation = Quaternion.Euler(90.0f, 0.0f, 100.0f);
But i think is not the right waty to make it work...

Rotate 2D Sprite with Virtual Joystick

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...

Unity C# use Transform.RotateAround with touch to move camera around target

So am looking at changing my Transform.RotateAround script for touch input. If I get rid of the "Input.GetAxis", the camera rotates on its own around the target. I cant seem to figure out how to format the code to get the position of the touch to a string to use with this. If anyone has any tips that would be awesome!
Here is the code:
using UnityEngine;
using System.Collections;
[AddComponentMenu("Camera-Control/Mouse Orbit with zoom2")]
public class MouseOrbitImproved2 : MonoBehaviour {
public float speed;
public Transform target;
public float rotateSpeed;
public Transform camera = Camera.main.transform;
public Vector3 camPosition;
public float camSpeed;
public float minDistance;
public float maxDistance;
//private Vector3 moveDirection = Vector3.zero;
//private Vector3 moveDirection = target.position;
public float perspectiveZoomSpeed = 0.5f; // The rate of change of the field of view in perspective mode.
public float orthoZoomSpeed = 0.5f; // The rate of change of the orthographic size in orthographic mode.
void start() {
//camPosition = camera.transform.position;
}
public void Update() {
if (Input.touchCount == 1) {
transform.LookAt(target);
Touch touchSwipe = Input.GetTouch(0);
string position = touchSwipe.deltaPosition;
transform.RotateAround(target.position, Vector3.up, Input.GetAxis(position)* speed);
transform.RotateAround(target.position, Vector3.forward, Input.GetAxis(position)* speed);
}
transform.LookAt(target);
/*
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0)
{
// calculate new position first...
camPosition += transform.forward * scroll * camSpeed;
// then compare to the limits:
float distanceToTarget = Vector3.Distance(target.position, camPosition);
// you can clamp the movement to min and max distances:
if (distanceToTarget > maxDistance){ // clamp at maxDistance...
camPosition = target.position - maxDistance * transform.forward;
}
if (distanceToTarget < minDistance){ // or at minDistance
camPosition = target.position - minDistance * transform.forward;
}
// finally, update the actual camera position:
transform.position = camPosition;
// set camera position
}
*/
// If there are two touches on the device...
if (Input.touchCount == 2)
{
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
// If the camera is orthographic...
if (Camera.main.orthographic)
{
// ... change the orthographic size based on the change in distance between the touches.
Camera.main.orthographicSize += deltaMagnitudeDiff * orthoZoomSpeed;
// Make sure the orthographic size never drops below zero.
Camera.main.orthographicSize = Mathf.Max(Camera.main.orthographicSize, 0.1f);
}
else
{
// Otherwise change the field of view based on the change in distance between the touches.
Camera.main.fieldOfView += deltaMagnitudeDiff * perspectiveZoomSpeed;
// Clamp the field of view to make sure it's between 0 and 180.
Camera.main.fieldOfView = Mathf.Clamp(Camera.main.fieldOfView, 0.1f, 179.9f);
}
}
}
public void ChangeToAxial (){
Camera.main.transform.position = new Vector3 (45.3f,234.5f,66.9f);
}
public void ChangeToSagright (){
Camera.main.transform.position = new Vector3 (28.13f,76.41f,222.68f);
}
public void ChangeToSagleft (){
Camera.main.transform.position = new Vector3 (49.36f,66.85f,-93.78f);
}
public void ChangeToCoronal () {
Camera.main.transform.position = new Vector3 (-71.6f,69.66f,66.29f);
}
}
I think it may be best if you look at this question and answer from the unity forum Unit 5 forum rotating camera with touch. It should work with the Input.GetTouch instead of the Input.GetAxis. Hope that helps. Be aware that script is in Javascript, but you shouldn't need the whole script.

Monogame - Making the camera stop when my player collides

I have come to a position with my 3D game where I am now trying to perfect the camera. What I ultimately want is a working first person camera that stops when it collides with a wall. I assume you do this by having the camera move with a model and have the model collide to stop the camera also, i am just having issues seeing how to do that.
I have the model working so it stops, i just need to lock the camera from moving also. So far this is the code I have, making the model stop with collison:
if (player_health != 0)
{
if (kb.IsKeyDown(Keys.Left))
{
player_x = player_x + 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
if (IsCollision(ball, world_player, ball, world_spike))
{
player_x = player_x - 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
player_health = 0;
}
if (IsCollision(ball, world_player, ball, world_bullet[0]))
{
player_health = 0;
}
// use this code for any standard collision
if ((IsCollision(ball, world_player, ball, world_cannon)) || (IsCollision(ball, world_player, ball, walls[0])) || (IsCollision(ball, world_player, ball, walls[1])))
{
player_x = player_x - 0.05f;
world_player = Matrix.CreateTranslation(new Vector3(player_x, player_y, player_z));
}
}
My camera added into the game1 class:
camera = new Camera(this, new Vector3(10f, 3f, 5f), Vector3.Zero, 5f);
Components.Add(camera);
And the camera class itself (I have been told this is rather over complicated? for a camera class, but the simpler ones didnt work):
namespace Game7
{
class Camera : GameComponent
{
private Vector3 cameraPosition;
private Vector3 cameraRotation;
private float cameraSpeed;
private Vector3 cameraLookAt;
private Vector3 mouseRotationBuffer;
private MouseState currentMouseState;
private MouseState previousMouseState;
// Properties
public Vector3 Position
{
get { return cameraPosition; }
set
{
cameraPosition = value;
UpdateLookAt();
}
}
public Vector3 Rotation
{
get { return cameraRotation; }
set
{
cameraRotation = value;
UpdateLookAt();
}
}
public Matrix Projection
{
get;
protected set;
}
public Matrix View
{
get
{
return Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);
}
}
//Constructor
public Camera(Game game, Vector3 position, Vector3 rotation, float speed)
: base(game)
{
cameraSpeed = speed;
// projection matrix
Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver4,
Game.GraphicsDevice.Viewport.AspectRatio,
0.05f,
1000.0f);
// set camera positiona nd rotation
MoveTo(position, rotation);
previousMouseState = Mouse.GetState();
}
// set Camera's position and rotation
private void MoveTo(Vector3 pos, Vector3 rot)
{
Position = pos;
Rotation = rot;
}
//update the look at vector
private void UpdateLookAt()
{
// build rotation matrix
Matrix rotationMatrix = Matrix.CreateRotationX(cameraRotation.X) * Matrix.CreateRotationY(cameraRotation.Y);
// Look at ofset, change of look at
Vector3 lookAtOffset = Vector3.Transform(Vector3.UnitZ, rotationMatrix);
// update our cameras look at vector
cameraLookAt = cameraPosition + lookAtOffset;
}
// Simulated movement
private Vector3 PreviewMove(Vector3 amount)
{
// Create rotate matrix
Matrix rotate = Matrix.CreateRotationY(cameraRotation.Y);
// Create a movement vector
Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
movement = Vector3.Transform(movement, rotate);
return cameraPosition + movement;
}
// Actually move the camera
private void Move(Vector3 scale)
{
MoveTo(PreviewMove(scale), Rotation);
}
// updat method
public override void Update(GameTime gameTime)
{
// smooth mouse?
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
currentMouseState = Mouse.GetState();
KeyboardState ks = Keyboard.GetState();
// input
Vector3 moveVector = Vector3.Zero;
if (ks.IsKeyDown(Keys.W))
moveVector.Z = 1;
if (ks.IsKeyDown(Keys.S))
moveVector.Z = -1;
if (ks.IsKeyDown(Keys.A))
moveVector.X = 1;
if (ks.IsKeyDown(Keys.D))
moveVector.X = -1;
if (moveVector != Vector3.Zero)
{
//normalize it
//so that we dont move faster diagonally
moveVector.Normalize();
// now smooth and speed
moveVector *= dt * cameraSpeed;
// move camera
Move(moveVector);
}
// Handle mouse input
float deltaX;
float deltaY;
if(currentMouseState != previousMouseState)
{
//Cache mouse location
deltaX = currentMouseState.X - (Game.GraphicsDevice.Viewport.Width / 2);
deltaY = currentMouseState.Y - (Game.GraphicsDevice.Viewport.Height / 2);
// smooth mouse ? rotation
mouseRotationBuffer.X -= 0.01f * deltaX * dt;
mouseRotationBuffer.Y -= 0.01f * deltaY * dt;
if (mouseRotationBuffer.Y < MathHelper.ToRadians(-75.0f))
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(-75.0f));
if (mouseRotationBuffer.Y > MathHelper.ToRadians(75.0f))
mouseRotationBuffer.Y = mouseRotationBuffer.Y - (mouseRotationBuffer.Y - MathHelper.ToRadians(75.0f));
Rotation = new Vector3(-MathHelper.Clamp(mouseRotationBuffer.Y, MathHelper.ToRadians(-75.0f), MathHelper.ToRadians(75.0f)), MathHelper.WrapAngle(mouseRotationBuffer.X), 0);
deltaX = 0;
deltaY = 0;
}
// Alt + F4 to close now.
// Makes sure the mouse doesn't wander across the screen (might be a little buggy by showing the mouse)
Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
previousMouseState = currentMouseState;
base.Update(gameTime);
}
}
}
The Preview Move part of the camera class is meant to be where it detects for collision, at least the guide i followed said so, i just dont see how to integrate it. Thanks for any help or input, even if it is just a link to another guide or resource, would be very appreciated!
If your hero model (player) already has move functionality and collision functionality, and you want the camera to follow the model, then you can simplify the camera update tremendously.
Assuming after moving the player, the new position and/or orientation of the player is represented in player_world, simply borrow the location and orientation information stored in the player_world matrix to build a view matrix each frame.
//after moving player and setting its matrix accordingly:
view = Matrix.Invert(player_world);
And that is your complete camera class update. This creates a view matrix that is in the same position as the player and facing the same direction he is. If the player model stops because it hits a wall, then the camera (view matrix) stops too, because it is built from the player's 'stopped' matrix. No need to create a whole class for moving and rotating the camera around when the movement and rotation is the same as the player.
Sometimes the local player model origin would be located at the player's feet or belly and you want the camera up in the head where the eyes are. If so, simply apply something like this:
//after moving player and setting its matrix accordingly:
Matrix camera_world = player_world;
camera_world *= Matrix.CreateTranslation(Vector3.Up * ??f);// set ??f to the height difference between feet and head
view = Matrix.Invert(camera_world);

Unity 2D - zoom in =ok, zoom out = borked

I hope someone can help. Im trying to create a little script that zooms in to my player and back out - toggling.
The zoom in works fine, but when I try to zoom back out it doesn't work, it gets stuck. I've created a bool to ensure it only runs the code when it needs to and I'm wondering if that is what's causing the error.
using UnityEngine;
using System.Collections;
public class CameraZoom : MonoBehaviour
{
public float zoom = 10f;
public float normal = 3.471398f;
public float smooth = 5f;
private bool isZoomed = false;
public Camera cam;
public GameObject player;
// lock the camera settings
public float LockedX = 0f;
public float LockedY = 0f;
public float LockedZ = 0f;
private bool hasBeenZoomed = false;
Vector3 targetPos;
private Transform playerTransform;
// Use this for initialization
void Start()
{
targetPos = transform.position;
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("z")) { isZoomed = !isZoomed; }
if (isZoomed == true)
{
ZoomInToPlayer();
hasBeenZoomed = true;
}
else
{
if (hasBeenZoomed)
{
ZoomOutFromPlayer();
hasBeenZoomed = false;
}
}
}
void ZoomInToPlayer()
{
// By default the target x and y coordinates of the camera are it's current x and y coordinates.
float targetX = transform.position.x;
float targetY = transform.position.y;
// ... the target x coordinate should be a Lerp between the camera's current x position and the player's current x position.
targetX = Mathf.Lerp(transform.position.x, playerTransform.position.x, smooth * Time.deltaTime);
//Debug.Log("player x is " + playerTransform.position.x + " and TargetX is " + targetX);
// ... the target y coordinate should be a Lerp between the camera's current y position and the player's current y position.
targetY = Mathf.Lerp(transform.position.y, playerTransform.position.y, smooth * Time.deltaTime);
//Debug.Log("player y is " + playerTransform.position.y+ " and TargetY is " + targetY);
// Set the camera's position to the target position with the same z component.
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// Change the size of the camera viewport
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, zoom, Time.deltaTime * smooth);
}
void ZoomOutFromPlayer()
{
// By default the target x and y coordinates of the camera are it's current x and y coordinates.
float targetX;
float targetY;
// Change the size of the camera viewport
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, normal, Time.deltaTime * smooth);
// ... the target x coordinate should be a Lerp between the camera's current x position and the original x position.
targetX = Mathf.Lerp(transform.position.x, LockedX, smooth * Time.deltaTime);
// ... the target y coordinate should be a Lerp between the camera's current y position and the original y position.
targetY = Mathf.Lerp(transform.position.y, LockedY, smooth * Time.deltaTime);
// Set the camera's position to the target position with the same z component.
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
}
}
Your methods ZoomInToPlayer and ZoomOutFromPlayer are written in a way that suggests that they should be called once per frame for the duration of the zoom in/out animation. However, ZoomOutFromPlayer will only be called once, because Update, when ZoomOutFromPlayer is called, the hasBeenZoomed is immediately set to false.
What you're trying to do here, essentially, is a simple Finite State Machine. I suggest researching this design pattern a little more — it will help you noticing the sources of such problems and structuring your code in a better way.
In this particular case, a good way to prevent this problem when designing your code would be to write something akin to "API documentation" for yourself, when writing your methods. For ZoomOutFromPlayer, it would read something like this:
Call every frame when you want to perform zoom-out animation, until the animation is complete.
After you written (and read) such a description, you should immediately notice a red flag — "until the animation is complete"? So, the code that calls this method should somehow take track of whether the animation is complete or not, during a separate mechanism? Wouldn't it make it really easy to use this method incorrectly? Well, that's exactly what happened here.
Instead, what you could've done, is to create two different methods, ZoomInUpdate and ZoomOutUpdate, with descriptions that would read something like this:
Call every frame when the camera should be zoomed out/zoomed in.
This way, using this methods is a lot easier, and you can safely throw out additional logic with hasBeenZoomed out. Just call these methods every frame, and ensure (inside these methods) that they change the camera settings with a certain speed, if these settings need to be changed, or otherwise do nothing.
Try this
using UnityEngine;
using System.Collections;
public class CameraZoom : MonoBehaviour
{
public float zoom = 10f;
public float normal = 3.471398f;
public float smooth = 5f;
private bool isZoomed = false;
private bool isZoomFinished = true; // the animation zoom is over ?
public Camera cam;
public GameObject player;
public float LockedX = 0f;
public float LockedY = 0f;
public float LockedZ = 0f;
private bool hasBeenZoomed = false;
Vector3 targetPos;
private Transform playerTransform;
void Start()
{
targetPos = transform.position;
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update()
{
if (Input.GetKeyDown("z") && isZoomFinished) {
isZoomed = !isZoomed;
isZoomFinished = false;
}
if (isZoomed && !isZoomFinished)
{
ZoomInToPlayer();
}
else if (!isZoomed && !isZoomFinished)
{
ZoomOutFromPlayer()
}
}
float delta = 0;
void ZoomInToPlayer()
{
delta += smooth * Time.deltaTime;
//Cam size
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, zoom, delta);
//Cam pos
float targetX = transform.position.x;
float targetY = transform.position.y;
targetX = Mathf.Lerp(transform.position.x, playerTransform.position.x, delta);
targetY = Mathf.Lerp(transform.position.y, playerTransform.position.y, delta);
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// is animation over ?
if(delta >= 1) {
isZoomFinished = true;
delta = 0;
}
}
void ZoomOutFromPlayer()
{
delta += smooth * Time.deltaTime;
//Cam size
cam.orthographicSize = Mathf.Lerp(cam.orthographicSize, normal, delta);
//Cam pos
float targetX;
float targetY;
targetX = Mathf.Lerp(transform.position.x, LockedX, delta);
targetY = Mathf.Lerp(transform.position.y, LockedY, delta);
cam.transform.position = new Vector3(targetX, targetY, transform.position.z);
// is animation over ?
if(delta >= 1) {
isZoomFinished = true;
delta = 0;
}
}
}

Categories