Skip to content

Vector2F

Generated from engine/math/vector2f.h at 862e08b. The text under each declaration is the header's own comment, word for word. About the reference says how these pages are made.

Browse the math module

#include "engine/math/vector2f.h" · namespace mattmath

struct Vector2F
float x = 0.0f;
float y = 0.0f;
Vector2F() = default;
Vector2F(const Vector2F&) = default;
constexpr explicit Vector2F(float f);
constexpr Vector2F(float x, float y);
explicit Vector2F(const mattmath::Vector2I& vector);

explicit, all of them. A float is not a vector, a Vector2I is not a Vector2F, and a RectangleF is not a Quad - and an implicit conversion is one the compiler inserts silently, even at /W4 /WX. Two of the Quad forms end in a throw, so a wrong-typed argument would become a runtime exception from inside the callee with no conversion visible at the call site.

constexpr and defined here, the two that take only floats, so the constants at the bottom of this struct are constant-initialised: see them for what that buys.

bool operator==(const Vector2F& other) const;
bool operator!=(const Vector2F& other) const;

operator+= · operator-= · operator*= · operator/=

Section titled “operator+= · operator-= · operator*= · operator/=”
Vector2F& operator+=(const Vector2F& other);
Vector2F& operator-=(const Vector2F& other);
Vector2F& operator*=(const Vector2F& other);
Vector2F& operator/=(const Vector2F& other);
Vector2F& operator*=(float other);
Vector2F& operator/=(float other);
float length() const;
float length_squared() const;
float dot(const Vector2F& other) const;
Vector2F normalized() const;
void normalize();

Zero-length in, zero-length out. A zero vector has no direction, and returning zero lets the caller detect that; dividing by the length would produce NaN, which would then propagate silently through velocities and shape validation.

Note this is deliberately NOT the same contract as to_unit_vector() and unit_vector(), which substitute (1, 0) for a zero vector. Use those only where an arbitrary direction is acceptable.

void clamp(const Vector2F& min, const Vector2F& max);
Vector2F clamped(const Vector2F& min, const Vector2F& max) const;
float angle() const;
static float angle(const Vector2F& vec);
void to_unit_vector();

Substitutes (1, 0) for a zero-length vector - i.e. it invents a direction rather than reporting that there is none. See normalize().

static float angle_between(const Vector2F& a, const Vector2F& b);
static Vector2F lerp(const Vector2F& a, const Vector2F& b, float t);
static Vector2F lerp(const Vector2F& a, const Vector2F& b, const Vector2F& t);
static float distance(const Vector2F& a, const Vector2F& b);
static float distance_squared(const Vector2F& a, const Vector2F& b);
static float dot(const Vector2F& a, const Vector2F& b);
static float cross(const Vector2F& a, const Vector2F& b);

The 2D cross product: a scalar, not a vector. In three dimensions the cross product of two vectors is the third axis; in two there is no third axis, and what survives is its signed length, a.x * b.y - a.y * b.x.

It is the signed area of the parallelogram a and b span, so its magnitude measures how far from parallel they are - the exact counterpart of dot() measuring how far from perpendicular. Its sign is the orientation test: positive when b lies counter-clockwise of a, negative when clockwise, and zero when the two are parallel, which is the only reliable way to ask that question.

Comparing three points is this on their differences: cross(b - a, c - a) is twice the signed area of triangle abc, and is positive exactly when abc winds counter-clockwise. That composite is Ericson's ORIENT2D; ericson_math.h spells it signed_2D_tri_area.

Beware the y-down screen convention: "counter-clockwise" above is stated in maths axes. On screen, where y grows downward, a positive result reads as clockwise. The sign is consistent either way - it is the word that flips.

static Vector2F unit_vec_from_angle(float angle);
static Vector2F rotate_vector(const Vector2F& vec, float angle);

vec turned by angle radians about the origin.

Counter-clockwise in maths axes, which reads as clockwise on a screen where y grows downward - the same word that flips in cross()'s note above, and for the same reason. The sign is consistent either way.

It is the general case of normal(), which is this at PI_OVER_2 and exact where this is not: cos(PI/2) is not zero in floating point, so rotating (1, 0) by a right angle lands a few ulps off the y axis. Where a right angle is what is wanted, want normal().

HERE WHATEVER ITS CALL COUNT. A 2D vector that answers angle(), unit_vec_from_angle() and normal() and cannot turn a vector has a hole in it, and a game fills that hole with a second definition of engine arithmetic, living outside the engine's tests.

static Vector2F unit_vector(const Vector2F& vec);

Returns (1, 0) for a zero-length vector. See to_unit_vector().

static Vector2F normal(const Vector2F& vec);

ZERO · ONE · DIRECTION_RIGHT · DIRECTION_DOWN · DIRECTION_LEFT · DIRECTION_UP · DIRECTION_UP_RIGHT · DIRECTION_DOWN_RIGHT · DIRECTION_DOWN_LEFT · DIRECTION_UP_LEFT

Section titled “ZERO · ONE · DIRECTION_RIGHT · DIRECTION_DOWN · DIRECTION_LEFT · DIRECTION_UP · DIRECTION_UP_RIGHT · DIRECTION_DOWN_RIGHT · DIRECTION_DOWN_LEFT · DIRECTION_UP_LEFT”
static const Vector2F ZERO;
static const Vector2F ONE;
static const Vector2F DIRECTION_RIGHT;
static const Vector2F DIRECTION_DOWN;
static const Vector2F DIRECTION_LEFT;
static const Vector2F DIRECTION_UP;
static const Vector2F DIRECTION_UP_RIGHT;
static const Vector2F DIRECTION_DOWN_RIGHT;
static const Vector2F DIRECTION_DOWN_LEFT;
static const Vector2F DIRECTION_UP_LEFT;

CONSTANT-INITIALISED, and the definitions say constinit so that the compiler refuses if that ever stops being true. Dynamically initialised, a namespace-scope object in any other translation unit that copied one - a game's own direction table, a default in a static - would read (0, 0) or the real value depending on link order, with no error anywhere.

typedef Vector2F Point2F;

A point and a vector are the same two floats, and the library says so. The name is here rather than beside a forward declaration because this is the type it names.

Vector2F operator- (const Vector2F& V);

Reversing a direction. The collision module does this constantly - a contact normal points from the first shape to the second, so the second needs the other one.

operator+ · operator- · operator* · operator/

Section titled “operator+ · operator- · operator* · operator/”
Vector2F operator+ (const Vector2F& V1, const Vector2F& V2);
Vector2F operator- (const Vector2F& V1, const Vector2F& V2);
Vector2F operator* (const Vector2F& V1, const Vector2F& V2);
Vector2F operator* (const Vector2F& V, float S);
Vector2F operator/ (const Vector2F& V1, const Vector2F& V2);
Vector2F operator/ (const Vector2F& V, float S);
Vector2F operator* (float S, const Vector2F& V);

Named in the public declarations above: Vector2I.

The files that include this header directly. A file can also reach it through another header.

Development documentation (unreleased). Built from Labrador 862e08b of 2026-10-08.