LookAt and Move functions

Discussion in 'Resources' started by bergerkiller, Jul 17, 2011.

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

    bergerkiller

    I already wrote these functions for my own Java game before, but it could be useful to lots of other people

    lookAt
    What it does is make a Location look at another location, in other words, change the pitch/yaw in such manner that, if applied to a player or entity, it will look at the specified location.

    Code:
        public static Location lookAt(Location loc, Location lookat) {
            //Clone the loc to prevent applied changes to the input loc
            loc = loc.clone();
    
            // Values of change in distance (make it relative)
            double dx = lookat.getX() - loc.getX();
            double dy = lookat.getY() - loc.getY();
            double dz = lookat.getZ() - loc.getZ();
    
            // Set yaw
            if (dx != 0) {
                // Set yaw start value based on dx
                if (dx < 0) {
                    loc.setYaw((float) (1.5 * Math.PI));
                } else {
                    loc.setYaw((float) (0.5 * Math.PI));
                }
                loc.setYaw((float) loc.getYaw() - (float) Math.atan(dz / dx));
            } else if (dz < 0) {
                loc.setYaw((float) Math.PI);
            }
    
            // Get the distance from dx/dz
            double dxz = Math.sqrt(Math.pow(dx, 2) + Math.pow(dz, 2));
    
            // Set pitch
            loc.setPitch((float) -Math.atan(dy / dxz));
    
            // Set values, convert to degrees (invert the yaw since Bukkit uses a different yaw dimension format)
            loc.setYaw(-loc.getYaw() * 180f / (float) Math.PI);
            loc.setPitch(loc.getPitch() * 180f / (float) Math.PI);
    
            return loc;
        }
    move
    Moves the given Location in the direction it is looking. For example, if you wish to teleport a Player two blocks further from where he is looking.

    Code:
        public static Location move(Location loc, Vector offset) {
            // Convert rotation to radians
            float ryaw = -loc.getYaw() / 180f * (float) Math.PI;
            float rpitch = loc.getPitch() / 180f * (float) Math.PI;
    
            //Conversions found by (a lot of) testing
            double x = loc.getX();
            double y = loc.getY();
            double z = loc.getZ();
            z -= offset.getX() * Math.sin(ryaw);
            z += offset.getY() * Math.cos(ryaw) * Math.sin(rpitch);
            z += offset.getZ() * Math.cos(ryaw) * Math.cos(rpitch);
            x += offset.getX() * Math.cos(ryaw);
            x += offset.getY() * Math.sin(rpitch) * Math.sin(ryaw);
            x += offset.getZ() * Math.sin(ryaw) * Math.cos(rpitch);
            y += offset.getY() * Math.cos(rpitch);
            y -= offset.getZ() * Math.sin(rpitch);
            return new Location(loc.getWorld(), x, y, z, loc.getYaw(), loc.getPitch());
        }
    Feel free to use these functions, but please do add that you got it from me. It took me several man-hours and trial and error to get this function working. :)
     
  2. Offline

    captainawesome7

    @bergerkiller Looks nice, I might use it in a plugin soon.
     
  3. Offline

    bergerkiller

    Added the move function I had in my own Location class. If you need the rotateAt functions, just ask and I will add those too. :)
    Note: It could be that x and z are swapped. I am not sure if both my game and Minecraft uses the same x and z dimension.
     
  4. Sorry to sound rude but my Extras Library does this in about 2 lines of code.

    I know this sounds arrogant and offensive but I just wanted to inform you of a more efficient way to check. If you look at my extras library to which the source is on github inside the player class you'll see the getlookedatlocation and block method.
     
  5. Offline

    captainawesome7

    But doesn't your getlocationlooked return the location that the player is looking at? I don't think you understand the point of this method. You give it a player's location and say the location of a cow, and it returns a modified location of the player, that, when teleported to this modified location, makes the player look at the cow. Your getlocationlooked in the player class gets the location that the player is looking at, and this adjusts the player's location to make it look at something, which are two completely different things.
    And great job @bergerkiller , this works perfectly.
     
  6. Oh sorry, I scanned through the post and it looked similar to code i had seen before which did that :p
     
  7. Offline

    bergerkiller

    Yup, all lookat does is, basically, compute the yaw and pitch values required to look at a location.
    I used it in my Yahtzee game to make the camera look at the dice thrown in the air, proven pretty solid.

    You can use it, for example, if you want a Player to look at a nearby player when he types something in the chat.
    Move can be used when placing blocks, for example: you want to place a block 2-3 meters away from where the player looks (at the cursor):
    Code:
    Location loc = player.getLocation();
    loc = move(loc, new Vector(0, 0, 2);
    world.setBlockAt(loc, ...);
    //written outside the IDE
     
  8. Offline

    Jeespah

    OMG, I think I love you!
    But seriously, this saved me for a lot of work, and I probably would never get it to work as good as this does!
     
  9. Offline

    bergerkiller

    Jeespah well actually, they can be even better. :)

    I'll upload my current latest versions of these functions. They are in BKCommonLib:
    Code:
        public static final float DEGTORAD = 0.017453293F;
        public static final float RADTODEG = 57.29577951F;
        public static float getLookAtYaw(net.minecraft.server.Entity loc, net.minecraft.server.Entity lookat) {
            return getLookAtYaw(loc.getBukkitEntity(), lookat.getBukkitEntity());
        }
        public static float getLookAtYaw(Entity loc, Entity lookat) {
            return getLookAtYaw(loc.getLocation(), lookat.getLocation());
        }
        public static float getLookAtYaw(Block loc, Block lookat) {
            return getLookAtYaw(loc.getLocation(), lookat.getLocation());
        }
        public static float getLookAtYaw(Location loc, Location lookat) {
            // Values of change in distance (make it relative)
            return getLookAtYaw(lookat.getX() - loc.getX(), lookat.getZ() - loc.getZ());
        }
        public static float getLookAtYaw(Vector motion) {
            return getLookAtYaw(motion.getX(), motion.getZ());
        }
        public static float getLookAtYaw(double dx, double dz) {
            float yaw = 0;
            // Set yaw
            if (dx != 0) {
                // Set yaw start value based on dx
                if (dx < 0) {
                    yaw = 270;
                } else {
                    yaw = 90;
                }
                yaw -= atan(dz / dx);
            } else if (dz < 0) {
                yaw = 180;
            }
            return -yaw - 90;
        }
        public static float getLookAtPitch(double motX, double motY, double motZ) {
            return getLookAtPitch(motY, length(motX, motZ));
        }
        public static float getLookAtPitch(double motY, double motXZ) {
            return -atan(motY / motXZ);
        }
        public static float atan(double value) {
            return RADTODEG * (float) Math.atan(value);
        }
    
    Code:
        public static Location move(Location loc, Vector offset) {
            return move(loc, offset.getX(), offset.getY(), offset.getZ());
        }
        public static Location move(Location loc, double dx, double dy, double dz) {
            Vector off = rotate(loc.getYaw(), loc.getPitch(), dx, dy, dz);
            double x = loc.getX() + off.getX();
            double y = loc.getY() + off.getY();
            double z = loc.getZ() + off.getZ();
            return new Location(loc.getWorld(), x, y, z, loc.getYaw(), loc.getPitch());
        }   
        public static Vector rotate(float yaw, float pitch, Vector value) {
            return rotate(yaw, pitch, value.getX(), value.getY(), value.getZ());
        }
        public static Vector rotate(float yaw, float pitch, double x, double y, double z) {
            //Conversions found by (a lot of) testing
            float angle;
            angle = yaw * DEGTORAD;
            double sinyaw = Math.sin(angle);
            double cosyaw = Math.cos(angle);
           
            angle = pitch * DEGTORAD;
            double sinpitch = Math.sin(angle);
            double cospitch = Math.cos(angle);
           
            double newx = 0.0;
            double newy = 0.0;
            double newz = 0.0;
            newz -= x * cosyaw;
            newz -= y * sinyaw * sinpitch;
            newz -= z * sinyaw * cospitch;
            newx += x * sinyaw;
            newx -= y * cosyaw * sinpitch;
            newx -= z * cosyaw * cospitch;
            newy += y * cospitch;
            newy -= z * sinpitch;
           
            return new Vector(newx, newy, newz);
        }
    A lot more advanced/multi-usable now. Might be easier or more complicated to understand :)
     
  10. Offline

    Jeespah

    Ah, ok.

    Good work, we are lucky this community has people like you!
     
Thread Status:
Not open for further replies.

Share This Page