libgdx pinch to zoom

Aug. 15, 2015, 12:40 p.m. Programming libgdx

I was looking for the code for pinch to zoom on libgdx that zooms with the origin at the center of two fingers. Then I found this. Unfortunately, it seems that the solution there is far from being elegant. Then I figure out a new solution using the camera matrix myself. Here is the code:

this.gestureDetector = new GestureDetector(new GestureAdapter(){
        private Vector2 oldInitialFirstPointer=null, oldInitialSecondPointer=null;
        private float oldScale;
        @Override
        public boolean pan(float x, float y, float deltaX, float deltaY) {
            game.getCamera().update();
            game.getCamera().position.add(
                game.getCamera().unproject(new Vector3(0, 0, 0))
                .add(game.getCamera().unproject(new Vector3(deltaX, deltaY, 0)).scl(-1f))
            );
            return true;
        }
        @Override
        public boolean pinch (Vector2 initialFirstPointer, Vector2 initialSecondPointer, Vector2 firstPointer, Vector2 secondPointer){
            if(!(initialFirstPointer.equals(oldInitialFirstPointer)&&initialSecondPointer.equals(oldInitialSecondPointer))){
                oldInitialFirstPointer = initialFirstPointer.cpy();
                oldInitialSecondPointer = initialSecondPointer.cpy();
                oldScale = game.getCamera().zoom;
            }
            Vector3 center = new Vector3(
                    (firstPointer.x+initialSecondPointer.x)/2,
                    (firstPointer.y+initialSecondPointer.y)/2,
                    0
            );
            zoomCamera(center, oldScale*initialFirstPointer.dst(initialSecondPointer)/firstPointer.dst(secondPointer));
            return true;
        }
        private void zoomCamera(Vector3 origin, float scale){
            game.getCamera().update();
            Vector3 oldUnprojection = game.getCamera().unproject(origin.cpy()).cpy();
            game.getCamera().zoom = scale; //Larger value of zoom = small images, border view
            game.getCamera().zoom = Math.min(2.0f, Math.max(game.getCamera().zoom, 0.5f));
            game.getCamera().update();
            Vector3 newUnprojection = game.getCamera().unproject(origin.cpy()).cpy();
            game.getCamera().position.add(oldUnprojection.cpy().add(newUnprojection.cpy().scl(-1f)));
        }
});

The method Camera.unproject() is used to convert the coordinate of the points you touch(let's say it's coordinate A) to the coordinate that you use for displaying objects(let's say it's coordinate B). For example, if you draw a object on a SpriteBatch, and the batch has set to use a camera, then the coordinate used there is probably in coordinate B. However, another coordinate system, coordinate A is used for touch input. That's why we need to do an unprojection for the conversion between two coordinate systems. Remember to update the camera before using the unproject method. Otherwise, it may do that unprojection based on an outdated transformation matrix of the camera, which make the calculation inaccurate


Comments

A
March 1, 2016, 9:43 p.m.

Could you update this w/ some comments? I'm a little unclear on what some of this does (It seems to work, though!)

View all comments