Vector Programming for Beginners Vector Programming for Beginners Learn what vectors are and how understanding them will benefit your code ContentsWhat is a vector?The vector in SpigotWhat is the use of a vector in Spigot?AdditionMultiplicationNormalizeCrossproductMidpointExampleWhat is a vector?(top)A vector is represented by a length and a direction and always describes a movement from one point to another. Most of you will already have heard about vectors or seen some strange arrows representing them. Let's have a look at the vector in Spigot. The vector in Spigot(top)The vector in Spigot can be found in org.bukkit.util (JavaDoc) package and can be created the following ways: Code (Java): Vector v = new Vector(); //Creates a vector with length 0 and NO direction Vector v = new Vector(x, y, z); //Creates a vector with defined direction and length Each vector has three values that represent the vector, called X, Y, and Z (the 3 directions). Also important to know is that you can get the length of a vector by calling .length() and subsequently get / set the value of every axis by calling .getX(), .getY(), .getZ(), and .setX(x), .setY(y), .setZ(z). What is the use of a vector in Spigot?(top)Whenever an entity moves or the target you're are looking at has to be calculated, a vector is used. At the end of this tutorial, you should be able to do both. Let's explain the possible calculations. * The blue arrow is always the result of the calculation. Addition(top) This calculation is very basic. You got one arrow and add it to another. Lets code it! Code (Java): Vector first = new Vector(1, 3, 2); Vector second = new Vector(3, -1, 4); // Let's add them together! Vector result = first.add(second); // Result is now a Vector of 4, 2, 6 // NOTE: The #add method modifies the vector it's called on // Thus, result and first now refer to the same vector In order to avoid changing the vector, one needs to clone it first using the Vector#clone method. Multiplication(top) The second simple (and essential) calculation. Just multiply the length of the vector. When the value given is NEGATIVE, the vector switches its direction. Code: Code (Java): Vector v = new Vector(3, 4, 2); Vector result1 = v.clone().multiply(2); // Vector of 6, 8, 4 Vector result2 = v.clone().multiply(-1); // Vector of -3, -4, -2 // NOTE: Since the multiply method modifies the vector, // we need to clone it in order to get a new one As you see, every value of the vector is being multiplied with the value you specify. Normalize(top)Sets the vectors length to 1. For example, you have a vector (3, 3, 3). Then, its length is the √( (3*3)+(3*3)+(3*3) ) = √(27) = 5.19, so the vector's length is 5.19. Normalizing now has to divide the vector's length by its length to get the resulting vector. So normalizing calls .multiply(1/5.19) resulting in a vector of (0.57, 0.57, 0.57). Code: Code (Java): Vector v = new Vector(3, 3, 3); Vector result = v.normalize(); // Returns vector of length 1 and movement of 0.57, 0.57, 0.57 Crossproduct(top) This calculation returns a vector that is orthogonal to both of the previous vectors. Its length is the area of the light blue parallelogram. This can be used to compare if two vectors are nearly the same (for example, when targeting a player). Example: Code (Java): Vector first = new Vector(1, 2, 3); Vector second = new Vector(-7, 8, 9); Vector result = first.crossProduct(second); // Will return vector of -6, -30, 22 Source of example: Wikipedia (didn't want to draw these brackets) Midpoint(top)This is easy! Take one vector, add it to another, and divide by 2. Then you have your midpoint! You have two vectors, the black and the orange one. You add them together and get the green vector. You divide the green vector by 2 or multiply it by 0.5 and get your midpoint. Code: Code (Java): Vector first = new Vector(1, 3, 4); Vector second = new Vector(4, 3, 1); Vector midpoint1 = first.midpoint(second); // Vector of 2.5, 3, 2.5 Vector midpoint2 = first.add(second).multiply(0.5); // Vector of 2.5, 3, 2.5 Now you know how to use vectors! Time to practice a bit! Example(top)Let's check if a player targets another location! Code (Java): public boolean doesPlayerTarget(Player p, Location target){ //p is your player //target is the location the player might target //Check if they are in the same world if(!target.getWorld().equals(p.getWorld()))return false; //Let's begin! //Get the players head location Location head = p.getLocation().add(0, p.getEyeHeight(), 0); //Get the players looking direction as vector and // shorten it to a length of 1 by using normalize() Vector look = p.getLocation().getDirection().normalize(); //Get the direction of the target from the player by substracting his location with the target //Again use normalize() of course, to shorten the value Vector direction = head.subtract(target).toVector().normalize(); //Lets build our crossProduct. When the crossProduct's length is 0, the player //is exactly targeting our target location //why? because then the parallelogram shown above has an area of 0 :) Vector cp = direction.crossProduct(look); //Lets get the length from the vector double length = cp.length(); //If the length is bigger than 0.1 the player is probably //Not targeting our location. Choose this value appropriate return (length < 0.1); } (View this Page on the Wiki) Last Modified: Aug 29, 2020 at 7:37 AM (Cached) #1 jflory7, May 26, 2015 Last edited: May 27, 2015 Like x 6 Useful x 3 Informative x 2
Yeah, you can do that. Code (Text): public void makeFly(final EntityLiving e){ new BukkitRunnable(){ public void run(){ if(e.isDead()){ cancel(); return; } e.setVelocity(new Vector()); //new Vector() is vector of 0, 0, 0 } }.runTaskTimer(PLUGIN, 1, 1); }
I've noticed that almost all operations that return a vector actually modify the vector you call them on, such as multiply() and most disgustingly crossProduct(). This behavior has cost me hours of time trying to debug code (thanks to Bukkit's atrocious javadocs). For example: Code (Text): public Vector crossProduct(Vector o) { double newX = y * o.z - o.y * z; double newY = z * o.x - o.z * x; double newZ = x * o.y - o.x * y; x = newX; y = newY; z = newZ; return this; } The easiest solution is to simply call clone() after every vector that you don't want to mess with. Inefficient, but necessary since the behavior has become a feature (plugins rely on it, anyways). This is otherwise a very nice tutorial, but unfortunately the results are all going to be wrong because the Bukkit methods modify the left hand operand, making everything a +=, -=, *=, /=, x=, etc operation.
I'd quite imagine the above is due to pass by value of reference. Whoever thought that was a good idea for vectors does indeed need to be shot, though. You should consider the object you are getting as the object and not a copy unless stated otherwise.