Original: http://gad.qq.com/program/translateview/7172922
Translation: Wang Chenglin (Maxwell's Maxwell) revision: Huang Xiumei (Heavy-tak)
This is the fifth article in this series that we have long been looking forward to. If you don't know much about vectors, check out the first four articles in this series: Introduction, Vector basics, vector geometry, vector operations.
This quick check list lists some of the common geometric problems in the game and how to solve them using mathematical vectors.
Complete form for basic vector operations
First, let's review it.
First I assume that you have a vector class available. Most of its functions are concentrated on the 2D, but the principle of 3D is the same. The difference is only in the vector product, in 2D I assume that a vector multiplication only returns a scalar representing the "z" axis. I will specifically point out any case that applies only to 2D or 3D.
Strictly speaking, a point is not a vector--but a vector can represent the distance from the origin (0,0) to the point, so it is reasonable to represent the vector as a dot.
I expect you to have each component in this class, and the following operations (using C + + style notation, including operator overloading – but depending on your needs it should be easy to translate it into any other language). If an operation is not available, you can still implement it by extending the class or by creating a "Vectorutils" class. The following examples generally apply to 2D vectors--but for 3D it is usually only possible to add Z coordinates in the form of x and Y.
- vector2foperator+ (vector2f VEC): Returns the and of two vectors. (in languages that are not overloaded, the function may be called add ().) Here are a few examples similar. )
A+B=VECTOR2F (A.X+B.X,A.Y+B.Y);
- vector2foperator- (vector2f VEC): Returns the difference between two vectors
A-B=VECTOR2F (A.X-B.X,A.Y-B.Y);
- vector2foperator* (vector2f VEC): Returns the product of a component of two vectors
A*B=VECTOR2F (A.X*B.X,A.Y*B.Y);
- vector2foperator/ (vector2f VEC): Returns a component quotient of two vectors
A/B=VECTOR2F (A.X/B.X,A.Y/B.Y);
- vector2foperator* (float scalar): Returns the result of multiplying all the components of a vector by a scalar parameter, respectively.
A*S=VECTOR2F (a.x*s,a.y*s);
S*A=VECTOR2F (a.x*s,a.y*s);
- vector2foperator/ (float scalar): Returns the result of each component of the vector divided by a scalar parameter.
A/S=VECTOR2F (A.X/S,A.Y/S);
- Floatdot (vector2f VEC): Returns the dot multiplication of two vectors
A.dot (b) =a.x*b.x+a.y*b.y;
- Floatcross (vector2f VEC): (2D case) returns the z component of a two-vector fork (3D vector)
A.cross (b) =a.x*b.y-a.y*b.x;
- Vector3fcross (vector3f VEC): (3D case) returns the cross-multiplication of two vectors.
A.cross (b) =vector3f (A.Y*B.Z-A.Z*B.Y, a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
- Floatlength (): Returns the length of the vector.
A.length () =sqrt (A.X*A.X+A.Y*A.Y);
- Floatsquaredlength (): Returns the square of the length of the vector. It is suitable for comparing the lengths of two vectors and avoids the calculation of square roots.
A.squaredlength () =a.x*a.x+a.y*a.y;
- Floatunit (): Returns a vector that points to a length of 1 in the same direction.
A.unit () =a/a.length ();
- Vector2fturnleft (): Returns the result of a vector rotated 90 degrees to the left. Applies to the calculation method vector. (Assuming the y-axis is pointing up, or turning right)
A.TURNLEFT=VECTOR2F (-a.y,a.x);
- Vector2fturnright (): Returns the result of a vector rotated 90 degrees to the right. Applies to the calculation method vector. (Suppose the y-axis is pointing up, or turn left)
- A.TURNRIGHT=VECTOR2F (a.y,-a.x);
- vector2frotate (float angle): Rotates the vector by a specific angle. Although rarely found in vector classes, this is a very useful operation. is equivalent to multiplying by a 2x2 rotation matrix
A.rotate (angle) =vector2f (A.x*cos (angle)-a.y*sin (angle), a.x*sin (angle) +a.y*cos (angle));
- Floatangle (): Returns the angle to which the vector is pointing.
A.angle () =atan2 (a.y,a.x);
A simple example-warm-up
Example of the distance between two points
You may know that you can use the Pythagorean theorem, but the vector method is simpler. Give direction A and vector B:
1 |
float distance = (A-B). Length (); |
Example 2--straightening (alignment)
In some cases you may want to straighten it in the center of a picture. Sometimes you have to follow the upper-left or upper-middle points. More broadly, in order to maximize control of the straightening line, you can use a two-component, 0-to-1 (or even more, if you wish) vector to straighten in any direction.
1 2 |
Imgpos, imgsize and align is all vector2f vector2f drawposition = imgpos + imgsize * Align |
Example of 3--parametric linear equation
Two points define a line, but the definition has a lot of mystery. A good way to deal with a straight line is to use parametric equations: a point ("P0") and a direction ("dir").
1 2 |
vector2f p0 = point1; vector2f dir = (point2-point1). unit (); |
With this, you can, for example, you can get a distance p010 units far from the point:
1 |
vector2f P1 = p0 + dir * 10; |
Example 4:--between midpoint and two points (interpolation)
Give directional quantities of p0 and P1. Their midpoint is (P0+P1)/2. More broadly, the segments defined by P0 and P1 can be changed by linear delay between 0 and 1.
1 |
vector2f p = (1-t) * p0 + t * p1; |
|
|
In t=0, you get p0, you get P1 in T=1, you get the midpoint in t=0.5, and so on.
Example 5: Finding the normal direction of a segment
You already know how to find the direction of the line segment (example 3). Rotate it 90 degrees to get the normal vector, so use TurnLeft () or turnright () to get the result.
Using the projection of a point multiplication
The point multiplication is very helpful for calculating the length of the vector that is projected along One direction. We need a vector ("a") and a unit vector representing the projection direction ("dir") (So make sure you first use unit ()). Then the projection length is A.dot (dir). For example, if a= (3,4), dir= (1,0), then A.dot (dir) = 3. You can tell that this is correct, because (1,0) is the direction of the X axis. In fact a.x constant equals A.dot (vector2f (1,0)), A.Y constant equals A.dot (vector2f (0,1)).
Because the point multiplication of a and B can also be defined as |a| | B|cos (Alpha) (Alpha is a two-vector angle), so if both the vertical result is 0, if the two angle is less than 90 ° The result is positive, greater than 90 ° result is negative. We can use this to determine whether the two vectors point to the same general direction.
If you multiply the result of a point multiply by the direction vector, you get a projection of the vector along that direction-what we call "at" (t for tangential). If we do a-at, we will get a vector perpendicular to the direction vector-what we call "an" (N for normal). At+an=a.
Example 6--determines the direction closest to Dir
Suppose you have many unit vectors pointing in different directions, and you want to find out which direction is closest to Dir. Just find the one with the largest result in the list of vectors and the dir point multiply. Similarly, the smallest point multiplier means the furthest away.
Example 7--to determine if the angle of two vectors is less than alpha
Using the above equation, we know that if the point multiplication of the unit vectors of the two vectors A and B is less than the Cos (alpha), then the angle between them is less than alpha.
123 |
bool isLessThanAlpha(Vector2f a, Vector2f b, float alpha) { return a.unit().dot(b.unit()) < cos (alpha); } |
Example 8--judging the half plane of a point
Suppose there is any point in the plane p0, and a direction (unit) vector, dir. Suppose a wireless long line that crosses the p0, perpendicular to dir, divides the plane in two: dir points to the half plane and Dir does not point to a half plane. So how do you tell if a point P is on the side of Dir? Remember that when the angle between the vectors is less than 90 ° their point multiplication is positive, then just do the projection and then check:
123 |
bool isInsideHalfPlane(Vector2f p, Vector2f p0, Vector dir) { return (p - p0).dot(dir) >= 0; } |
Example 9--forcing a little in the half plane
Similar to the example above, but not just the check, if the projection is less than 0, we use it to move the target-projection to dir direction so that the target point is at the edge of the half plane.
12345 |
Vector2f makeInsideHalfPlane(Vector2f p, Vector2f p0, Vector dir) { float proj = (p - p0).dot(dir); if (proj >= 0) return p; else return p - proj * dir; } |
Example 10--Check/force a little in a convex multi-faceted body.
A convex multipatch can be defined as the result of intersecting multiple half-planes, with each intersection as the edge of the Multipatch. Their p0 are vertices on the edge, and their dir is the inner normal vector of the edge (for example, if you go clockwise, that is turnright () normal). A point is inside a multipatch if and only if it is within all half planes. Similarly, you can force it to use the Makeinsidehalfplane algorithm on all half planes in a multi-faceted body (by moving to the nearest edge). Oh It only works when all angles are >=90°]
Example 11--a vector reflected by a given normal
Play ball games, the ball hit a diagonal wall surface. The velocity vector of the known ball and the normal vector of the wall (see Example 5). How will it bounce in the real world? Simple! Simply reflect the normal velocity of the ball and keep its tangential velocity.
12345 |
Vector2f vel = getVel(); Vector2f dir = getWallNormal(); // Make sure this is a unit vector Vector2f velN = dir * vel.dot(dir); // Normal component Vector2f velT = vel - velN; // Tangential component Vector2f reflectedVel = velT - velN; |
To be closer to reality, you can multiply the Velt and veln by a constant that represents the friction and recovery coefficients respectively.
Example 12--offsets the movement along the axis
Sometimes we need to limit the movement to a given axis. The idea is the same as above: break the velocity down to normal and tangent upward, and then only the tangent speed is preserved. This helps to calculate the speed of people moving along the track.
Rotating
Example 13--points around a fixed point to do rotation
Assuming we have a little, rotate () rotates the point at the origin. It's fun, but there are limits. It is easy and practical to rotate at any point-just subtract the point by a dot, that is, pan the point to the origin, then rotate it, and then add the point back.
123 |
Vector2f rotateAroundPivot(Vector2f p, Vector2f pivot) { return (pos - pivot).rotate(angle) + pivot; } |
Example 14--determine which direction to rotate
Suppose we have a character who wants to turn toward the enemy. Known for his direction and direction toward the enemy. So should he turn left or right? Cross-multiplication gives a simple answer: Curdir.cross (targetDir) returns positive if you should turn left, negative if you should turn right (return 0 if you have already faced him or 180° back to him).
Additional Geometry examples
There are some other practical examples where vectors are not used too much, but are useful:
Example 15--offset space to screen coordinates
Equidistant game, you know where the world (0,0) is on the screen (let's call it the origin, use a vector to represent it), but how do you know where (x, y) is on the screen? First, you need two vectors representing the coordinate base, a new x-axis, and a new y-axis. For a typical isometric game, they can be bx=vector2f (2,1) and by=vector2f ( -2,1)-they are not necessarily unit vectors. Now, everything is simple.
12 |
Vector2f p = getWorldPoint(); Vector2f screenPos = bx * p.x + by * p.y + origin; |
Yes, it's very simple indeed.
Example 16--isometric screen to world coordinates
In the same situation, but this time you want to know which tile the mouse is sliding over. It's a little more complicated. We know (x ', y ') = (X*BX.X+Y*BY.X,X*BX.Y+Y*BY.Y) + origin, so we can subtract the origin first and then solve the equation. Using the Kramer rule, we can use the 2D cross-multiplication intelligently (to see the definition of the beginning of the article) to simplify:
12345 |
Vector2f pos = getMousePos() - origin; float demDet = bx.cross(by); float xDet = pos.cross(by); float yDet = bx.cross(pos); Vector2f worldPos = Vector2f(xDet / demDet, yDet / demDet); |
I think a lot of people are using the "Find rectangle and see Bitmap" method, and now you don't need it.
"Go" game Programmer's Mathematical food 05--vector quick look table