pixijs-math

Par pixijs · pixijs-skills

Utilisez cette skill lorsque vous travaillez avec des coordonnées, des vecteurs, des matrices, des formes, des tests de collision ou des rectangles de mise en page dans PixiJS v8. Couvre Point/ObservablePoint, Matrix (affine 2D, décomposition, apply, applyInverse), les formes (Rectangle, Circle, Ellipse, Polygon, RoundedRectangle, Triangle), les helpers de mise en page Rectangle (pad, fit, enlarge, ceil, scale, getBounds), les tests de collision strokeContains, Polygon isClockwise/containsPolygon, toGlobal/toLocal, les types PointData/PointLike/Size, DEG_TO_RAD, ainsi que les helpers vectoriels et d'intersection de pixi.js/math-extras. Se déclenche sur : Point, ObservablePoint, Matrix, Rectangle, Circle, Polygon, Triangle, RoundedRectangle, toGlobal, toLocal, hitArea, strokeContains, pad, fit, enlarge, ceil, getBounds, containsRect, intersects, isClockwise, math-extras, lineIntersection, segmentIntersection, DEG_TO_RAD, PointData.

npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-math

PixiJS expose des primitives mathématiques légères (Point, Matrix, classes de formes) utilisées dans la bibliothèque pour les transformations, les tests de collision et la conversion de coordonnées. Importez pixi.js/math-extras pour ajouter des opérations vectorielles (add, dot, magnitude, reflect) et des helpers d'intersection/union de Rectangle.

Démarrage rapide

const parent = new Container();
parent.position.set(100, 100);
parent.scale.set(2);
app.stage.addChild(parent);

const child = new Container();
child.position.set(50, 50);
parent.addChild(child);

const globalPt = child.toGlobal(new Point(0, 0));

const m = new Matrix()
  .translate(100, 50)
  .rotate(Math.PI / 4)
  .scale(2, 2);
const world = m.apply(new Point(10, 20));

const hitArea = new Rectangle(0, 0, 200, 100);
console.log(hitArea.contains(50, 50));

Skills liées : pixijs-scene-container (propriétés de transformation), pixijs-events (utilisation de hitArea), pixijs-scene-core-concepts (culling avec Rectangle).

Modèles principaux

Point et ObservablePoint

Point est un simple type {x, y}. ObservablePoint déclenche un callback quand x ou y change ; il est utilisé en interne par les propriétés position, scale, pivot, origin et skew d'un Container.

import { Point } from "pixi.js";

const p = new Point(10, 20);
p.set(30, 40); // définir les deux
p.set(50); // x=50, y=50

const clone = p.clone();
console.log(p.equals(clone)); // true

p.copyFrom({ x: 1, y: 2 }); // accepte tout PointData

// Point.shared : point temporaire, réinitialisé à (0,0) à chaque accès
const temp = Point.shared;
temp.set(100, 200);
// ne pas conserver de référence à Point.shared

Les propriétés d'un Container comme position, scale, pivot, origin et skew sont des ObservablePoints. Définir .x ou .y sur eux déclenche automatiquement le recalcul de la transformation.

import { Container } from "pixi.js";

const obj = new Container();
obj.position.set(100, 200); // déclenche l'observateur -> marque la transformation comme dirty
obj.position.x = 150; // déclenche aussi l'observateur

Matrix (transformation affine 2D)

Matrix représente une transformation affine 3x3 : | a c tx | b d ty | 0 0 1 |. Elle supporte translate, scale, rotate, append, prepend, invert et decompose.

import { Matrix, Point } from "pixi.js";

// Construire une transformation
const m = new Matrix()
  .translate(100, 50)
  .rotate(Math.PI / 4)
  .scale(2, 2);

// Transformer un point (espace local -> espace parent)
const local = new Point(10, 20);
const world = m.apply(local);

// Transformer inversement (espace parent -> espace local)
const backToLocal = m.applyInverse(world);

// Combiner des matrices
const a = new Matrix().translate(50, 0);
const b = new Matrix().rotate(Math.PI / 2);
a.append(b); // a = a * b

// Décomposer en position/scale/rotation/skew
const transform = {
  position: new Point(),
  scale: new Point(),
  pivot: new Point(),
  skew: new Point(),
  rotation: 0,
};
m.decompose(transform);
console.log(transform.rotation); // ~0.785 (PI/4)

// Matrice temporaire partagée (réinitialisée à chaque accès)
const temp = Matrix.shared;
// IDENTITY est une référence en lecture seule
const isDefault = m.equals(Matrix.IDENTITY);

Transformations de coordonnées via Container

Les Containers fournissent toGlobal, toLocal et getGlobalPosition pour la conversion de coordonnées.

import { Container, Point } from "pixi.js";

const parent = new Container();
parent.position.set(100, 100);
parent.scale.set(2);

const child = new Container();
child.position.set(50, 50);
parent.addChild(child);

// Point local dans l'espace du child -> espace global (monde)
const globalPt = child.toGlobal(new Point(0, 0));
// globalPt = { x: 200, y: 200 } (100 + 50*2, 100 + 50*2)

// Point global -> espace local du child
const localPt = child.toLocal(new Point(200, 200));
// localPt = { x: 0, y: 0 }

// Convertir entre deux containers
const other = new Container();
other.position.set(300, 300);
const ptInOther = child.toLocal(new Point(10, 10), other);

Formes et tests de collision

Rectangle, Circle, Ellipse, Polygon, RoundedRectangle et Triangle implémentent tous contains(x, y) pour les tests point-in-shape, plus getBounds(out?) et strokeContains(x, y, width, alignment?). Ils peuvent être utilisés comme hitArea sur des containers pour les régions d'interaction personnalisées.

import { Rectangle, Circle, Polygon, Container } from "pixi.js";

const rect = new Rectangle(0, 0, 200, 100);
rect.contains(50, 50); // true
rect.contains(300, 50); // false
rect.left; // 0
rect.right; // 200
rect.top; // 0
rect.bottom; // 100
rect.isEmpty(); // false (Rectangle.EMPTY retourne un nouveau rectangle vide)

// Méthodes natives Rectangle-to-Rectangle (pas besoin de math-extras)
const other = new Rectangle(50, 50, 100, 100);
rect.containsRect(other); // true si `other` est complètement à l'intérieur de `rect`
rect.intersects(other); // booléen : se chevauchent-ils ?
rect.intersects(other, matrix); // chevauchement après transformation de `other`

// Test de collision sur le contour (alignment: 1 = intérieur, 0.5 = centré, 0 = extérieur)
rect.strokeContains(0, 50, 4); // true si (0,50) se trouve sur un contour de 4px centré
const circle = new Circle(100, 100, 50);
circle.strokeContains(150, 100, 4, 1); // vérification du contour aligné intérieurement

// getBounds fonctionne sur chaque forme (retourne un Rectangle, accepte un paramètre out)
const bounds = circle.getBounds();
const reused = new Rectangle();
new Polygon([0, 0, 100, 0, 50, 100]).getBounds(reused);

// Utiliser comme zone d'interaction
const button = new Container();
button.hitArea = new Rectangle(0, 0, 200, 50);
button.eventMode = "static";
button.on("pointerdown", () => {
  /* cliqué */
});

Ne confondez pas la méthode native Rectangle.intersects(other) (retourne boolean) avec intersection(other) de math-extras (retourne un Rectangle décrivant la zone de chevauchement).

Helpers de disposition Rectangle

Rectangle est fourni avec des helpers mutants utilisés massivement en UI/layout, agrégation de limites et pixel snapping. Tous retournent this pour le chaînage.

import { Rectangle } from "pixi.js";

const r = new Rectangle(10, 10, 100, 50);

r.pad(5); // agrandir de tous les côtés : x=5, y=5, w=110, h=60
r.pad(10, 4); // padding horizontal/vertical séparé
r.scale(2); // multiplier x, y, width, height par 2

// fit rétrécit `this` pour qu'il se trouve à l'intérieur d'un autre rectangle (clipping)
const viewport = new Rectangle(0, 0, 200, 200);
new Rectangle(150, 150, 200, 200).fit(viewport); // -> 150, 150, 50, 50

// enlarge agrandit `this` pour inclure un autre rectangle (agrégation de limites)
const total = new Rectangle();
items.forEach((item) =>
  total.enlarge(new Rectangle().copyFromBounds(item.getBounds())),
);

// ceil accroche à une grille de pixels (resolution: 1 = pixels entiers, 2 = demi-pixels)
new Rectangle(10.2, 10.6, 100.8, 100.4).ceil();

// copier directement les limites d'un Container/Mesh dans un Rectangle
new Rectangle().copyFromBounds(container.getBounds());

Polygon

Polygon accepte quatre formats de constructeur : un tableau de nombres plat, un tableau d'objets de type point, ou l'un ou l'autre passé en arguments spread.

import { Polygon, Point } from "pixi.js";

new Polygon([0, 0, 100, 0, 50, 100]); // nombres plats
new Polygon([new Point(0, 0), new Point(100, 0), new Point(50, 100)]); // PointData[]
new Polygon(0, 0, 100, 0, 50, 100); // nombres spread
new Polygon(new Point(0, 0), new Point(100, 0), new Point(50, 100)); // points spread

const poly = new Polygon([0, 0, 100, 0, 100, 100, 0, 100]);
poly.points; // [0, 0, 100, 0, 100, 100, 0, 100] (tableau plat mutable)
poly.closePath; // true par défaut ; false produit un chemin ouvert
poly.startX; // 0  - premier vertex
poly.lastX; // 0  - dernier vertex (lastY pour y)
poly.isClockwise(); // test d'enroulement shoelace (utile pour la détection de trous SVG)

// Contenance polygon-in-polygon pour la détection de trous
const outer = new Polygon([0, 0, 100, 0, 100, 100, 0, 100]);
const hole = new Polygon([25, 25, 75, 25, 75, 75, 25, 75]);
outer.containsPolygon(hole); // true

Constantes

import { DEG_TO_RAD, RAD_TO_DEG, PI_2 } from "pixi.js";

const angle = 45 * DEG_TO_RAD; // 0.785...
const degrees = angle * RAD_TO_DEG; // 45
const fullCircle = PI_2; // Math.PI * 2

Types

  • PointData - interface minimale {x, y} acceptée par la plupart des APIs. Utilisez-la quand vous typez des paramètres qui n'ont besoin que de lire les coordonnées.
  • PointLike - étend PointData avec set(), copyFrom(), copyTo(), equals(). Implémenté par Point et ObservablePoint.
  • Size - interface { width, height } utilisée par les APIs renderer/canvas.
  • SHAPE_PRIMITIVE - string literal union : 'rectangle' | 'circle' | 'ellipse' | 'polygon' | 'roundedRectangle' | 'triangle'. Chaque forme expose type pour que vous puissiez vous brancher sans instanceof.
import type { PointData } from "pixi.js";

function distance(a: PointData, b: PointData): number {
  const dx = a.x - b.x;
  const dy = a.y - b.y;
  return Math.sqrt(dx * dx + dy * dy);
}

math-extras (import side-effect)

import 'pixi.js/math-extras' ajoute des méthodes à Point, ObservablePoint et Rectangle via extension de prototype. Non inclus dans le bundle par défaut.

import "pixi.js/math-extras";
import { Point } from "pixi.js";

Méthodes vectorielles Point / ObservablePoint

Toutes les méthodes acceptent un paramètre out optionnel pour éviter les allocations. Sans out, un nouveau Point est retourné.

const a = new Point(3, 4);
const b = new Point(1, 2);

// Arithmétique
const sum = a.add(b); // Point(4, 6)
const diff = a.subtract(b); // Point(2, 2)
const prod = a.multiply(b); // Point(3, 8) - composante par composante
const scaled = a.multiplyScalar(2); // Point(6, 8)

// Produit scalaire et produit vectoriel
const dot = a.dot(b); // 11
const cross = a.cross(b); // 2 (composante z du produit vectoriel 3D)

// Longueur
const len = a.magnitude(); // 5
const lenSq = a.magnitudeSquared(); // 25 (plus rapide pour les comparaisons)

// Normaliser en vecteur unitaire
const unit = a.normalize(); // Point(0.6, 0.8)

// Projection et réflexion
const proj = a.project(b); // projeter a sur b
const refl = a.reflect(new Point(0, 1)); // réfléchir sur la normale

// Rotation
const rotated = a.rotate(Math.PI / 2); // tourner de 90 degrés

// Réutiliser un point existant pour éviter une allocation
const out = new Point();
a.add(b, out); // résultat écrit dans out

Méthodes étendues de Rectangle

containsRect et intersects sont des méthodes natives de Rectangle (voir ci-dessus). math-extras ajoute equals, intersection (retourne le rectangle de chevauchement) et union :

import "pixi.js/math-extras";
import { Rectangle } from "pixi.js";

const r1 = new Rectangle(0, 0, 100, 100);
const r2 = new Rectangle(50, 50, 100, 100);

r1.equals(r2); // false

const overlap = r1.intersection(r2); // Rectangle(50, 50, 50, 50)
const envelope = r1.union(r2); // Rectangle(0, 0, 150, 150)

// Paramètre out optionnel
const out = new Rectangle();
r1.intersection(r2, out);

Fonctions utilitaires de géométrie

Ces fonctions sont exportées depuis pixi.js/math-extras, pas depuis l'entrée principale pixi.js.

import {
  floatEqual,
  lineIntersection,
  segmentIntersection,
} from "pixi.js/math-extras";
import { Point } from "pixi.js";

// Comparaison de floats basée sur epsilon (epsilon par défaut : Number.EPSILON)
floatEqual(0.1 + 0.2, 0.3, 1e-10); // true avec un epsilon raisonnable
floatEqual(1.0, 1.001, 0.01); // true (epsilon personnalisé)

// Intersection de lignes non bornées (retourne {x: NaN, y: NaN} si parallèles)
const hit = lineIntersection(
  new Point(0, 0),
  new Point(10, 10), // ligne A
  new Point(10, 0),
  new Point(0, 10), // ligne B
); // Point(5, 5)
if (isNaN(hit.x)) {
  /* les lignes sont parallèles */
}

// Intersection de segments bornés (retourne {x: NaN, y: NaN} si les segments ne se croisent pas)
const segHit = segmentIntersection(
  new Point(0, 0),
  new Point(10, 10),
  new Point(10, 0),
  new Point(0, 10),
); // Point(5, 5)
if (isNaN(segHit.x)) {
  /* les segments ne se croisent pas */
}

Erreurs courantes

HIGH : Importer depuis @pixi/math

Incorrect :

import { Point } from "@pixi/math";

Correct :

import { Point } from "pixi.js";

v8 utilise un seul package pixi.js. Tous les sous-packages comme @pixi/math, @pixi/core, etc. ont été supprimés.

MEDIUM : Muter ObservablePoint sans déclencher l'observateur

Incorrect :

// Remplacer la référence perd l'observation
let pos = container.position;
pos = new Point(100, 200); // container.position inchangé

Correct :

// Muter sur place pour déclencher l'observateur
container.position.set(100, 200);
// ou
container.position.x = 100;
container.position.y = 200;
// ou copier depuis un autre point
container.position.copyFrom(new Point(100, 200));

La position, scale, pivot, origin et skew d'un Container sont des ObservablePoints. Définir .x ou .y sur eux déclenche la mise à jour de la transformation du container. Réassigner la référence de variable ne modifie pas le container. Mutez toujours l'ObservablePoint existant via .set(), .copyFrom() ou une assignation de propriété directe sur l'objet original.

MEDIUM : Ne pas importer math-extras pour les méthodes étendues

Incorrect :

import { Point } from "pixi.js";
const p = new Point(1, 2);
p.add(new Point(3, 4)); // TypeError: p.add is not a function

Correct :

import "pixi.js/math-extras";
import { Point } from "pixi.js";
const p = new Point(1, 2);
const sum = p.add(new Point(3, 4)); // fonctionne

Les utilitaires mathématiques étendus (add, subtract, multiply, magnitude, normalize, dot, cross, etc. sur Point ; méthodes d'intersection sur les formes) requièrent un explicit import 'pixi.js/math-extras'. Ceux-ci ne sont pas inclus dans le bundle par défaut.

MEDIUM : Stocker des références à des objets partagés/temporaires

Incorrect :

const myPoint = Point.shared;
myPoint.set(100, 200);
// ... plus tard ...
console.log(myPoint.x); // 0 (réinitialisé au prochain accès)

Correct :

const myPoint = new Point();
myPoint.copyFrom(Point.shared.set(100, 200));
// ou simplement
const myPoint = new Point(100, 200);

Point.shared et Matrix.shared sont réinitialisés à zéro/identité chaque fois qu'on y accède. Ils existent pour des calculs ponctuels dans une seule expression. Ne stockez jamais une référence à eux.

Référence API

Skills similaires