jonnypotwash
jonnypotwash

Reputation: 43

touch scrolling with libgdx

I'm trying to implement touch scrolling in a libgdx game. I have a wide image that is a panorama of a room. I want to be able to scroll the image so the user can see around the room. I have it so that I can scroll a certain distance but when a new touchDragged event is registered the image is moved back to the original position.

This is how I'm implementing it

public class AttackGame implements ApplicationListener {

AttackInputProcessor inputProcessor;
Texture backgroundTexture; 
TextureRegion region;
OrthographicCamera cam;
SpriteBatch batch;
float width;
float height;
float posX;
float posY;

@Override
public void create() {
    posX = 0;
    posY = 0;
    width = Gdx.graphics.getWidth();
    height = Gdx.graphics.getHeight();  
    backgroundTexture = new Texture("data/pancellar.jpg");
    region = new TextureRegion(backgroundTexture, 0, 0, width, height);
    batch = new SpriteBatch();

}

@Override
public void resize(int width, int height) {
    cam = new OrthographicCamera();
    cam.setToOrtho(false, width, height);
    cam.translate(width / 2, height / 2, 0);
    inputProcessor = new AttackInputProcessor(width, height, cam);
    Gdx.input.setInputProcessor(inputProcessor);

}

@Override
public void render() {

    Gdx.gl.glClearColor(0,0,0,1);
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);    
    batch.setProjectionMatrix(cam.combined);
    batch.begin();
    batch.draw(backgroundTexture, 0, 0, 2400, 460);
    batch.end();

}

@Override
public void pause() {
    // TODO Auto-generated method stub

}

@Override
public void resume() {
    // TODO Auto-generated method stub

}

@Override
public void dispose() {
    backgroundTexture.dispose();

}

}

And in the InputProcessor

@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {

    cam.position.set(screenX, posY / 2, 0);
    cam.update();
    return false;
}

I got this far with help from this question LibGdx How to Scroll using OrthographicCamera?. However it doesn't really solve my problem.

I think the problem is with the touchDragged corodinates not being world coordinates but I have tried unprojecting the camera with no effect.

I have been struggling with this for a few weeks and I would really appreciate some help on this.

Thanks in advance.

Upvotes: 3

Views: 8935

Answers (5)

Daniel Roca Lopez
Daniel Roca Lopez

Reputation: 574

Used drinor's answer but added the line on "touchDown) function so it doesn't reset the camera every time you start dragging again:

@Override
        public boolean touchDown(int screenX, int screenY, int pointer, int button) {
            last_touch_down.set( screenX, screenY, 0);
            return false;
        }

Upvotes: 1

Madmenyo
Madmenyo

Reputation: 8584

Simple answer:

Declare 2 fields to hold the new and old drag location:

Vector2 dragOld, dragNew;

When just touched you set both of these equal to the touched location or your cam will jump.

if (Gdx.input.justTouched())
{
    dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
    dragOld = dragNew;
}

Update dragNew each frame and simply subtract the vectors from each other to get the x and y for translating the camera.

if (Gdx.input.isTouched())
    {
        dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
        if (!dragNew.equals(dragOld))
        {
            cam.translate(dragOld.x - dragNew.x, dragNew.y - dragOld.y); //Translate by subtracting the vectors
            cam.update();
            dragOld = dragNew; //Drag old becomes drag new.
        }
    }

This is all I use to drag my ortho cam around, simple and effective.

Upvotes: 1

rjurado01
rjurado01

Reputation: 5535

I recently did something as what you want. This is my Input class that I use for move the map, you only need to change my 'stage.getCamera()' for your 'cam':

public class MapInputProcessor implements InputProcessor {
    Vector3 last_touch_down = new Vector3();

    ...

    public boolean touchDragged(int x, int y, int pointer) {
        moveCamera( x, y );     
        return false;
    }

    private void moveCamera( int touch_x, int touch_y ) {
        Vector3 new_position = getNewCameraPosition( touch_x, touch_y );

        if( !cameraOutOfLimit( new_position ) )
            stage.getCamera().translate( new_position.sub( stage.getCamera().position ) );

        last_touch_down.set( touch_x, touch_y, 0);
    }

    private Vector3 getNewCameraPosition( int x, int y ) {
        Vector3 new_position = last_touch_down;
        new_position.sub(x, y, 0);
        new_position.y = -new_position.y;
        new_position.add( stage.getCamera().position );

        return new_position;
    }

    private boolean cameraOutOfLimit( Vector3 position ) {
        int x_left_limit = WINDOW_WIDHT / 2;
        int x_right_limit = terrain.getWidth() - WINDOW_WIDTH / 2;
        int y_bottom_limit = WINDOW_HEIGHT / 2;
        int y_top_limit = terrain.getHeight() - WINDOW_HEIGHT / 2;

        if( position.x < x_left_limit || position.x > x_right_limit )
            return true;
        else if( position.y < y_bottom_limit || position.y > y_top_limit )
            return true;
        else
          return false;
}


    ...
}

This is the result: http://www.youtube.com/watch?feature=player_embedded&v=g1od3YLZpww

Upvotes: 7

P.T.
P.T.

Reputation: 25177

You need to do a lot more computation in the touchDragged callback, you can't just pass whatever screen coordinates were touched on to the camera. You need to figure out how far the user has dragged their finger, and in what direction. The absolute coordinates are not immediately useful.

Consider dragging down from the top-right or dragging down from the top-left. In both cases you want (I presume) to move the camera the same distance, but the absolute values of the screen coordinates will be very different in the two cases.

I think the simplest thing is to just track previousX and previousY (initialize them in the touchDown method. Then invoke cam.translate() with the delta (deltaX = screenX - previousX, for example), during touchDragged. And also update the previous* in touchDragged.

Alternatively, you can look at some of the fancier InputProcessor wrappers libgdx provides (see https://code.google.com/p/libgdx/wiki/InputGestureDetection).

Upvotes: 1

Christophe Roussy
Christophe Roussy

Reputation: 16999

I have not used it myself, but I would start by looking at the code of:

Have you looked at the code of http://libgdx.l33tlabs.org/docs/api/com/badlogic/gdx/scenes/scene2d/ui/FlickScrollPane.html

See: touchDragged

Upvotes: 0

Related Questions