How to get the closest player another player is directly looking at?

Discussion in 'Plugin Development' started by Janmm14, Nov 5, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    Janmm14

    Well my question is in the title. The range is 10 blocks.

    I think you have to do some math with vectors, range checking, getting players of the current world. Just some notes. Please help me!
     
  2. Offline

    The_Doctor_123

    Actually, Bukkit kindly created a method just for this kind of thing. In Player, there is a method called "getLineOfSight" and it returns a List of Blocks that the player is looking at, in order from closest to furthest. You can then iterate through the List until the Block is 1 meter(or whatever distance you'd like) from any Player.
     
  3. Offline

    blablubbabc

    Get all the players in a cerain radius and then calculate the angle or dot product to each of them to get the nearest player the player is looking at.

    I can give you the code for that when i am at home.

    Edit: Okay, here you go:

    Code:
    private Player getTarget(Player from) {
            assert from != null;
            // SOME FIXED VALUES (maybe define them globally somewhere):
            // the radius^2:
            double radius2 = 10.0D * 10.0D;
            // the min. dot product (defines the min. angle to the target player)
            // higher value means lower angle means that the player is looking "more directly" at the target):
            // do some experiments, which angle / dotProduct value fits best for your case
            double minDot = 0.98D;
         
            String fromName = from.getName();
            Location fromLocation = from.getEyeLocation();
            String fromWorldName = fromLocation.getWorld().getName();
            Vector fromDirection = fromLocation.getDirection().normalize();
            Vector fromVectorPos = fromLocation.toVector();
     
            Player target = null;
            double minDistance2 = Double.MAX_VALUE;
            for (Player somePlayer : Bukkit.getServer().getOnlinePlayers()) {
                if (somePlayer.getName().equals(fromName)) continue;
                Location newTargetLocation = somePlayer.getEyeLocation();
                // check the world:
                if (!newTargetLocation.getWorld().getName().equals(fromWorldName)) continue;
                // check distance:
                double newTargetDistance2 = newTargetLocation.distanceSquared(fromLocation);
                if (newTargetDistance2 > radius2) continue;
                // check angle to target:
                Vector toTarget = newTargetLocation.toVector().subtract(fromVectorPos).normalize();
                // check the dotProduct instead of the angle, because it's faster:
                double dotProduct = toTarget.dot(fromDirection);
                if (dotProduct > minDot && from.hasLineOfSight(somePlayer) && (target == null || newTargetDistance2 < minDistance2)) {
                    target = somePlayer;
                    minDistance2 = newTargetDistance2;
                }
            }
     
            // can return null, if no player was found, which meets the conditions:
            return target;
        }
    
    Edit2: Changed it to prioritize a smaller distance rather than a smaller angle for multiple potential targets.

    Edit3: Fixed, to only check players in the same world.
     
    Janmm14 likes this.
  4. Offline

    Janmm14

Thread Status:
Not open for further replies.

Share This Page