6

I have a player and of course able to grab the direction the player is facing in vector form.

Using this vector, I need to calculate if the player is looking at an entity within x blocks and if a 'spell' would hit it. I would also need to take in account if there is anything in front of the entity.

So far my thought process has been to first, get a list of all entities in x blocks of the player. But from there, I have no clue.

Any help leading me in the right direction would be awesome.

Unihedron
  • 10,902
  • 13
  • 62
  • 72
SexyToad
  • 113
  • 1
  • 6
  • [this might help](http://www.minecraftforum.net/forums/mapping-and-modding/minecraft-mods/modification-development/1435155-if-the-player-is-looking-at-an-entity-do-something) – Vicente Bermúdez Jul 07 '15 at 03:07
  • Thanks for the reply, however that seems to be for client modding of Minecraft and not bukkit plugins. – SexyToad Jul 07 '15 at 03:36

2 Answers2

5

I edited your code to be more precise and less complicated, it doesn't go through blocks. But your method is fine to :D

public static Entity getNearestEntityInSight(Player player, int range) {
    ArrayList<Entity> entities = (ArrayList<Entity>) player.getNearbyEntities(range, range, range);
    ArrayList<Block> sightBlock = (ArrayList<Block>) player.getLineOfSight( (Set<Material>) null, range);
    ArrayList<Location> sight = new ArrayList<Location>();
    for (int i = 0;i<sightBlock.size();i++)
        sight.add(sightBlock.get(i).getLocation());
    for (int i = 0;i<sight.size();i++) {
        for (int k = 0;k<entities.size();k++) {
            if (Math.abs(entities.get(k).getLocation().getX()-sight.get(i).getX())<1.3) {
                if (Math.abs(entities.get(k).getLocation().getY()-sight.get(i).getY())<1.5) {
                    if (Math.abs(entities.get(k).getLocation().getZ()-sight.get(i).getZ())<1.3) {
                        return entities.get(k);
                    }
                }
            }
        }
    }
    return null; //Return null/nothing if no entity was found
}
PhantomUnicorns
  • 101
  • 1
  • 2
2

Your thought process of getting all the entities within a certain range of the player is a good start in my opinion! Below is an example of a method that uses the blocks in a player's line of sight (raytrace) to find the nearest entity that isn't obstructed.

public static Entity getNearestEntityInSight(Player player, int range) {
    List<Entity> entities = player.getNearbyEntities(range, range, range); //Get the entities within range
    Iterator<Entity> iterator = entities.iterator(); //Create an iterator
    while (iterator.hasNext()) {
        Entity next = iterator.next(); //Get the next entity in the iterator
        if (!(next instanceof LivingEntity) || next == player) { //If the entity is not a living entity or the player itself, remove it from the list
            iterator.remove();
        }
    }
    List<Block> sight = player.getLineOfSight((Set) null, range); //Get the blocks in the player's line of sight (the Set is null to not ignore any blocks)
    for (Block block : sight) { //For each block in the list
        if (block.getType() != Material.AIR) { //If the block is not air -> obstruction reached, exit loop/seach
            break;
        }
        Location low = block.getLocation(); //Lower corner of the block
        Location high = low.clone().add(1, 1, 1); //Higher corner of the block
        AxisAlignedBB blockBoundingBox = AxisAlignedBB.a(low.getX(), low.getY(), low.getZ(), high.getX(), high.getY(), high.getZ()); //The bounding or collision box of the block
        for (Entity entity : entities) { //For every living entity in the player's range
            //If the entity is truly close enough and the bounding box of the block (1x1x1 box) intersects with the entity's bounding box, return it
            if (entity.getLocation().distance(player.getEyeLocation()) <= range && ((CraftEntity) entity).getHandle().getBoundingBox().b(blockBoundingBox)) {
                return entity;
            }
        }
    }
    return null; //Return null/nothing if no entity was found
}

Note: There are a few things/potential bugs to consider when using the method above:

  1. The way the check whether the block's bounding box intersects with the entity's bounding box works means that the player might not actually be looking directly at the entity but only at part of the block. This proximity check can be done in a variety of different ways (for example: Checking whether the entity location is near the block's location) but most are not necessarily more precise. To get a more accurate result you'd need to make your own ray trace that scans smaller distances to make sure it doesn't "miss" any entities and to check whether the player is truly looking directly at the entity. The more precise you want it to be the more resources/time it will take. Check to see if this method is precise enough for you.
  2. The loop that looks through the nearby entities chooses the first one it finds that meets the criteria, meaning that if two or three entities are bunched up and close together, it might not choose the "true" closest one (this could be fixed with more checks though and might not be that important).
  3. The check whether an entity is obstructed only looks for blocks that are not air and therefore doesn't consider transparent blocks or blocks with small collision boxes (e.g. Looking through some stairs might return null even though you might technically be able to see the entity). Once again, this doesn't make a big difference usually and I think correcting it is rather tricky.
Adrian Sohn
  • 1,271
  • 8
  • 10
  • Thank you! I'll definitely be sure to look back on this code went attempting to try this myself. I'll keep those concerns in mind, I'll need this pretty accurate as this will be for a combat system. But I'll play with the code and check out the results – SexyToad Jul 09 '15 at 07:46