#FaresFilms Zooming Code
1 messages · Page 1 of 1 (latest)
@dense hound
so how do you intend on zooming in and out in your game?
is it just a camera that changes its distance when you scroll?
sorry the internet is really slow
Yes, I use cinemachines VCam though
makes no difference, the issue here is ScreenToWorldPoint
thats for converting a position on the screen into a 3d coordinate
sorta like how a crosshair can indicate to someone where a bullet will go in an FPS
hm
if you zoom out, that distance will increase, naturally
and that will then make the next attempt to zoom a bigger change
so what would I use instead
lets see the full code again so i can get a better look at how to fit a solution into your work
this is the zoom file (attached to main camera)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class zoom : MonoBehaviour
{
float zoomValue = 10f;
// Update is called once per frame
void Update()
{
// if(Camera.main.orthographic) {
// Camera.main.orthographicSize -= Input.GetAxis("Mouse ScrollWheel") * zoomValue;
// } else {
// Camera.main.fieldOfView -= Input.GetAxis("Mouse ScrollWheel") * zoomValue;
// }
var camera = Camera.main;
var brain = (camera == null) ? null : camera.GetComponent<CinemachineBrain>();
var vcam = (brain == null) ? null : brain.ActiveVirtualCamera as CinemachineVirtualCamera;
if (vcam != null) {
vcam.m_Lens.OrthographicSize -= Input.GetAxis("Mouse ScrollWheel") * zoomValue;
print(Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
}
}
lets clean this up a bit
then work on a fix, var is vague, you are constantly replacing the reference every frame, and ternaries are a bit awkward to read with no performance benefits
just to explain my thought process, I wanted to zoom in to center, and then use cinemachine to move the camera to the mouse. It didn't work and I have no problems with changing everything
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class zoom : MonoBehaviour
{
private Camera MyCamera;
private CinemachineBrain MyBrain;
private CinemachineVirtualCamera MyVCam;
float zoomValue = 10f;
void Start()
{
MyCamera = Camera.main;
MyBrain = MyCamera.GetComponent<CinemachineBrain>();
MyVCam = MyBrain.ActiveVirtualCamera as CinemachineVirtualCamera;
}
// Update is called once per frame
void Update()
{
if (MyVCam)
{
MyVCam.m_Lens.OrthographicSize -= Input.GetAxis("Mouse ScrollWheel") * zoomValue;
print(Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
}
}```
okay so its a little cleaner now
no need to constantly check if things exist, ideally, let them exist or cause a bug, handle the bug itself, rather than prepare for one every single frame
alright
now, in the update method, it seems you arent even using the screenworld to point thingy any more
but you are printing it
yeah I asked elsewhere, and some suggestion were made and I removed it
so when you scroll, what do you want it to do?
just get closer and further away yeah?
yes
okay, so that code is already pretty close to perfect
now for moving the camera to the mouse position, thats an interesting one
oh so zooming at a certain location?
yes
thats not something ive tried, interesting
maybe thats why I couldn't find many tutorials on this exactly
just trying to think this through, havent ditched you dw
wherever the mouse IS, the camera seems to center around it
as if the map itself is moving and the camera is moving in the opposite direction to make up for it
odd
its odd how hard this is to think through, never really considered this before, wow
I've done this before, and from what I could remember:
- you zoom in (already works)
- you get the mouse postion before scaling and after scaling and subtract
- Add that offset to the camera's pos
actually lemme look in my files I might find something
good shout
I found this which someone gave me which I believe originated from a stackoverflow question. The steps to zooming in with the center of the zoom being the mouse
- Convert the mouse coordinate from screen space to world space
- Change the zoom level
- Convert the mouse coordinate from screen space to world space again (since zoom is part of that equation, we get a different result)
- Move the camera's position the difference between the answer we get for 1 and 3
- When you draw something make sure to convert that object's position from world space coordinates to screen space coordinates
I think 5 is irrelevant here
and I think this was in the context of a no engine game
so is the world not moving at all?
you could, on zoom, lerp / pan the camera towards the mouse position converted to a world position
right now, it is, just the movement is really fast like i showed
this isn't
ah
this
it seems to work but its scaled weird
can you try the new code and get a video of that?
alright
definitely worth seeing how things shape up
at the very end, I was zooming in and out in alternating fashion, it just flies off
mostly I was zoom in and out alternatingly
you know I just realized that the unity preview screen is exactly what I want to do
so its a good example
so in cinemachine, you can only track gameobjects, so I made a empty object with the script
public class followMouse : MonoBehaviour
{
// Update is called once per frame
void Update()
{
if(Input.mouseScrollDelta.y != 0) {
transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
}
Just to track the mouse
if you wanna half the scale of the camera, you find the difference between the middle of the camera and the mouse position, and also half that
so theres another object adding more behaviors to the camera?
oh...
this is causing issues for debugging
id disable that, lets work on this single script for the camera that youve got and make it into a generic pan zoom script
perfect, thats what i had changed the script into
now we can focus on mouse position and all
okay so lets figure out the relative distance in WORLD units that the mouse is from the center of the camera
the black box is the camera, the triangle is the mouse
we need to know the exact length of the blue line in world units
is the center just camera pos?
yep!
alright good
so if the camera is at (-10,-10) in the world, and the mouse is at (5,5), whats the difference?
15, 15?
actually i have a better way of solving this
i made this image in paint
bottom left, this exists
huh
we can use this as a guide to make sure we use the same math that paint does, as its coordinate system works fine
pro tip. MS paint always comes to the rescue!
lol
yeah i guess, its just faster to know a rough guess
so up and right is -y and +x
the difference between those numbers is probably then as simple as subtracting one from the other
in paint or unity?
so camera position - ScreenToWorldPoint(MousePosition)
yes
both?
yup, its just a 2d coordinate at the end of the day
since when I made a game in pygame it was 0, 0 at topleft
I was used to it being at the top left, not the center
thats a world space, screen space is usually 00 at the top left
alright
world space doesnt have a "top left"
its just an infinitely big space, so it makes sense to use 00 as the middle bc you can move as far negative as you can positive, but in screen space, there are no negative pixels, make sense?
ah yes
okay so im gonna sudocode this, it might well be wrong, but its worth a try
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class zoom : MonoBehaviour
{
private Camera MyCamera;
private CinemachineBrain MyBrain;
private CinemachineVirtualCamera MyVCam;
// NEW CODE HERE:
public Vector2 MouseOffset;
float zoomValue = 10f;
void Start()
{
MyCamera = Camera.main;
MyBrain = MyCamera.GetComponent<CinemachineBrain>();
MyVCam = MyBrain.ActiveVirtualCamera as CinemachineVirtualCamera;
}
// Update is called once per frame
void Update()
{
// NEW CODE HERE:
MouseOffset = MyCamera.Transform.Position - MyCamera.ScreenToWorldPoint(Input.MousePosition);
// OLDER CODE HERE:
if (MyVCam)
{
MyVCam.m_Lens.OrthographicSize -= Input.GetAxis("Mouse ScrollWheel") * zoomValue;
print(Camera.main.ScreenToWorldPoint(Input.mousePosition));
}
}
}```
okay so ive added an offset checker, update the script to match that
in your inspector, it should show you the difference between your camera and mouse now, if it looks weird, ive got the subtraction the wrong way around
i think its correct tho
if its a metre to the top right, it should spit out a [1, -1] in the inspector, roughly
so
I started by moving the mouse slightly, then zoom in and out for a bit, then at the very end move the mouse
public Vector2 MouseOffset;
this is public so we can keep an eye on it
when you move the mouse around, a value will change over here ish
make sense?
yeah
is it working?
okay but where is the camera position
that flip at the end I believe is zooming past the thing
yeah an inversion of the camera entirely
that does seem to be working though, is the camera at 00?
try putting the camera at 00 first, so its easier to read the values
at the start its not
nor at runtime either
but, we know now that the zoom level does adjust the difference between the mouse and the camera perfectly
because the further we zoom out, the bigger the distance can be
// Update is called once per frame
void Update()
{
// NEW CODE HERE:
MouseOffset = MyCamera.Transform.Position - MyCamera.ScreenToWorldPoint(Input.MousePosition);
float _zoomAmount = Input.GetAxis("Mouse ScrollWheel") * zoomValue;
// OLDER CODE HERE:
MyVCam.m_Lens.OrthographicSize -= _zoomAmount;
MyVCam.Transform.Position += (MouseOffset * _zoomAmount);
}
lets try updating the ... update method to this
I had to fix some thing with the code (like capitalization and changing last line to vector3)
void Update()
{
// NEW CODE HERE:
MouseOffset = MyCamera.transform.position - MyCamera.ScreenToWorldPoint(Input.mousePosition);
float _zoomAmount = Input.GetAxis("Mouse ScrollWheel") * zoomValue;
// OLDER CODE HERE:
MyVCam.m_Lens.OrthographicSize -= _zoomAmount;
MyVCam.transform.position += (Vector3)(MouseOffset * _zoomAmount);
}
and lemme send the vid one sec
oh also with that code it goes wild and the last part of the video I zoomed in once
lets be explicit here, MyVCam.transform.position += new Vector3(MouseOffset.x, MouseOffset.y, 0) * _zoomAmount
looks like its going the wrong direction
yeah
change that += to a -=
after changing I zoom in and out, in and out and so on
thats looking like its working to me
should I send the project so you can test more easily?
its very fast tho
zooming once (or like one mouse wheel increment) is way too much
make ZoomValue public
then you can play with the value in the inspector while its running
youve got it set to 10f at the moment, thats the only issue
one trick i like to use is this
[Range(0f, 10f)] public float ZoomValue;
dont declare a value for it, but specify a range
in unity, a slider will appear and you can change the zoom strength with that instead if hard coded values
it still has some unexpected behaviour
I can't really explain lemme record
like here, i manage deadzones with ranges
yeah np
so, when I draw a circle with my mouse, that means im zooming out
huh
thats not a problem
void Update()
{
// NEW CODE HERE:
MouseOffset = MyCamera.transform.position - MyCamera.ScreenToWorldPoint(Input.mousePosition);
float _zoomAmount = Input.GetAxis("Mouse ScrollWheel") * zoomValue;
MyVCam.m_Lens.OrthographicSize -= _zoomAmount;
if(_zoomAmount > 0)
MyVCam.transform.position += (Vector3)(MouseOffset * _zoomAmount);
else if (_zoomAmount < 0)
MyVCam.transform.position -= (Vector3)(MouseOffset * _zoomAmount);
}
if we zoom in, add the offset distance, if we zoom out, subtract it
if this goes tits up, i probably got the + and - the wrong way around lol
I’ll take a break my back hurts
yeah np, dm me when youre back
I'm back
using this code, zoom in or out almost always moves the sprite away from the mouse. and its weird aswell
And btw this video is me zooming in and out alternatingly