获得附近实体的最佳方式

时间:2016-07-24 22:22:38

标签: java minecraft bukkit

我已经思考过这个问题很长一段时间了,只是想知道是否有更好的方法来获取附近的实体而不是遍历世界上的每个实体并测试它们的位置?

对于我正在开发的插件,我正在使用每个刻度线,而且根本不是高效的。

public static List<Entity> getEntitiesAroundPoint(Location location, double radius) {
    List<Entity> entities = new ArrayList<Entity>();

    for (Entity entity : location.getWorld().getEntities()) {
        if (entity.getWorld() != location.getWorld()) {
            continue;
        } else if (entity instanceof Player && ((Player) entity).getGameMode().equals(GameMode.SPECTATOR)) {
            continue; //Don't want spectators
        } else if (entity.getLocation().distanceSquared(location) <= radius * radius) {
            entities.add(entity);
        }
    }
    return entity;
}

我无权访问玩家对象,因此player.getNearbyEntities()实际上不是一个选项(我不知道这是否更好)。我确实想知道location.getChunk().getEntities()是否会更好地循环,但我又不知道背后的过程。任何人都可以与我分享一些关于什么可能是一个更好的方式去实现有效的见解?

提前致谢。

2 个答案:

答案 0 :(得分:1)

在幕后,来自Error:(9, 23) No resource found that matches the given name (at 'icon' with value '@drawable/abc_ic_menu_moreoverflow_mtrl_alpha'). 的{​​{1}}方法循环遍历所有相关的块,所以我认为这样做比循环遍历世界上的每个实体都要快。

不幸的是,getNearbyEntities()内部使用的NMS org.bukkit.entity.Entity方法(甚至是它调用的一些方法)需要getEntities作为其第一个参数。您可以编写自己的方法来获取两个参数并镜像NMS方法的行为。

我不知道我是否可以在这里发布NMS方法的确切源代码,因为Craftbukkit DMC删除和Stack Overflow规则,但我理解它的方式getNearbyEntities方法采用轴对齐边界框,在该框中找到块并返回这些块中的实体。

由于你使用的是球体而不是盒子作为边界,我最初会使用这个盒子,然后进行距离检查以确定实体是否真的在给定的球体中。

以下是一个示例:

Entity

这个方法可能比使用getEntities稍微慢一些,因为我不确定调用此处使用的Bukkit方法来检索public static List<Entity> getEntitiesAroundPoint(Location location, double radius) { List<Entity> entities = new ArrayList<Entity>(); World world = location.getWorld(); // To find chunks we use chunk coordinates (not block coordinates!) int smallX = MathHelper.floor((location.getX() - radius) / 16.0D); int bigX = MathHelper.floor((location.getX() + radius) / 16.0D); int smallZ = MathHelper.floor((location.getZ() - radius) / 16.0D); int bigZ = MathHelper.floor((location.getZ() + radius) / 16.0D); for (int x = smallX; x <= bigX; x++) { for (int z = smallZ; z <= bigZ; z++) { if (world.isChunkLoaded(x, z)) { entities.addAll(Arrays.asList(world.getChunkAt(x, z).getEntities())); // Add all entities from this chunk to the list } } } // Remove the entities that are within the box above but not actually in the sphere we defined with the radius and location // This code below could probably be replaced in Java 8 with a stream -> filter Iterator<Entity> entityIterator = entities.iterator(); // Create an iterator so we can loop through the list while removing entries while (entityIterator.hasNext()) { if (entityIterator.next().getLocation().distanceSquared(location) > radius * radius) { // If the entity is outside of the sphere... entityIterator.remove(); // Remove it } } return entities; } 和其中的实体是否与直接调用NMS一样高效getNearbyEntities方法之类的方法可以。

答案 1 :(得分:1)

getNearbyEntities方法也适用于世界对象!

public static List<Entity> getEntitiesAroundPoint(Location location, double radius) {
    return location.getWorld().getNearbyEntities(location, radius, radius, radius);
}

但请注意&#39; radius&#39;实际上是一个长方体区域,而不是球形。

如果你想要一个球形ara,你必须遍历当前世界中的块/实体并检查:

if (entityLoc.distanceSqared(radius * radius) <= radius) {