| name | libgdx-math |
| description | Use when writing libGDX Java/Kotlin code involving math utilities — Vector2, Vector3, Matrix4, Quaternion, MathUtils, Interpolation, Intersector, Polygon, Circle, Rectangle, or spline curves. Use when debugging mutation bugs, wrong interpolation names, or incorrect collision detection. |
libGDX Math Utilities
Quick reference for com.badlogic.gdx.math.*. Covers vectors, matrices, quaternion, interpolation, intersection/collision, shapes, and math helpers.
CRITICAL: Vectors Mutate In Place
Almost every Vector2/Vector3 method mutates this and returns this for chaining. This is the #1 source of bugs.
Vector2 a = new Vector2(1, 2);
Vector2 b = new Vector2(3, 4);
a.add(b);
a.cpy().add(b);
a.sub(b).nor();
This applies to: set(), add(), sub(), scl(), nor(), lerp(), rotate*(), limit(), clamp(), setLength(), mulAdd(), setZero(), setToRandomDirection().
Vector2
new Vector2()
new Vector2(float x, float y)
new Vector2(Vector2 v)
Vector2.X
Vector2.Y
Vector2.Zero
Key methods beyond the obvious (set, add, sub, scl, nor, lerp, setZero, cpy — all mutating, return this):
limit(float) / limit2(float) — cap magnitude (limit2 avoids sqrt)
clamp(float min, float max) — clamp magnitude
setLength(float) / setLength2(float) — set magnitude
mulAdd(Vector2, float) — this += vec * scalar
mul(Matrix3) — transform by Matrix3 only, NOT Matrix4
crs(Vector2) — returns float (2D cross product is a scalar)
len2(), dst2() — squared versions (prefer for comparisons, avoids sqrt)
Angle & Rotation (Vector2 only)
Use Deg suffix methods. Non-suffixed versions are deprecated:
angleDeg() / angleDeg(Vector2 ref) — degrees 0–360
angleRad() / angleRad(Vector2 ref) — radians
rotateDeg(float) / rotateRad(float) — rotate vector
rotateAroundDeg(Vector2 ref, float deg) — rotate around point
setAngleDeg(float) / setAngleRad(float) — set direction
rotate90(int dir) — dir >= 0 = CCW, dir < 0 = CW
- DEPRECATED:
angle(), rotate(float), setAngle(float), rotateAround(Vector2, float) — use Deg versions
Vector3
new Vector3()
new Vector3(float x, float y, float z)
new Vector3(Vector3 other)
new Vector3(float[] values)
new Vector3(Vector2 v, float z)
Vector3.X, Vector3.Y, Vector3.Z, Vector3.Zero
Same methods as Vector2, plus key differences:
crs(Vector3) — MUTATES this with 3D cross product (unlike Vector2's crs() which returns float). Use a.cpy().crs(b) to preserve a.
slerp(Vector3 target, float alpha) — spherical lerp (Vector2 lacks this)
rotate(Vector3 axis, float degrees) — NOT deprecated (unlike Vector2's rotate)
mul(Matrix4), mul(Matrix3), mul(Quaternion) — transform by matrix/quaternion
prj(Matrix4) — project (divide by w) — for projection matrices
rot(Matrix4) — rotate only (ignores translation)
Matrix4
Column-major 4x4 matrix. public final float[] val = new float[16].
Matrix4 mat = new Matrix4();
mat.idt();
mat.setToTranslation(x, y, z);
mat.setToRotation(axis, degrees);
mat.setToScaling(x, y, z);
mat.setToLookAt(direction, up);
mat.translate(x, y, z);
mat.rotate(axis, degrees);
mat.scale(sx, sy, sz);
mat.mul(other);
mat.inv();
mat.tra();
float d = mat.det();
Vector3 pos = mat.getTranslation(new Vector3());
Quaternion rot = mat.getRotation(new Quaternion());
mat.set(position, rotation, scale);
mat.set(quaternion);
There is NO setToRotation(Quaternion) — use set(Quaternion) instead.
Matrix3
9-float 2D transform / normal matrix. public float[] val = new float[9] (NOT final).
Matrix3 m3 = new Matrix3();
m3.set(matrix4);
m3.inv();
m3.mul(other);
float d = m3.det();
Quaternion
new Quaternion()
new Quaternion(float x, float y, float z, float w)
new Quaternion(Quaternion other)
new Quaternion(Vector3 axis, float degrees)
q.idt();
q.set(other);
q.setFromAxis(axis, degrees);
q.setFromAxisRad(axis, radians);
q.setEulerAngles(yaw, pitch, roll);
q.setEulerAnglesRad(yaw, pitch, roll);
q.getYaw();
q.getPitch();
q.getRoll();
q.slerp(endQuat, alpha);
q.mul(other);
q.mulLeft(other);
q.nor();
q.conjugate();
q.transform(vector3);
q.toMatrix(float[16]);
q.cpy();
Gotchas:
setEulerAngles parameter order is (yaw, pitch, roll), not (pitch, yaw, roll). Other engines differ.
transform(Vector3) mutates the input vector — not the quaternion.
toMatrix() returns void, not the Quaternion.
- Quaternion must be normalized for
getYaw/getPitch/getRoll to be accurate.
MathUtils
Constants
| Constant | Value | Alias |
|---|
PI | 3.14159... | |
PI2 | 6.28318... (2π) | |
HALF_PI | 1.5708... (π/2) | |
E | 2.71828... | |
radiansToDegrees | 57.2957... | radDeg |
degreesToRadians | 0.01745... | degRad |
FLOAT_ROUNDING_ERROR | 0.000001f (1e-6) | |
Random
MathUtils.random()
MathUtils.random(int range)
MathUtils.random(int start, int end)
MathUtils.random(float range)
MathUtils.random(float start, float end)
MathUtils.randomSign()
MathUtils.randomBoolean()
MathUtils.randomBoolean(float chance)
int overloads are INCLUSIVE on both bounds. float overloads are EXCLUSIVE on the upper bound. This catches people constantly.
Trig (lookup-table — faster than Math.sin/cos)
| Method | Input | Returns |
|---|
sin(float rad) | Radians | float |
cos(float rad) | Radians | float |
sinDeg(float deg) | Degrees | float |
cosDeg(float deg) | Degrees | float |
atan2(float y, float x) | y, x | Radians (−π to π) |
atan2Deg360(float y, float x) | y, x | Degrees (0 to 360) |
Utility
MathUtils.clamp(value, min, max)
MathUtils.lerp(from, to, progress)
MathUtils.norm(rangeStart, rangeEnd, value)
MathUtils.map(inStart, inEnd, outStart, outEnd, value)
MathUtils.isZero(float)
MathUtils.isZero(float, tolerance)
MathUtils.isEqual(a, b)
MathUtils.isEqual(a, b, tolerance)
MathUtils.log2(float value)
MathUtils.lerpAngle(fromRad, toRad, progress)
MathUtils.lerpAngleDeg(fromDeg, toDeg, progress)
Interpolation
Usage: Interpolation.NAME.apply(alpha) where alpha in [0,1]. Also: apply(start, end, alpha).
Naming pattern: {category}, {category}In (slow-to-fast), {category}Out (fast-to-slow).
Categories: pow2–pow5, sine, exp5, exp10, circle, elastic, swing, bounce.
Standalone: linear, smooth (smoothstep), smooth2, smoother (Perlin smootherstep).
Aliases: fade = smoother (NOT smooth), slowFast = pow2In, fastSlow = pow2Out.
Inverses exist ONLY for pow2 and pow3: pow2InInverse, pow2OutInverse, pow3InInverse, pow3OutInverse.
DO NOT use quadIn, cubicOut, easeIn, easeOut, easeInOut, linear_in, quad — none exist. Convention is pow2, pow3, etc.
Custom: new Interpolation.Pow(6), new Interpolation.Elastic(2, 10, 7, 1), new Interpolation.Swing(2.5f).
Intersector
Static utility — all methods are public static.
Key methods (all return boolean unless noted):
overlaps(Circle, Circle), overlaps(Circle, Rectangle), overlaps(Rectangle, Rectangle)
overlapConvexPolygons(Polygon, Polygon) — optional MinimumTranslationVector param for MTV
isPointInTriangle(...), isPointInPolygon(...) — Vector2 or float overloads
intersectSegments(x1,y1, x2,y2, x3,y3, x4,y4, Vector2 intersection) — populates intersection
intersectRayTriangle(Ray, Vector3, Vector3, Vector3, Vector3 intersection)
intersectLinePlane(...) — returns FLOAT (distance), NOT boolean
intersectRayBounds(Ray, BoundingBox, Vector3), intersectRaySphere(Ray, Vector3, float, Vector3)
nearestSegmentPoint(...) — returns Vector2; distanceSegmentPoint(...) — returns float
Common Mistakes
- Mutating vectors unintentionally —
a.add(b) changes a. Use a.cpy().add(b) to create a new vector. This applies to nearly every Vector method.
- Mutating Vector3.X/Y/Z/Zero constants — These are mutable static fields, not true constants.
Vector3.Zero.set(1,0,0) corrupts the constant globally. Never pass them to methods that mutate.
- Using invented Interpolation names — There is no
quadIn, cubicOut, easeIn, easeInOut. Use pow2In, pow3Out, etc. Use fade or smoother for smooth acceleration.
- Confusing
fade with smooth — fade is an alias for smoother (Perlin smootherstep), NOT for smooth (classic smoothstep).
- Wrong random bounds assumption —
MathUtils.random(int start, int end) is INCLUSIVE on both ends. MathUtils.random(float start, float end) is EXCLUSIVE on the upper bound.
- Calling
Intersector.overlap() (singular) — The method is overlaps (plural). There is no overlap().
- Expecting
intersectLinePlane to return boolean — It returns float (distance from first point to plane), not boolean.
- Forgetting
Vector3.crs() mutates — Unlike Vector2's crs() which returns a float scalar, Vector3's crs() overwrites this with the cross product. Use a.cpy().crs(b).
- Using deprecated Vector2 angle/rotate methods —
angle(), rotate(float), setAngle(float), rotateAround(Vector2, float) are all deprecated. Use angleDeg(), rotateDeg(), setAngleDeg(), rotateAroundDeg().
- Allocating vectors in hot loops —
new Vector2() in render/update creates GC pressure. Declare reusable private static final Vector2 tmp = new Vector2() fields and call tmp.set(...).
- Using
Matrix4.setToRotation(quaternion) — This method does not exist. Use mat.set(quaternion) or mat.rotate(quaternion) instead.
- Not calling
cpy() before passing vectors to physics/AI — Many libraries store references. If you reuse a temp vector, the stored reference silently changes value.