# tecs.math.vec2 Allocation-free two-dimensional vector and point math. `vec2` takes separate coordinates and returns multiple values, so a system can update an archetype column without allocating vector objects: ```teal local record Homing is tecs.ecs.Component targetX: number targetY: number speed: number end tecs.ecs.newFFIComponent({ name = "Homing", container = Homing, fields = { {"targetX", "float"}, {"targetY", "float"}, {"speed", "float"}, }, }) return tecs.newApplication({ plugin = function(world: tecs.World) local homing = world:newQuery({ include = {tecs.Transform2D, Homing}, }) world:addSystem({ name = "game.Homing", phase = tecs.ecs.phases.Update, run = function(dt: number) for archetype, length in homing:iter() do local transforms = archetype:getMut( tecs.Transform2D ) local targets = archetype:get(Homing) for row = 1, length do local transform = transforms[row] local target = targets[row] transform.x, transform.y = tecs.math.vec2.moveTowards( transform.x, transform.y, target.targetX, target.targetY, target.speed * dt ) transform.rotation = tecs.math.vec2.angle( target.targetX - transform.x, target.targetY - transform.y ) end end end, }) end, }) ``` The writable [`Transform2D`](/modules/ecs/#tecs.ecs.Transform2D) column comes from `getMut`; the read-only target column comes from `get`. Taking both through `getMut` would dirty `Homing` every frame and defeat consumers that skip clean columns. ## Coordinates and boundaries Every angle uses radians. A positive quarter turn maps `(1, 0)` to `(0, 1)`, which appears clockwise when screen y grows downward. Operations without a unique geometric answer return stable values. `normalize(0, 0)`, either angle-between function with a zero vector, and `project` onto a zero axis return zero. `reflect` with a zero normal returns the original vector. `lerp` does not clamp, and `moveTowards` never overshoots. ## Module contents ### Functions | Function | Kind | Description | | --- | --- | --- | | [`add`](/modules/math/vec2/#tecs.math.vec2.add) | Static | Adds two vectors. | | [`angle`](/modules/math/vec2/#tecs.math.vec2.angle) | Static | Computes a vector's direction. | | [`angleBetween`](/modules/math/vec2/#tecs.math.vec2.angleBetween) | Static | Computes the smaller unsigned angle between two vectors. | | [`cross`](/modules/math/vec2/#tecs.math.vec2.cross) | Static | Computes the scalar two-dimensional cross product. | | [`distance`](/modules/math/vec2/#tecs.math.vec2.distance) | Static | Computes the distance between two points. | | [`distanceSquared`](/modules/math/vec2/#tecs.math.vec2.distanceSquared) | Static | Computes squared distance without taking a square root. | | [`dot`](/modules/math/vec2/#tecs.math.vec2.dot) | Static | Computes the dot product of two vectors. | | [`length`](/modules/math/vec2/#tecs.math.vec2.length) | Static | Computes vector length. | | [`lengthSquared`](/modules/math/vec2/#tecs.math.vec2.lengthSquared) | Static | Computes squared vector length without taking a square root. | | [`lerp`](/modules/math/vec2/#tecs.math.vec2.lerp) | Static | Interpolates linearly between two points. | | [`moveTowards`](/modules/math/vec2/#tecs.math.vec2.moveTowards) | Static | Moves a point toward another by at most a given distance. | | [`normalize`](/modules/math/vec2/#tecs.math.vec2.normalize) | Static | Produces a unit vector in the same direction. | | [`project`](/modules/math/vec2/#tecs.math.vec2.project) | Static | Projects a vector onto another vector. | | [`reflect`](/modules/math/vec2/#tecs.math.vec2.reflect) | Static | Reflects a vector across the line perpendicular to a normal. | | [`rotate`](/modules/math/vec2/#tecs.math.vec2.rotate) | Static | Rotates a vector around the origin. | | [`scale`](/modules/math/vec2/#tecs.math.vec2.scale) | Static | Multiplies both coordinates by a scalar. | | [`signedAngleBetween`](/modules/math/vec2/#tecs.math.vec2.signedAngleBetween) | Static | Computes the smaller signed angle from one vector to another. | | [`subtract`](/modules/math/vec2/#tecs.math.vec2.subtract) | Static | Subtracts the second vector from the first. | ## Functions ### tecs.math.vec2.add Static Adds two vectors. ```teal function tecs.math.vec2.add( ax: number, ay: number, bx: number, by: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First vector's x coordinate. | | `ay` | `number` | First vector's y coordinate. | | `bx` | `number` | Second vector's x coordinate. | | `by` | `number` | Second vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The sum's x coordinate. | | `number` | The sum's y coordinate. | #### Examples Combines a position with a per-frame velocity step. ```teal local x, y = tecs.math.vec2.add(1, 2, 3, 4) assert(x == 4 and y == 6) ``` ### tecs.math.vec2.angle Static Computes a vector's direction. ```teal function tecs.math.vec2.angle(x: number, y: number): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | `atan2(y, x)` in `[-pi, pi]`. A zero vector returns zero. | #### Examples Converts a direction into a rotation for a sprite. ```teal assert(tecs.math.vec2.angle(0, 1) == math.pi / 2) ``` ### tecs.math.vec2.angleBetween Static Computes the smaller unsigned angle between two vectors. ```teal function tecs.math.vec2.angleBetween( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First vector's x coordinate. | | `ay` | `number` | First vector's y coordinate. | | `bx` | `number` | Second vector's x coordinate. | | `by` | `number` | Second vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | Radians in `[0, pi]`. If either vector is zero, returns zero. | #### Examples Measures the unsigned separation of two facing directions. ```teal assert(tecs.math.vec2.angleBetween(1, 0, 0, 1) == math.pi / 2) ``` ### tecs.math.vec2.cross Static Computes the scalar two-dimensional cross product. ```teal function tecs.math.vec2.cross( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First vector's x coordinate. | | `ay` | `number` | First vector's y coordinate. | | `bx` | `number` | Second vector's x coordinate. | | `by` | `number` | Second vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | `ax * by - ay * bx`; positive puts the second vector on the positive rotation side of the first. | #### Examples Determines which side of a direction another vector lies on. ```teal assert(tecs.math.vec2.cross(1, 0, 0, 1) == 1) ``` ### tecs.math.vec2.distance Static Computes the distance between two points. ```teal function tecs.math.vec2.distance( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First point's x coordinate. | | `ay` | `number` | First point's y coordinate. | | `bx` | `number` | Second point's x coordinate. | | `by` | `number` | Second point's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The nonnegative Euclidean distance between the points. | #### Examples Measures how far apart two positions are. ```teal assert(tecs.math.vec2.distance(1, 2, 4, 6) == 5) ``` ### tecs.math.vec2.distanceSquared Static Computes squared distance without taking a square root. Prefer this to `distance` for radius tests. ```teal function tecs.math.vec2.distanceSquared( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First point's x coordinate. | | `ay` | `number` | First point's y coordinate. | | `bx` | `number` | Second point's x coordinate. | | `by` | `number` | Second point's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The squared Euclidean distance between the points. | #### Examples Tests whether a target lies inside a radius without a square root. ```teal assert(tecs.math.vec2.distanceSquared(1, 2, 4, 6) == 25) ``` ### tecs.math.vec2.dot Static Computes the dot product of two vectors. ```teal function tecs.math.vec2.dot( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First vector's x coordinate. | | `ay` | `number` | First vector's y coordinate. | | `bx` | `number` | Second vector's x coordinate. | | `by` | `number` | Second vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | `ax * bx + ay * by`. | #### Examples Tests how closely two directions face each other. ```teal assert(tecs.math.vec2.dot(2, 3, 4, 5) == 23) ``` ### tecs.math.vec2.length Static Computes vector length. ```teal function tecs.math.vec2.length(x: number, y: number): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The nonnegative Euclidean length. | #### Examples Measures a velocity's speed. ```teal assert(tecs.math.vec2.length(3, 4) == 5) ``` ### tecs.math.vec2.lengthSquared Static Computes squared vector length without taking a square root. Prefer this to `length` when comparing magnitudes: compare the answer with the other distance squared, such as `radius * radius`. ```teal function tecs.math.vec2.lengthSquared(x: number, y: number): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | `x * x + y * y`. | #### Examples Compares speed without taking a square root. ```teal assert(tecs.math.vec2.lengthSquared(3, 4) == 25) ``` ### tecs.math.vec2.lerp Static Interpolates linearly between two points. ```teal function tecs.math.vec2.lerp( ax: number, ay: number, bx: number, by: number, t: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | Starting point's x coordinate. | | `ay` | `number` | Starting point's y coordinate. | | `bx` | `number` | Destination point's x coordinate. | | `by` | `number` | Destination point's y coordinate. | | `t` | `number` | Unclamped interpolation amount. Zero returns the start, one returns the destination, and values outside that interval extrapolate. | #### Returns | Type | Description | | --- | --- | | `number` | The interpolated x coordinate. | | `number` | The interpolated y coordinate. | #### Examples Blends halfway between two positions. ```teal local x, y = tecs.math.vec2.lerp(2, 4, 6, 8, 0.5) assert(x == 4 and y == 6) ``` ### tecs.math.vec2.moveTowards Static Moves a point toward another by at most a given distance. A frame-rate-independent chase passes the speed for this frame: ```teal function tecs.math.vec2.moveTowards( x: number, y: number, targetX: number, targetY: number, maxDistance: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Starting point's x coordinate. | | `y` | `number` | Starting point's y coordinate. | | `targetX` | `number` | Destination point's x coordinate. | | `targetY` | `number` | Destination point's y coordinate. | | `maxDistance` | `number` | Greatest distance to travel. A nonpositive value leaves the starting point unchanged. | #### Returns | Type | Description | | --- | --- | | `number` | The moved x coordinate. Reaching the destination returns it exactly and never overshoots. | | `number` | The moved y coordinate, with the same endpoint rule. | #### Examples Moves toward a target without overshooting it. ```teal local x, y = tecs.math.vec2.moveTowards(0, 0, 3, 4, 2) assert(x == 1.2 and y == 1.6) ``` ### tecs.math.vec2.normalize Static Produces a unit vector in the same direction. ```teal function tecs.math.vec2.normalize(x: number, y: number): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The normalized x coordinate. A zero vector returns zero because it has no direction. | | `number` | The normalized y coordinate, with the same zero-vector rule. | #### Examples Builds a unit direction toward a target. ```teal local x, y = tecs.math.vec2.normalize(3, 4) assert(x == 0.6 and y == 0.8) ``` ### tecs.math.vec2.project Static Projects a vector onto another vector. The projection axis may have any length: ```teal function tecs.math.vec2.project( x: number, y: number, ontoX: number, ontoY: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | The vector's x coordinate. | | `y` | `number` | The vector's y coordinate. | | `ontoX` | `number` | Projection axis's x coordinate. | | `ontoY` | `number` | Projection axis's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The projected x coordinate. The axis may have any length; a zero axis returns zero. | | `number` | The projected y coordinate, with the same zero-axis rule. | #### Examples Keeps only the component of a velocity along an axis. ```teal local x, y = tecs.math.vec2.project(3, 4, 1, 0) assert(x == 3 and y == 0) ``` ### tecs.math.vec2.reflect Static Reflects a vector across the line perpendicular to a normal. The normal may have any length: ```teal function tecs.math.vec2.reflect( x: number, y: number, normalX: number, normalY: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | The vector's x coordinate. | | `y` | `number` | The vector's y coordinate. | | `normalX` | `number` | Surface normal's x coordinate. | | `normalY` | `number` | Surface normal's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The reflected x coordinate. The normal may have any length; a zero normal returns the original x coordinate. | | `number` | The reflected y coordinate, with the same zero-normal rule. | #### Examples Bounces a velocity from a surface normal. ```teal local x, y = tecs.math.vec2.reflect(1, -1, 0, 1) assert(x == 1 and y == 1) ``` ### tecs.math.vec2.rotate Static Rotates a vector around the origin. ```teal function tecs.math.vec2.rotate( x: number, y: number, radians: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | | `radians` | `number` | Rotation in radians. A positive quarter turn maps `(1, 0)` to `(0, 1)`. | #### Returns | Type | Description | | --- | --- | | `number` | The rotated x coordinate. | | `number` | The rotated y coordinate. | #### Examples Rotates a facing direction by a quarter turn. ```teal local x, y = tecs.math.vec2.rotate(1, 0, math.pi / 2) assert(math.abs(x) < 0.000001 and math.abs(y - 1) < 0.000001) ``` ### tecs.math.vec2.scale Static Multiplies both coordinates by a scalar. ```teal function tecs.math.vec2.scale( x: number, y: number, factor: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `x` | `number` | Vector's x coordinate. | | `y` | `number` | Vector's y coordinate. | | `factor` | `number` | Multiplier applied to both coordinates. | #### Returns | Type | Description | | --- | --- | | `number` | The scaled x coordinate. | | `number` | The scaled y coordinate. | #### Examples Turns a unit direction into a movement step. ```teal local x, y = tecs.math.vec2.scale(2, 3, 4) assert(x == 8 and y == 12) ``` ### tecs.math.vec2.signedAngleBetween Static Computes the smaller signed angle from one vector to another. Use the answer directly as the shortest directional correction: ```teal function tecs.math.vec2.signedAngleBetween( ax: number, ay: number, bx: number, by: number ): number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | Starting vector's x coordinate. | | `ay` | `number` | Starting vector's y coordinate. | | `bx` | `number` | Destination vector's x coordinate. | | `by` | `number` | Destination vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | Radians in `[-pi, pi)`, positive in the same sense as `rotate`. If either vector is zero, returns zero; an exact half-turn is negative pi. | #### Examples Chooses the shortest directional correction toward a target. ```teal assert(tecs.math.vec2.signedAngleBetween(1, 0, 0, 1) == math.pi / 2) ``` ### tecs.math.vec2.subtract Static Subtracts the second vector from the first. ```teal function tecs.math.vec2.subtract( ax: number, ay: number, bx: number, by: number ): number, number ``` #### Arguments | Name | Type | Description | | --- | --- | --- | | `ax` | `number` | First vector's x coordinate. | | `ay` | `number` | First vector's y coordinate. | | `bx` | `number` | Second vector's x coordinate. | | `by` | `number` | Second vector's y coordinate. | #### Returns | Type | Description | | --- | --- | | `number` | The difference's x coordinate. | | `number` | The difference's y coordinate. | #### Examples Finds the offset from a position to a target. ```teal local x, y = tecs.math.vec2.subtract(5, 4, 1, 2) assert(x == 4 and y == 2) ```