Maths and types¶
types/point.hpp, types/size.hpp, types/rect.hpp, types/vec2.hpp, types/vec3.hpp, types/mat3.hpp, types/mat4.hpp, math/constants.hpp, math/interpolation.hpp
Whole-pixel types (Point, Size, Rect) are for drawing; float types (Vec2, Vec3) are for movement and physics. Convert with Point(vec) when you draw.
Point¶
struct Point {
int32_t x = 0, y = 0;
Point() = default;
constexpr Point(int32_t x, int32_t y);
constexpr Point(Vec2 v); // truncates towards zero
explicit constexpr operator Vec2() const;
};
A pixel position. Points convert from Vec2 automatically (the fractions are dropped), so you can pass a Vec2 wherever drawing functions want a Point. Converting the other way needs Vec2(p).
| Operator | Result |
|---|---|
p + q, p - q, -p |
component-wise |
p * f |
both components multiplied by the float f, truncated |
p / n |
both divided by the integer n (integer division) |
p * m |
transformed by the Mat3 m |
p == q, p != q |
compare |
+=, -=, *= and /= work the same way in place.
Size¶
struct Size {
int32_t w = 0, h = 0;
Size() = default;
constexpr Size(int32_t w, int32_t h);
constexpr bool empty() const; // w <= 0 or h <= 0
constexpr int32_t area() const; // w * h
constexpr bool contains(const Point &p) const; // 0 <= x < w and 0 <= y < h
};
A width and height. Supports * and / by an int or a float, and ==/!=. screen.bounds is a Size.
Rect¶
struct Rect {
int32_t x = 0, y = 0, w = 0, h = 0;
Rect() = default;
constexpr Rect(int32_t x, int32_t y, int32_t w, int32_t h);
constexpr Rect(Point tl, Size s);
constexpr Rect(Point tl, Point br); // br is one past the bottom-right pixel
};
A rectangle by its top-left corner and size. It covers the pixels from x to x + w - 1 and y to y + h - 1.
| Member | Returns |
|---|---|
size() |
Size(w, h) |
empty() |
true if w or h is 0 or less |
contains(Point p) |
true if p is one of the rectangle's pixels |
contains(Rect r) |
true if r is inside, not touching the right or bottom edge |
intersects(Rect r) |
true if the rectangles overlap or touch (see below) |
intersection(Rect r) |
the overlapping rectangle; check empty() on the result, because rectangles that don't overlap give a negative size |
inflate(v), deflate(v) |
grow or shrink by v on every side, in place |
clamp(Point p) |
the nearest point to p from x..x + w, y..y + h |
tl() |
Point(x, y) |
tr(), bl(), br() |
Point(x + w, y), Point(x, y + h), Point(x + w, y + h): one past the last pixel |
center() |
Point(x + w/2, y + h/2) |
Rect * f scales all four fields; == and != compare.
intersects() counts rectangles that only share an edge as intersecting: Rect(0, 0, 8, 8) and Rect(8, 0, 8, 8) intersect, though no pixel is in both. That's usually harmless for game collisions. For a strict pixel overlap, use !a.intersection(b).empty().
Vec2¶
struct Vec2 {
float x, y;
explicit constexpr Vec2(float x = 0, float y = 0);
float length();
void normalize(); // makes length 1, in place
float dot(const Vec2 &a);
float cross(const Vec2 &a); // x * a.y - y * a.x
void rotate(float radians); // in place
float angle(Vec2 o); // signed angle from this to o, radians
float angle_to(Vec2 o); // direction of (this - o), radians
void transform(const Mat3 &m); // in place
static Vec2 normalize(Vec2 &v); // normalizes v in place and returns it
};
A 2D vector of floats for positions, velocities and directions.
- Operators:
+,-, unary-;* float,/ float;* Vec2and/ Vec2(component-wise);* Mat3(transform), and the in-place forms. - The constructor is
explicit, so writeVec2(1, 2), not{1, 2}, when passing or assigning one. normalize()divides by the length, so a zero vector becomes NaN. Check the length first:
Vec2 dir(0, 0);
if(buttons & Button::DPAD_LEFT) dir.x -= 1;
if(buttons & Button::DPAD_RIGHT) dir.x += 1;
if(buttons & Button::DPAD_UP) dir.y -= 1;
if(buttons & Button::DPAD_DOWN) dir.y += 1;
if(dir.length() > 0) {
dir.normalize(); // diagonals no faster than straight lines
player += dir * speed;
}
rotate()andMat3::rotation()use radians, clockwise on screen, because y points down.angle_to(o)is the direction pointing fromoto this vector. To aim fromaatb, useb.angle_to(a), oratan2f(b.y - a.y, b.x - a.x).
Mat3¶
struct Mat3 {
float v00, v01, v02;
float v10, v11, v12;
float v20, v21, v22;
Mat3(); // all zeros, not identity
static Mat3 identity();
static Mat3 rotation(float radians);
static Mat3 translation(Vec2 v);
static Mat3 scale(Vec2 v);
void inverse(); // in place
};
A 3×3 matrix for 2D transforms: used for tile map drawing and for transforming points and vectors.
Warning
Mat3() is all zeros. Start from Mat3::identity() or one of the other constructors.
Combining transforms¶
m1 * m2 multiplies matrices, and v * m transforms a vector or point by m. In a product, the rightmost matrix is applied first:
// rotate around (64, 64): move it to the origin, rotate, move it back
Mat3 m = Mat3::translation(Vec2(64, 64))
* Mat3::rotation(angle)
* Mat3::translation(Vec2(-64, -64));
Vec2 p = Vec2(100, 64) * m;
v * m1 * m2 is different: it applies m1 first, then m2, because it's (v * m1) * m2.
inverse() turns a transform into the one that undoes it, for example to turn a tile map's screen-to-world transform into world-to-screen for drawing sprites on the map.
Vec3 and Mat4¶
struct Vec3 {
float x, y, z;
constexpr Vec3(float x = 0, float y = 0, float z = 0);
float length();
void normalize();
Vec3 cross(const Vec3 &a);
float dot(const Vec3 &a);
void transform(const Mat4 &m); // with perspective divide
};
struct Mat4 {
float v00 ... v33;
Mat4(); // all zeros
static Mat4 identity();
static Mat4 rotation(float degrees, Vec3 axis);
static Mat4 translation(Vec3 v);
static Mat4 scale(Vec3 v);
void inverse();
};
The 3D versions, for simple 3D effects such as rotating wireframes or star fields. The operators match Vec2 and Mat3.
Note
Mat4::rotation takes its angle in degrees, unlike Mat3::rotation and Vec2::rotate, which use radians.
transform() divides by the resulting w, so a projection matrix gives screen-space coordinates directly.
Constants and interpolation¶
Use pi for angles: pi * 2 is a full turn, pi / 180 converts degrees to radians.
The lerp() functions are described on the timers and tweens page. Note that the float and Vec2 three-argument forms do opposite things.