libGDX:如何实现平滑的基于瓦片/网格的游戏角色移动?

3

为了避免重复造轮子,我想知道:

libGDX上,如何实现一个基于网格的游戏角色平滑移动的最佳方法?该游戏是基于Tiled(2D)地图的。

只要按下箭头键(或者角色朝某个方向发生触摸事件),角色就应该在瓷砖之间平滑移动,并在松开键盘/触摸时停留在网格位置上。这种运动应该与帧率无关。

如果有一些已经实现的例子可以供学习,并指导正确使用libGDX API,那将非常感激。


我写了一篇关于平滑瓦片移动的文章,希望能对你有所帮助。https://paladin-t.github.io/articles/smooth-tile-based-movement-algorithm-with-sliding.html - pipipi
2个回答

6
测试特定按钮是否被按下(或屏幕触摸),如果是,则在一个字段中设置正确的目标图块(玩家将要去的图块),并开始移动到那里。这个移动只有当玩家进入下一个图块时才会结束。当发生这种情况时,再次检查输入以继续移动(即重复)。
假设你的图块宽度/高度为1,并且你想每秒移动1个图块。您的用户按下右箭头键。然后,您只需将目标图块设置为玩家右侧的图块即可。
if(targettile!=null){
    yourobject.position.x += 1*delta;
    if(yourobject.position.x>=targettile.position.x){
        yourobject.position.x = targettile.position.x;
        targettile = null;
    }
}

这段代码仅简化了向右移动,您还需要将其扩展到其他方向。
如果玩家没有移动,请别忘了再次轮询输入。
编辑:
按键的输入轮询:
if (Gdx.input.isKeyPressed(Keys.DPAD_RIGHT)){

输入轮询触摸(cam 为您的相机,touchPoint 是用于存储未投影的触摸坐标的 Vector3,而 moveRightBounds 是 (libgdx) 矩形):

if (Gdx.input.isTouched()){
    cam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
    //check if the touch is on the moveright area, for example:
    if(moveRightBounds.contains(touchPoint.x, touchPoint.y)){
        // if its not moving already, set the right targettile here
    }
}

正如noone所说,你可以在render方法中将delta作为参数传入,或者在任何其他地方使用以下方法获取:

Gdx.graphics.getDeltatime();

参考资料:


谢谢你的帮助。你能否详细解释一下从哪里调用代码以及如何进行输入轮询?此外,我不确定如何根据变化的帧率计算“delta”。 - Jens Piegsa
1
@JensPiegsa 在你的render()方法中,你可以通过LibGDX获取delta参数。否则,你可以通过Gdx.graphics.getDeltaTime()获取它。 - noone
1
修改了我的回答 :) 你可以在渲染方法中调用它(每一帧)。 - Daahrien
再次感谢您提供的关键提示,这些提示实际上帮助我找到了可行的解决方案。 - Jens Piegsa

2

这只是针对一维的情况,但我希望你能理解这个思路。通过检查方向键并加/减1,然后将其转换为int(或floor)将给出下一个瓷砖。如果你松开键盘,你仍然有一个未到达的目标,实体将继续移动,直到它到达目标瓷砖。我认为它看起来应该像这样:

void update()(
    // Getting the target tile
    if ( rightArrowPressed ) {
        targetX = (int)(currentX + 1); // Casting to an int to keep 
                                       // the target to next tile
    }else if ( leftArrowPressed ){
        targetX = (int)(currentX - 1);
    }

    // Updating the moving entity
    if ( currentX < targetX ){
        currentX += 0.1f;
    }else if ( currentX > targetX ){
        currentX -= 0.1f;
    }
}

这正是我几个小时前回答的内容...而且这里使用了固定步长,而不是利用帧之间经过的时间来实现帧无关的移动。 - Daahrien
1
抱歉,当我回复时,我无法看到您的答案。 - Per-Erik Bergman

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