- Introduction
- Configuration
- Compatibility
- Functioning
- Mouse inputs support
- Move the camera while zooming
- Zoom at a specific point
- Stop moving on camera's limit
- Fling animation
- Known issues
- Contributing
The necessity of a camera with touch inputs support bring me to search the web for a solution, without much success.
Some implementations that I found look promising, but I always came across some behavior that just don't work the way I expected, like the impossibility of move the camera while zooming, or even the zoom itself, amplifying the center of the screen when I was focused in something that simply disappear, forcing me to move the camera on every zoom ajustement.
It lead me to implement a solution that fit my needs in any scenario used. So here it is.
Put the TouchCamera2D.gd script somewhere on your project and make sure
the class icon path points to the correct svg file (touch_camera_icon.svg)
or simply delete everything after class_name TouchCamera2D
.
If everything is done right you should be able to add the camera as a node on your scene tree.
Set the parameters you need and make sure to mark the camera as the current
one (it can also be set via script by calling camera_reference.make_current()
).
Done, it should be ready.
Tested using the Godot versions 3.2+
The camera captures and interprets the unhandled inputs, so make sure the inputs
reaches the camera's _unhandled_input(event: InputEvent)
method. If needed you
can call it directly by script, like this camera_reference._unhandled_input(event)
.
The camera supports touch and drag (or click and drag) to move the camera's position,
two fingers pinch to zoom in/out (or mouse wheel) and fling animation to
fast move the camera.
The camera can handle the mouse inputs right out of the box without the need of emulating touch from mouse. If needed, you can ignore the mouse inputs by unmarking the Handle Mouse Inputs on the Inspector panel.
The mouse inputs supported are left click and drag to pan the camera, and the mouse wheel up/down to zoom in and out.
By default, the camera move while you applying zoom, so you don't have to remove a finger to move the camera if needed.
It can be turned off on the Inspector panel by disabling Move While Zooming.
When applying zoom, is expected that the point you're focused in always stays on screen. The camera will do that if the Zoom At Point is set true on the Inspector panel. Otherwise the camera will zoom in/out relative to the camera's position.
If you change the value of the camera's limits, by default, the script will stop moving the camera's position to prevent pan issues. But if you desire a more smooth action, the script can allow the user to move the camera beyond the limit. After the move action be released the camera will move itself to the limit smoothly.
A fling animation occurs when the user make a fast swipe motion releasing the finger of the screen immediately after the action. It causes the camera to move with an initial velocity and gradually slows down until it stops.
In the properties panel you can turn off the fling animation or adjust the deceleration rate of the camera, as well as the minimum velocity to be considerate to perform a fling motion.
As said above, the camera catches the unhandled inputs to work. But what if this events never reaches the camera? Well, the camera will not do anything.
A good example of this is Nodes that inherits Control
. The Control
nodes always handle the inputs that occur inside them, even when your
code don't do anything with it. In this cases you can call the camera's
_unhandled_input(event: InputEvent)
method directly passing the event
to it.
The problem with that is the fact that control nodes events have their
position relative to the node itself. So if you touch in the middle of
a 20x20 node, the event.position
will be (10, 10)
, independely of the
viewport size.
For moving the camera it don't represents a lot of trouble, but for zoom at a specific point the camera need the position relative to the viewport. Otherwise the camera will go crazy, e.g. positioning itself at 10, 10 while you are focusing an object at 1000, 1000.
A work around, is to manipulate the event's position before calling the camera's method, adding the node's position to the event's position. But you'll have to test it well to see if it behaves properly.
If you need to emulate touch from mouse and the Handle Mouse Events are set true, it causes an issue while moving the camera.
The engine will trigger the camera's _unhandled_input(event: InputEvent)
twice, one for the mouse and one for the emulated touch. For zoom action
it's not a big of a deal, since this action is handled independently for the
mouse and touch. But when moving the camera it causes the drag to double, e.g
clicking and dragging the mouse 10 pixels, will move the camera 20.
So, if you really need to emulate the touch, you'll need to ajust the script. Just delete everything related to the mouse inputs from the code. Again, the zoom action is not affected for the emulated touch. So you can leave it there if you want.
Feel free to suggest any improvements for the script or for this README translation.