使用Libgdx实现触摸滚动

3

我正在尝试在libgdx游戏中实现触摸滚动。我有一张宽阔的图片,是一个房间的全景图。我希望能够滚动图片,让用户能够看到房间周围的景象。我已经实现了滚动一定距离的功能,但当新的touchDragged事件被注册时,图片会被移回原始位置。

这是我的实现方式:

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();

}

在InputProcessor中

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

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

我在这个问题的帮助下有所进展:LibGdx How to Scroll using OrthographicCamera?。然而,它并没有真正解决我的问题。

我认为问题出在touchDragged坐标不是世界坐标,但我已经尝试使用unprojecting相机来解决,但没有效果。

我已经苦苦挣扎了几周,真的很需要一些帮助。

提前感谢。

5个回答

7

我最近做了你想要的事情。这是我用于移动地图的Input类,你只需要将我的“stage.getCamera()”更改为你的“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;
}


    ...
}

这是结果:http://www.youtube.com/watch?feature=player_embedded&v=g1od3YLZpww

这看起来可能是答案,您能否请包含您的cameraOutOfLimit实现,因为这是我遇到问题的部分。我尝试了一个ScrollPane,它可以工作,但我无法添加一个新的Actor到场景中并使其与背景一起滚动。 - jonnypotwash
我添加了一个名为cameraOutOfLimit的函数。希望它能有所帮助。 - rjurado01
这个与 P.T. 建议的 gestureListener 结合使用效果非常好。 - jonnypotwash

1

简单回答:

声明两个字段来保存新的和旧的拖动位置:

Vector2 dragOld, dragNew;

当触摸时,你需要设置这两个值等于触摸的位置,否则你的摄像头会跳动。
if (Gdx.input.justTouched())
{
    dragNew = new Vector2(Gdx.input.getX(), Gdx.input.getY());
    dragOld = dragNew;
}

每帧更新dragNew,然后简单地将向量相减以获得用于平移相机的x和y。

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.
        }
    }

这是我用来拖动正交相机的全部内容,简单而有效。

Gdx.input.justTouched()在我的其中一台设备上无法正常工作。有任何替代方法吗? - iappmaker

1
你需要在touchDragged回调中进行更多的计算,不能仅仅将触摸屏幕坐标传递给相机。你需要弄清楚用户拖动手指的距离和方向。绝对坐标值并不立即有用。
考虑从右上角向下拖动或从左上角向下拖动。在这两种情况下,您想要(我认为)以相同的距离移动相机,但是屏幕坐标的绝对值在两种情况下会非常不同。
我认为最简单的方法就是跟踪previousXpreviousY(在touchDown方法中初始化它们)。然后在touchDragged期间使用增量(例如deltaX = screenX - previousX)调用cam.translate()。还要在touchDragged中更新previous*

或者,你可以查看一些更高级的InputProcessor包装器,这些由libgdx提供(请参见https://code.google.com/p/libgdx/wiki/InputGestureDetection)。


1

我使用了drinor的答案,但在“touchDown”函数中添加了一行代码,这样每次开始拖动时就不会重置相机:

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

0

谢谢,这看起来很有意思。我查看了ScrollPane,但放弃了,因为它会有滚动条,而这个看起来没有,可能非常完美。 - jonnypotwash
在最坏的情况下,你可以找到一些接近你想要实现的代码... - Christophe Roussy
刚刚发现了Badlogic Games的一篇博客,发布于6月底,其中指出FlickScrollPane不再使用,但ScrollPane具有其所有功能,并且滚动条可选,因此现在看起来ScrollPane是更好的选择。 - jonnypotwash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接