获取附近实体的最佳方式
Best way to get nearby entities
这个问题我思考了很久,只是想知道是否真的有更好的方法来获取附近的实体而不是遍历世界上的每个实体并测试它们的位置?
对于我正在开发的插件,我每时每刻都在使用它,而且它根本没有效率。
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()
是否会更好地循环,但同样,我不知道这背后的过程。任何人都可以与我分享一些关于什么可能是更好的方法有效的见解?
提前致谢。
在幕后,org.bukkit.entity.Entity
中的 getNearbyEntities()
方法循环遍历所有相关块,所以我认为这样做比遍历世界上的每个实体更快。
不幸的是,getNearbyEntities
内部使用的 NMS getEntities
方法(甚至它调用的一些方法)需要一个 Entity
作为它的第一个参数。您可以编写自己的方法来获取您的两个参数并反映 NMS 方法的行为。
由于 Craftbukkit DMC 下架和 Stack Overflow 规则,我不知道我是否可以 post 此处 NMS 方法的确切源代码,但我的理解方式 getEntities
方法采用轴对齐的边界框,找到该框内的块和 returns 这些块中的实体。
由于您使用的是球体而不是长方体作为周长,我最初会使用长方体然后进行距离检查以查看实体是否真的在给定的球体中。
下面是一个示例:
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;
}
此方法可能仍比使用 getNearbyEntities
稍慢,因为我不确定调用此处使用的 Bukkit 方法来检索 Chunk
和其中的实体是否与直接调用一样有效NMS 方法类似于 getNearbyEntities
方法。
getNearbyEntities 方法也可用于世界对象!
public static List<Entity> getEntitiesAroundPoint(Location location, double radius) {
return location.getWorld().getNearbyEntities(location, radius, radius, radius);
}
但要注意'radius'实际上是长方体面积,不是球面
如果你想要球形ara,你必须循环当前世界的chunks/entities并检查:
if (entityLoc.distanceSqared(radius * radius) <= radius) {
这个问题我思考了很久,只是想知道是否真的有更好的方法来获取附近的实体而不是遍历世界上的每个实体并测试它们的位置?
对于我正在开发的插件,我每时每刻都在使用它,而且它根本没有效率。
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()
是否会更好地循环,但同样,我不知道这背后的过程。任何人都可以与我分享一些关于什么可能是更好的方法有效的见解?
提前致谢。
在幕后,org.bukkit.entity.Entity
中的 getNearbyEntities()
方法循环遍历所有相关块,所以我认为这样做比遍历世界上的每个实体更快。
不幸的是,getNearbyEntities
内部使用的 NMS getEntities
方法(甚至它调用的一些方法)需要一个 Entity
作为它的第一个参数。您可以编写自己的方法来获取您的两个参数并反映 NMS 方法的行为。
由于 Craftbukkit DMC 下架和 Stack Overflow 规则,我不知道我是否可以 post 此处 NMS 方法的确切源代码,但我的理解方式 getEntities
方法采用轴对齐的边界框,找到该框内的块和 returns 这些块中的实体。
由于您使用的是球体而不是长方体作为周长,我最初会使用长方体然后进行距离检查以查看实体是否真的在给定的球体中。
下面是一个示例:
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;
}
此方法可能仍比使用 getNearbyEntities
稍慢,因为我不确定调用此处使用的 Bukkit 方法来检索 Chunk
和其中的实体是否与直接调用一样有效NMS 方法类似于 getNearbyEntities
方法。
getNearbyEntities 方法也可用于世界对象!
public static List<Entity> getEntitiesAroundPoint(Location location, double radius) {
return location.getWorld().getNearbyEntities(location, radius, radius, radius);
}
但要注意'radius'实际上是长方体面积,不是球面
如果你想要球形ara,你必须循环当前世界的chunks/entities并检查:
if (entityLoc.distanceSqared(radius * radius) <= radius) {