如何使用数组在2D瓦片游戏中协调图形和逻辑位置?

5
我正在使用Java编写一个像炸弹人一样的2D图块游戏(我的第一个游戏)。 我使用2D数组表示地图,其中我跟踪墙壁、可走空间等。到目前为止,我已经能够使玩家平滑移动,并根据他按下的方向键交换精灵(但不与背景/地图交互,可以随意走动并走出屏幕)。
当我想要跟踪玩家在数组中的位置时,我的问题出现了。逻辑上,角色始终只属于一个图块,但在图形上可能位于两个图块之间。我该如何解决这个问题?
我已经尝试过下面的方法: currentTileArrayX = x / tileWidth; currentTileArrayY = y / tileHeight; 其中x和y是精灵左上角的坐标。但由于玩家的精灵大小与图块不同,所以一切都变得非常混乱。
我心目中已经有另一个选项可以解决上一个问题:当玩家按下方向键时,将角色移动到下一个图块,就像进行动画一样。这不会让玩家停在两个图块的中间...但如果他用另一个按键打断它怎么办?我该如何在执行动画时停止用户的操作?我认为这是最简单的解决方案,但我不知道如何实现它。
我已经尝试在其他问题中寻找解决方案,但没有成功。希望您能帮助我,非常感谢!
3个回答

2
啊!遇到了“离散空间问题” :) 你的逻辑图是离散的,但是你的UI动作是在连续空间中。我不认为用户实际上可以在两个格子中“同时”存在 - 在视觉上是可以的,但是从内部来说是不可能的。现在你正在获取玩家的位置,这可以是在当前格子内的“任何地方”,或者是在两个格子的“边界”上,就像你所说的那样...
我认为你有两种解决方法:
1.使用简单的四舍五入:如果玩家的位置小于格子边界,只需将其保留在前一个格子上。如果大于,则移到下一个格子。现在的问题是边界问题 - 你可以使用启发式方法,因为你不能相信浮点比较的准确性(即与0比较不是一件好事)。所以你可以尝试这样做:if(currentPosition - boundary <= 0.000000001) 假设它是下一个格子,否则保留在同一个格子中。
2.嗯,@Jay比我先想到了。所以第二个解决方法是实际上定义一个移动速度,并且每次“点击”/“按钮按下”移动那么多步数 - 但是你说你有“介于”按键的问题。我猜如果你的代码是这样设计的,那么这不应该是一个问题:
    update()
        {
           calculate(); //更新所有数据结构/计算
           draw(); //根据计算更新可视化表示
        }
update()也称为gameLoop。我认为这可以解决你的问题...

Nupul,我使用第一种解决方案修改了我的代码。感谢它解决了许多错误,现在几乎可以工作了。但是我还有一个问题:http://imageshack.us/f/687/bomberbug.png/ 我希望我在图片中正确地解释了它。 - Rama
在图像中,currentPosition 仍然是红色的瓷砖。由于红色瓷砖右侧是空闲的,我可以向右走,但从图形上看,我不能这样做。 - Rama
@Rama:不太清楚你的意思...如果你可以向右走,那么“为什么不呢?”其次,如果“从图形上讲”你不能这样做,那么从数据结构上来说你也不应该被允许。你的内部模型必须是你视图的准确表示。如果我在模型中不能向右走,那么我就不应该被允许在视图中这样做,而不是相反,因为视图是非常十进制导向的。如果我理解有误,请您能否再详细说明一下问题? - PhD
@Rama:我现在明白了...就在接近边界线之前向右转。但是这本来就不应该被允许!因为右侧被阻挡了!你必须每帧更新你的数据结构并重新绘制,就像上面答案中的#2一样!在移动到“屏幕”之前,请检查模型中是否有效的“屏幕外”。 - PhD

1

我曾经在AS3中基本上做了同样的事情,但是这个概念可以转移到Java。我决定创建两个主要值来帮助跟踪移动,一个包含玩家x/y值(按照图块计算),另一个是移动方向的Point。以下是一些伪代码:

if(direction.x == 0 && direction.x == 0) {
    if (up) direction.y = -1;
    else if (down) direction.y = 1;
    else if (left) direction.x = -1;
    else if (right) direction.x = 1;
} else {
    player.x += direction.x;
    player.y += direction.y;
    distance--;
    if(distance == 0) {
        direction.x = direction.y = 0;
        distance = tileWidth;
    }
}

显然,您需要调整它以适应您的需求,但这是基础知识。此外,tileWidth 可以替换为一个整数字面值,它简单地等于单个瓷砖的宽度。


1

我会尽量将逻辑部分(玩家所属的瓷砖)和可视化部分(瓷砖之间的动画)分开。我的方法是拥有一个逻辑位置(玩家所在的瓷砖)和一个移动速度(实际上意味着玩家在移动到下一个瓷砖后不能立即移动的时间)。然后,从一个瓷砖到另一个瓷砖的动画意味着您的精灵始终朝向您的瓷砖的屏幕坐标移动 - 这需要的时间可以轻松地由移动速度确定(一个完整的瓷砖移动应该与玩家在当前瓷砖上休息的时间一样长)。

唯一的特殊情况是“掉头”,在这种情况下,您将允许玩家随时返回到他来自的瓷砖,只需花费 (timeToRecoverOnTile - (timeToRecoverOnTile - timeSinceMovementStarted)) 的时间。


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