Check if player is aiming at entity

Discussion in 'Plugin Development' started by CaptainUniverse, May 26, 2016.

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

    CaptainUniverse

    Before I say anything I know a lot of people have posted this thread before, but this time it is different. I'm trying to see if the entity is EXACTLY on the players cross hair, as if this was a sniper plugin. Is there any way I can do this?
     
  2. Offline

    Zombie_Striker

    @CaptainUniverse
    1. Get the direction the player is looking by using Player#getLocation().getDirection();
    2. Create one for loop that will be the X direction. Start at the player's X, always loop (meaning the second part should be "true"), and increment is by the Direction.getX();. Note that the X needs to be a double
    3. Create another for loop that will be the Y direction. Start at the player's Y, always loop (meaning the second part should be "true"), and increment is by the Direction.getY();. Note that the Yalso needs to be a double
    4. Create another for loop that will be the Z direction. Start at the player's Z, always loop (meaning the second part should be "true"), and increment is by the Direction.getZ();. Note that the Z also needs to be a double
    5. For each X, Y, and Z coordinant, loop through all the players online and test if their location is close to that value. I would recommend using the statement "Player'sLocation#distance(new Location(The World, X, Y, Z)) <= 1" to test if the player is close to that area.
    6. If that if statement is true, do whatever you want and then break out of all the for loops.
     
  3. Offline

    CaptainUniverse

    @Zombie_Striker what do you mean by "always loop" I'm a bit confused here
     
  4. Offline

    Zombie_Striker

    @CaptainUniverse
    There are three parts to a for loop, the inititialization of a variable, a boolean determining if it should loop again, and what it should do each loop. Here's what it looks like:
    Code:
    for (Initialization ; boolean ; what it should do) {
    What you want is for that boolean to true, meaning it will always loop until you use the "break" syntax.

    [Edit] You should instead have the boolean test as long as the distance from the player is less than a certain amount (e.g. 200 blocks away.) What I suggested before would crash the server if the player does not have another player on his cross hair.
     
  5. Offline

    CaptainUniverse

    @Zombie_Striker im still a bit confused on what exactly i should do sorry a bit new to java :D
    :D
     
  6. Offline

    CaptainUniverse

  7. Offline

    Betagear

    Try using LivingEntity.hasLineOfSight(Entity other). It may work just fine.
     
  8. Offline

    I Al Istannen

    @Betagear
    I think like of sight checks if the entity could be able to see another entity. So, if you are in a fully closed empty box of stone, you won't have line of sight to an entity outside it. But you would have line of sight to every entity inside the box (as it is empty), no matter if you look at it.

    EDIT: Apparently this is canSee
     
    Last edited: May 29, 2016
  9. Offline

    Betagear

  10. Offline

    I Al Istannen

    @Betagear
    Okay. Thanks for pointing it out.
     
  11. Offline

    CaptainUniverse

    @Betagear I tried that but it returns true even if the player doesn't have their crosshair on the entity just if it is close to it
     
  12. Offline

    Betagear

    @CaptainUniverse Then you'll have to do some maths :
    - Get the target's location, substract the player's location to it, then transfer that location into spherical coordinates.
    - Using the player's pitch and yaw, you can determine if the player is looking directly onto his target, with a treshhold of course, depending on the distance. The degrees treshold will have to be between 0 and 180, where 0 is when the target is at an infinite distance, and 180 when the target is at a 0 distance.
     
  13. Offline

    CaptainUniverse

    @Betagear can I please see some code I'm not entirely sure how to do that
     
  14. Offline

    Betagear

    Here is for the spherical coordinates :
    Code:
    public class SphericalLocation {
        public double Rho=0;
        public double Theta=0;
        public double Phi=0;
       
        public SphericalLocation(){
           
        }
        public SphericalLocation(float Rho, float Theta, float Phi){
            this.Rho = Rho;
            this.Theta = Theta;
            this.Phi = Phi;
        }
       
        public void FromCartesian(Location loc){
            double x = loc.getX();
            double y = loc.getY();
            double z = loc.getZ();
            Rho = Math.sqrt(x*x + y*y + z*z);
            Theta = Math.atan(z/x);
            Phi = Math.acos(y/Rho);
            if (x < 0) {
                Theta += Math.toRadians(180);
            }
           
        }
       
        public Vector ToCartesian(){
            double x = Rho * Math.sin(Phi) * Math.cos(Theta);
            double y = Rho * Math.cos(Phi);
            double z = Rho * Math.sin(Phi) * Math.sin(Theta);
            return new Vector(x, y, z);
        }
       
        public String toString(){
            return "Rho : " + Rho + " | Theta : " + Theta + " | Phi : " + Phi;
        }
    }
    And then, you can tune it to follow the yaw and pitch of the player.getLocation (using the same base rotation)
     
  15. Offline

    CaptainUniverse

    @Betagear I'm still a bit confused on what I have to do I determine if he is aiming?
     
  16. Offline

    Betagear

    @CaptainUniverse I'll use an example : The player you're aiming at is at 10 meters away from you.
    You convert his coordinates relatives to you, and you get :

    Rho = 10
    Theta = 90° (This will be in radians by default, convert it)
    Phi = 0° (In radians by default)

    As your target is 10 meters away, we willl have to calculate the margin for Phi (Vertical) first, then the margin for Theta (Horizontal). These margins can be multiplicated to make the "hitbox" larger, by default this will be a 1x1 cube, so multiply Phi by 2 to get your Steve sized hitbox. I'll tell you when to do this.

    So, in order to get these margins, we'll need to have a linear interpolation fonction, wich isn't by default in Java, so here it is :
    Code:
    public float lerp(float a, float b, float f)
    {
        return a + f * (b - a);
    }
    Where a is the value returned when f equals 0, and b is the value returned when f equals 1.

    So with that, we can divide your Rho by Double.MAX_VALUE, for an appoximative infinite, wich will be our f.
    Our a will be 180, and our b will be 0, as I explained earlier. The returned value will be our margin of error for Rho, so do the same with with Theta. We'll call the margins of error Mrho and Mtheta, even if they are basically the same.
    This is the time to multiply the margins.

    Then, using your margins of error, we'll check if the Theta is included in
    [player.getLocation().getPitch() - Mtheta ; player.getLocation().getPitch() + Mtheta]. Then do the same with Rho and Yaw. If true, then that's a hit.

    So, for that example, as the target is standing 10 meters away, his Mtheta will be (very low, close to maybe 20°, I don't know), so if the yaw and pitch are within this range, then it's good. Meh.
    Forget the example, try it.
     
  17. Offline

    CaptainUniverse

    @Betagear when you say do the same for theta do you mean this
    Code:
    lerp(180,0,90 / double.max_value)
    and also I don't understand what you mean by
     
  18. Offline

    CaptainUniverse

  19. Offline

    MCKrypto14

    This will probably work. If the player is looking at an entity, it should be able to be found like this:
    Code:
    public final Entity getLookingAt(final Player player) {
         final List<Entity> nearby = Bukkit.getWorlds().get(0).getNearbyEntities(player.getEyeLocation(), 0, 0, 0).stream().collect(Collectors.toList());
         return nearby.isEmpty() ? null : nearby.get(0);
    }
     
  20. @MCKrypto14 Please stop spoon feeding and the player may not be in the first world in the array, why are you getting the first one. Why not just use the players location and get the world
     
    cococow123 and I Al Istannen like this.
  21. Offline

    CaptainUniverse

    @MCKrypto14 that always returns an entity even if the player is behind the other
     
  22. Offline

    CaptainUniverse

    I was more wondering if anyone can help me a little further with the linear interpolation because im still not understanding it clearly enough such as how i use the error or rho and theta to determine if they are aiming or not as
    @Betagear tried to explain to me
     
  23. Offline

    Betagear

    I was wrong at this point :
    "The returned value will be our margin of error for Rho, so do the same with with Theta. We'll call the margins of error Mrho and Mtheta, even if they are basically the same."
    --> It is the margin of error for Phi, so call it Mphi

    @CaptainUniverse When you lerp, you lerp like so :
    double Mphi = lerp(180.0, 0.0, Rho / Double.MAX_VALUE);
    double Mpheta = Mphi * margin.getY();
    Mphi *= margin.getX();

    And when I say "check if it is included in [player.getLocation().getPitch() - Mtheta ; player.getLocation().getPitch() + Mtheta]", you just have to check if the number is bigger than the first argument, and smaller than the second argument.

    But that method is very dirty, try using LivingEntity. hasLineOfSight by casting it.
     
Thread Status:
Not open for further replies.

Share This Page