Java 基于x/y坐标高效查找阵列元素

Java 基于x/y坐标高效查找阵列元素,java,Java,我编写了一个java自上而下的2d游戏,它使用生成的贴图块绘制地图。每个磁贴由包含其x/y坐标的磁贴类描述 我需要能够得到一个玩家在地图上移动时“在”的地砖。player类知道其当前的x/y,Tile类知道其被分配到的x/y 当前,所有需要渲染的分幅都存储在分幅[]【】中。我对java还相当陌生,但简单地使用数组索引所需的x/y坐标似乎不是一个好主意(如果可能的话)——主要是因为我当前渲染的分片可能并不总是从0,0开始。假设玩家在10001000时加载已保存的游戏-我当然不会在不需要时从0,0加

我编写了一个java自上而下的2d游戏,它使用生成的贴图块绘制地图。每个磁贴由包含其x/y坐标的磁贴类描述

我需要能够得到一个玩家在地图上移动时“在”的地砖。player类知道其当前的x/y,Tile类知道其被分配到的x/y

当前,所有需要渲染的分幅都存储在
分幅[]【】
中。我对java还相当陌生,但简单地使用数组索引所需的x/y坐标似乎不是一个好主意(如果可能的话)——主要是因为我当前渲染的分片可能并不总是从
0,0
开始。假设玩家在
10001000
时加载已保存的游戏-我当然不会在不需要时从
0,0
加载互动程序

那么,我存储这些坐标的最佳方式是什么

在PHP中可以这样做,因为我知道数组不关心从0开始的索引:

$tiles[1000][1000]=新的Tile()


但我不确定Java中推荐的方法是什么。必须遍历每个磁贴并检查x/y是否匹配,这感觉非常低效。

您可以使用
映射来保存数据,并作为
协调对象的键。
坐标
对象应实现
等于
哈希代码
。这应该很快很简单

将项目添加到地图中:

map.put(new Coordinate(1000,1000), new Title(...));
您可以通过执行以下操作来恢复它:

Title title = map.get(new Coordinate(1000,1000));

另一种选择是使用字典来存储瓷砖。这不一定是最有效的,但它会起作用:

java.awt.Point p = new java.awt.Point(1000,1000);
Tile t = // however you get your tiles
java.util.Dictionary<java.awt.Point, Tiles> theDictionary = new java.util.Dictionary<>();
theDictionary.put(p, t);
java.awt.Point p=new java.awt.Point(10001000);
Tile t=//但是你得到了你的Tile
java.util.Dictionary theDictionary=new java.util.Dictionary();
离散的put(p,t);

老实说,你问的是一个相当高级的话题。这种涉及如此大的地图的项目真的不能用一个简单的数组来完成。有些人会建议使用简单的偏移量和动态数组,但这是非常低效的

不过,我可以给你一个建议。您可以分块加载瓷砖。比如说,每个区块是一个32乘32的2D数组。您可以加载当前区块和周围区块,而不是一般加载围绕玩家位置的区块。例如,假设位置1000,1000落在块C中,然后加载块C和所有周围的块。当您从块C移动到块D时,您卸载了围绕C的块,而加载了围绕块D的块

块类可能如下所示:

class Chunk {
    private Tile tiles[32][32];
    private Coordinate origin; // (0, 0) on this chunk's array is actually equal to origin on the map
    // Example: if the chunk started at (128, 128), then origin would be (128,128)
    ...
    public static Chunk loadChunk(...) { ... }
    ...
}
您需要Map类来帮助定位和加载块:

class Map {
    public Chunk currentChunk;
    public ArrayList<Chunk> loadedChunks;
    ...
    public ArrayList<Chunk> getSurroundingChunks( Chunk ch ) {...}
    ...
}
类映射{
公共语块;
公共ArrayList加载的块;
...
公共数组列表getSurroundingChunks(Chunk ch){…}
...
}
按块加载是几乎所有具有大型地图的游戏都采用的方式(minecraft是一个显著的例子,尽管该游戏的编程一般都非常糟糕)

当然,它在算法上很复杂,你需要进一步研究它,而不仅仅是阅读这篇文章。但它应该为您提供一个健壮的系统,该系统适用于任何大小的地图,并且已被证明在现实世界中有效

该系统的一个弱点是,由于垃圾收集,在java中卸载很难预测。然而,我不知道有一个健壮的加载系统至少不会受到Java垃圾收集器的轻微影响


这种类型的技术也称为延迟加载。这意味着你只需要把你真正需要的东西加载到内存中。这是加载大量可预测数据的最佳技术,因为它允许您最小化加载时间和内存消耗。基于块的加载不是唯一一种延迟加载,但我甚至可以说它可能是最好的一种。

通用高效实现:这是我总体的方向-它进展缓慢,但我自己编写整个系统,因为没有更好的方法来理解如何做这一切。)整个地图现在是按程序生成的,当我努力更好地将所有地形逻辑与游戏逻辑连接起来时,我需要更有效的方式来加载内容、保存等。将其拆分成块可以让唤醒理解我朋友的感受。一开始似乎有点吓人,不是吗?我相信你最终会得到它,它只需要一段时间,是一个学习的经验。祝你的项目好运。现在转换成基于块的系统可能比以后更值得——我已经构建并重建了地形代码,使用世界坐标,使用噪音系统制作高度地图,但我仍然有一个潜在问题(我知道我必须处理),目前,我从未“卸载”不在可视区域内的东西,这将使正确地进行操作变得更容易。但是,我仍然需要一种方法来轻松查找磁贴,因此我需要知道要查找的块,以及块中的哪个磁贴坐标,等等。如果我可以轻松确定哪个块包含当前磁贴,那么通过坐标拖动磁贴的效率就不成问题了-然后我可以使用偏移或迭代,或者使用一些其他解决方案-在16x16的瓷砖阵列上执行此类操作比在整个可视区域(如60x60左右)上更好。我只想在Map类中保留一个加载块的arraylist。另外,我会让Chunk类在其中存储一个偏移量。我还将保留对当前块的单独引用。我会用这个信息更新我的答案老实说,这不会很好地处理大型地图。您仍然会在内存中存储每个访问的磁贴,这是非常低效的。因为坐标本质上是数字的,所以它可能不会节省任何时间