Skip to content

A simple implementation of Godot's Camera2D uptimized for touch inputs

License

Notifications You must be signed in to change notification settings

williambcosta/godot-touch-camera-2d

Repository files navigation

Table of Contents

Introduction

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.

⬆ back to top

Configuration

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.

Icon Path

If everything is done right you should be able to add the camera as a node on your scene tree.

Add camera

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.

Parameters

⬆ back to top

Compatibility

Tested using the Godot versions 3.2+

⬆ back to top

Functioning

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.

⬆ back to top

Mouse inputs support

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.

Mouse settings

The mouse inputs supported are left click and drag to pan the camera, and the mouse wheel up/down to zoom in and out.

⬆ back to top

Move the camera while zooming

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.

Move camera while zooming

⬆ back to top

Zoom at a specific point

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.

Zoom at a specific point

⬆ back to top

Stop moving on camera's limit

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.

Stop moving on camera's limit

⬆ back to top

Fling animation

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.

Fling action

⬆ back to top

Known issues

Control Nodes

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.

⬆ back to top

Emulating touch from mouse

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.

Contributing

Feel free to suggest any improvements for the script or for this README translation.

⬆ back to top