Repository navigation
mathT
mathT is the engine's maths table. It has everything in Lua's own math library under
capitalised names, plus the helpers games need all the time: clamping, interpolation, angles,
random numbers and vector maths.
local t = mathT.Clamp01(timer / duration)
local height = mathT.Lerp(bottom, top, mathT.SmoothStep(0, 1, t))Lua's standard math library is still there too (math.floor, math.random, ...). Use
whichever you like. Note that mathT.Random* and math.random are separate generators:
mathT.RandomSeed doesn't affect math.random.
Radians or degrees? Sin, Cos, Tan, Asin, Acos, Atan and Atan2 use radians,
like Lua's math. Everything with Angle in its name, and Vector2Rotate /
Vector2FromAngle, use degrees. Convert with DegToRad and RadToDeg.
| Name | Value |
|---|---|
Pi |
3.14159265359f |
Tau |
2 * Pi, one full turn in radians. |
HalfPi |
Pi / 2, a quarter turn in radians. |
E |
Euler's number, 2.718281828459045f |
Sqrt2 |
Square root of 2. |
Infinity / NegativeInfinity
|
Positive and negative infinity. |
Epsilon |
1e-6, the default tolerance of Approximately. |
MaxInteger / MinInteger
|
Largest and smallest Lua integer. |
| Function | Returns | |
|---|---|---|
Abs(x) |
number | Absoulete value |
Sign(x) |
integer |
-1, 0 or 1. |
Floor(x) / Ceil(x)
|
integer | |
Round(x) |
integer | Rounds half away from zero: Round(2.5) is 3, Round(-2.5) is -3. |
Round(x, digits) |
number | Rounds to that many decimals: Round(3.14159, 2) is 3.14. |
Trunc(x) |
integer | Drops the fraction (rounds toward zero). |
Frac(x) |
number | The fraction: x - Trunc(x). Frac(-1.25) is -0.25. |
Min(a, b, ...) / Max(a, b, ...)
|
number | Any number of arguments. |
Mod(x, d) |
number | Floored modulo, like Lua's %: the result has the sign of d. Mod(-1, 360) is 359. |
Fmod(x, d) |
number | C-style remainder: the result has the sign of x. Fmod(-1, 360) is -1. |
Sqrt(x) |
number | |
Pow(base, exponent) |
number | |
Exp(x) |
number |
E raised to x. |
Log(x[, base]) |
number | Natural log, or the log in base. |
Log10(x) / Log2(x)
|
number | |
Hypot(x, y) |
number |
Sqrt(x*x + y*y), without overflow. |
| Function | |
|---|---|
Sin(r), Cos(r), Tan(r)
|
Radians in. |
Asin(x), Acos(x)
|
Radians out. |
Atan(y[, x]) |
Radians out. With two arguments it is the same as Atan2(y, x). |
Atan2(y, x) |
Radians out, full -Pi..Pi range. |
Sinh(x), Cosh(x), Tanh(x)
|
Hyperbolic functions. |
DegToRad(degrees) / RadToDeg(radians)
|
Conversions. |
| Function | |
|---|---|
Clamp(x, min, max) |
Keeps x between min and max. min must not be larger than max. |
Clamp01(x) |
Keeps x between 0 and 1. |
Lerp(a, b, t) |
a at t = 0, b at t = 1. Not clamped: t = 2 goes past b. |
LerpClamped(a, b, t) |
Lerp with t clamped to 0..1. |
InverseLerp(a, b, x) |
Where x sits between a and b: 0 at a, 1 at b. |
Remap(x, inMin, inMax, outMin, outMax) |
Maps x from one range to another (not clamped). Returns outMin if inMin == inMax. |
SmoothStep(a, b, t) |
Like LerpClamped, but eases in and out. |
MoveTowards(current, target, maxDelta) |
Steps toward target by at most maxDelta, never overshooting. |
SmoothDamp(current, target, velocity, smoothTime[, deltaTime]) |
Smooth, spring-like follow. Returns two values: the new value and the new velocity. See below. |
Repeat(x, length) |
Wraps x into 0..length. Returns 0 if length <= 0. |
PingPong(x, length) |
Bounces x back and forth between 0 and length. |
Wrap(x, min, max) |
Wraps x into min..max. |
Snap(x, step) |
Rounds x to the nearest multiple of step. |
MoveTowards moves at a steady speed and stops exactly on the target. Multiply the speed by
GameTime.deltaTime:
height = mathT.MoveTowards(height, targetHeight, 30 * GameTime.deltaTime)Lerp with a fixed t each frame slows down as it gets closer and never quite arrives. For a
smooth follow, SmoothDamp is usually better.
Lua functions can't change their arguments, so SmoothDamp hands the velocity back as a second
return value. Keep it in a variable and pass it back in next frame. deltaTime defaults to
GameTime.deltaTime.
local velocity = 0
function Update()
local p = entity.transform.position
local y
y, velocity = mathT.SmoothDamp(p.y, targetY, velocity, 0.3)
entity.transform.position = Vector3(p.x, y, p.z)
end| Function | |
|---|---|
DeltaAngle(from, to) |
The shortest signed turn from from to to, in -180..180. DeltaAngle(350, 10) is 20. |
LerpAngle(a, b, t) |
Lerp for angles, taking the short way round. t is clamped. |
MoveTowardsAngle(current, target, maxDelta) |
MoveTowards for angles, taking the short way round. |
NormalizeAngle(degrees) |
Wraps an angle into -180..180. |
-- Turn toward the player at 90 degrees per second.
local facing = 0
function Update()
local p, me = player.transform.position, entity.transform.position
local wanted = mathT.Vector2ToAngle(Vector2(p.x - me.x, p.z - me.z))
facing = mathT.MoveTowardsAngle(facing, wanted, 90 * GameTime.deltaTime)
endtransform.rotation is a quaternion, not an angle. To turn an angle into a rotation, see
Transform.
| Function | |
|---|---|
Approximately(a, b[, epsilon]) |
true if a and b differ by at most epsilon (default Epsilon). Use it instead of == for numbers that came out of maths. |
IsNaN(x) |
|
IsInfinite(x) |
|
IsFinite(x) |
false for NaN and infinities. |
| Function | Returns |
|---|---|
Random(max) |
Integer from 0 to max - 1. Returns 0 if max <= 0. |
Random(min, max) |
Integer from min to max, both included. |
RandomF() |
Number from 0 to 1. |
RandomF(max) |
Number from 0 to max. |
RandomF(min, max) |
Number from min to max. |
RandomBool() |
true or false, 50/50. |
RandomOnUnitCircle() |
Vector2 direction of length 1. |
RandomInsideUnitCircle() |
Vector2 point inside a circle of radius 1, evenly spread. |
RandomOnUnitSphere() |
Vector3 direction of length 1. |
RandomInsideUnitSphere() |
Vector3 point inside a sphere of radius 1, evenly spread. |
RandomFast() |
Number from 0 to 1 from a fixed table of 512 values. Cheaper, but repeats and ignores RandomSeed. |
RandomSeed(seed) |
Restarts every generator above except RandomFast. The same seed always gives the same sequence. |
The generator starts from the same seed every time the engine starts, so a level plays out the same way each run unless you reseed it. For different results each run:
function Start()
mathT.RandomSeed(GameTime.osTime)
endThe seed is shared by every script, so reseeding in one script changes what the others get.
-- Pick a random entry from a list.
local sounds = {"Hit1.wav", "Hit2.wav", "Hit3.wav"}
local pick = sounds[mathT.Random(1, #sounds)]These all take and return Vector2 values and never change their arguments. For
simple sums you can also use operators: a + b, a * 2, v.length, v.normalized.
| Function | |
|---|---|
Vector2Add(a, b), Vector2Sub(a, b)
|
|
Vector2Mul(a, b), Vector2Div(a, b)
|
Per component. |
Vector2Scale(v, s), Vector2Negate(v)
|
|
Vector2Length(v), Vector2LengthSquared(v)
|
|
Vector2Normalize(v) |
Length-1 copy. A zero vector stays zero. |
Vector2Distance(a, b), Vector2DistanceSquared(a, b)
|
|
Vector2Dot(a, b) |
|
Vector2Cross(a, b) |
A number: positive when b is counter-clockwise from a. |
Vector2Lerp(a, b, t) |
Not clamped. |
Vector2MoveTowards(current, target, maxDistance) |
Never overshoots. |
Vector2Angle(from, to) |
Unsigned angle in degrees, 0..180. |
Vector2SignedAngle(from, to) |
Signed angle in degrees, -180..180, positive counter-clockwise. |
Vector2Rotate(v, degrees) |
Rotates counter-clockwise. |
Vector2FromAngle(degrees) |
Unit vector at that angle: 0 is +x, 90 is +y. |
Vector2ToAngle(v) |
The opposite of Vector2FromAngle. |
Vector2Perpendicular(v) |
v turned 90 degrees counter-clockwise. |
Vector2Reflect(v, normal) |
Bounces v off a surface. normal should have length 1. |
Vector2Project(v, onto) |
The part of v that points along onto. |
Vector2ClampLength(v, maxLength) |
Shortens v if it is longer than maxLength. |
Vector2Min(a, b), Vector2Max(a, b)
|
Per component. |
Remember that a map position's .y is the world z. To turn a 3D position into a map position,
use Vector2(p.x, p.z).
| Function | |
|---|---|
Vector3Add(a, b), Vector3Sub(a, b)
|
|
Vector3Mul(a, b), Vector3Div(a, b)
|
Per component. |
Vector3Scale(v, s), Vector3Negate(v)
|
|
Vector3Length(v), Vector3LengthSquared(v)
|
|
Vector3Normalize(v) |
Length-1 copy. A zero vector stays zero. |
Vector3Distance(a, b), Vector3DistanceSquared(a, b)
|
|
Vector3Dot(a, b), Vector3Cross(a, b)
|
|
Vector3Lerp(a, b, t) |
Not clamped. |
Vector3MoveTowards(current, target, maxDistance) |
Never overshoots. |
Vector3Angle(from, to) |
Unsigned angle in degrees, 0..180. |
Vector3Reflect(v, normal) |
normal should have length 1. |
Vector3Project(v, onto) |
|
Vector3ProjectOnPlane(v, planeNormal) |
v with the part along planeNormal removed. |
Vector3ClampLength(v, maxLength) |
|
Vector3Min(a, b), Vector3Max(a, b)
|
Per component. |
-- Fly toward a target at a steady speed.
local pos = entity.transform.position
entity.transform.position = mathT.Vector3MoveTowards(pos, target, speed * GameTime.deltaTime)| Function | |
|---|---|
Vector4Add(a, b), Vector4Sub(a, b)
|
|
Vector4Mul(a, b) |
Per component, e.g. tinting a colour. |
Vector4Scale(v, s) |
|
Vector4Lerp(a, b, t) |
Fading between two colours. Not clamped. |
-- Fade a sprite from white to red over one second.
local t = mathT.Clamp01(timer)
entity.sprite.color = mathT.Vector4Lerp(Vector4(1, 1, 1, 1), Vector4(1, 0, 0, 1), t)