Skip to content

@gwenjs/physics2d

pnpm add @gwenjs/physics2d

Plugin de moteur de physique 2D alimenté par Rapier2D. Fournit la dynamique des corps rigides, les colliders et les capteurs pour les jeux 2D.

Configuration du plugin

Physics2DPlugin()

Signature:

ts
function Physics2DPlugin(options?: Physics2DPluginOptions): PluginDef

Description. Crée le plugin de physique 2D. Enregistrez dans votre config d'app pour activer la simulation physique.

Retourne: PluginDef — définition du plugin de physique.

Exemple:

ts
export default defineConfig({
  plugins: [Physics2DPlugin()],
  // ...
});

Composables

Utilisez ceux-ci à l'intérieur de defineActor pour ajouter des composants de physique aux entités.

useShape(options)

Signature:

ts
function useShape(options: ShapeOptions): void

Description. Ajoute une forme (collider) à l'entité courante.

Paramètres:

ParamètreTypeDescription
optionsShapeOptionsConfiguration de la forme

Retourne: void

useDynamicBody(options?)

Signature:

ts
function useDynamicBody(options?: DynamicBodyOptions): void

Description. Ajoute un corps rigide dynamique (affecté par la gravité et les forces). À utiliser pour les objets de jeu en mouvement.

Paramètres:

ParamètreTypeDescription
optionsDynamicBodyOptionsConfiguration du corps (optionnel)

Retourne: void

Exemple:

ts
const BallPrefab = definePrefab([{ def: Position, defaults: { x: 0, y: 0 } }])

export const BallActor = defineActor(BallPrefab, () => {
  useDynamicBody({ mass: 2, restitution: 0.8 })
  useBoxCollider({ w: 1, h: 1 })
})

useKinematicBody(options?)

Signature:

ts
function useKinematicBody(options?: KinematicBodyOptions): void

Description. Ajoute un corps cinématique (non affecté par la gravité, contrôlé par la vélocité). À utiliser pour les plates-formes, les obstacles mobiles.

Retourne: void

useStaticBody()

Signature:

ts
function useStaticBody(): void

Description. Ajoute un corps statique (immobile). À utiliser pour le terrain, les murs, le sol.

Retourne: void

Exemple:

ts
const GroundPrefab = definePrefab([{ def: Position, defaults: { x: 0, y: 0 } }])

export const GroundActor = defineActor(GroundPrefab, () => {
  useStaticBody()
  useBoxCollider({ w: 100, h: 1 })
})

Colliders

useBoxCollider(options)

Signature:

ts
function useBoxCollider(options: BoxColliderOptions): void

Description. Ajoute un collider de boîte/rectangle à l'entité courante.

Paramètres:

ParamètreTypeDescription
options.wnumberLargeur de la boîte en unités monde
options.hnumberHauteur de la boîte en unités monde
options.isSensorbooleanSi vrai, génère des événements de chevauchement sans réponse physique
options.layernumberBitmask de couche d'appartenance aux collisions
options.masknumberBitmask de filtre de collision
options.offsetXnumberDécalage X local par rapport à l'origine de l'acteur
options.offsetYnumberDécalage Y local par rapport à l'origine de l'acteur

Retourne: BoxColliderHandle

Exemple:

ts
useBoxCollider({ w: 2, h: 2, isSensor: false });

useSphereCollider(options)

Signature:

ts
function useSphereCollider(options: SphereColliderOptions): void

Description. Ajoute un collider circulaire à l'entité courante.

Paramètres:

ParamètreTypeDescription
options.radiusnumberRayon du cercle en unités monde
options.isSensorbooleanSi vrai, génère des événements de chevauchement sans réponse physique
options.layernumberBitmask de couche d'appartenance aux collisions
options.masknumberBitmask de filtre de collision

Retourne: void

useCapsuleCollider(options)

Signature:

ts
function useCapsuleCollider(options: CapsuleColliderOptions): void

Description. Ajoute un collider de capsule (rectangle arrondi).

Paramètres:

ParamètreTypeDescription
options.radiusnumberRayon de la capsule en unités monde
options.heightnumberHauteur totale de la capsule en unités monde
options.isSensorbooleanSi vrai, génère des événements de chevauchement sans réponse physique
options.layernumberBitmask de couche d'appartenance aux collisions
options.masknumberBitmask de filtre de collision

Retourne: void

Événements

onContact(handler)

Signature:

ts
function onContact(handler: (event: ContactEvent) => void): void

Description. Enregistre un gestionnaire pour les événements de collision (quand deux colliders entrent en collision).

Paramètres:

ParamètreTypeDescription
handlerfunctionAppelé avec les informations de collision

Retourne: void

Exemple:

ts
const PlayerPrefab = definePrefab([{ def: Position, defaults: { x: 0, y: 0 } }])

export const PlayerActor = defineActor(PlayerPrefab, () => {
  onContact((event) => {
    if (event.relativeVelocity > 10) {
      // Impact violent — prendre des dégâts
    }
  })
})

ContactEvent

Signature:

ts
interface ContactEvent {
  entityA: bigint;
  entityB: bigint;
  contactX: number;
  contactY: number;
  normalX: number;
  normalY: number;
  relativeVelocity: number;
}

onSensorEnter(sensorId, callback)

Signature:

ts
function onSensorEnter(sensorId: number, callback: (entityId: bigint) => void): void

Description. Appelé quand une autre entité entre dans un collider capteur. Utiliser le colliderId du handle de collider comme sensorId.

Exemple:

ts
export const CoinActor = defineActor(CoinPrefab, () => {
  const zone = useSphereCollider({ radius: 0.5, isSensor: true })
  onSensorEnter(zone.colliderId, (entityId) => {
    // Une entité est entrée dans la zone
    console.log('Collecté par l\'entité :', entityId)
  })
})

onSensorExit(sensorId, callback)

Signature:

ts
function onSensorExit(sensorId: number, callback: (entityId: bigint) => void): void

Description. Appelé quand une autre entité quitte un collider capteur.

Couches

defineLayers(definition)

Signature:

ts
function defineLayers<T extends Record<string, number>>(definition: T): Record<string, number>

Description. Déclare des couches de collision nommées avec leurs valeurs de bitmask. Le plugin Vite intègre les valeurs de couche au moment du build et avertit si des couches partagent des bits.

Paramètres:

ParamètreTypeDescription
definitionRecord<string, number>Objet associant des noms de couches à des valeurs de bitmask

Retourne: Record<string, number> — le même objet, avec les noms de couches comme clés.

Exemple:

ts
const Layers = defineLayers({
  player: 1 << 0,
  enemy:  1 << 1,
  wall:   1 << 2,
})
// Utilisez Layers.player, Layers.enemy, Layers.wall

Service de physique

usePhysics2D()

Signature:

ts
function usePhysics2D(): Physics2DAPI

Description. Retourne le service de physique pour interroger et manipuler les corps.

Retourne: Physics2DAPI — API d'exécution de physique.

Exemple:

ts
const physics = usePhysics2D();
physics.applyImpulse(entityId, 10, 0);

Physics2DAPI

Méthodes:

MéthodeSignatureDescription
applyImpulse(entityId: EntityId, x: number, y: number) => voidApplique une impulsion linéaire instantanée
setLinearVelocity(entityId: EntityId, vx: number, vy: number) => voidRemplace la vélocité linéaire (m/s)
getLinearVelocity(entityId: EntityId) => { x: number; y: number } | nullLit la vélocité linéaire actuelle
getPosition(entityId: EntityId) => { x: number; y: number; rotation: number } | nullLit la position et l'angle du corps
getCollisionEventsBatch(opts?) => CollisionEventsBatchRécupère tous les événements de collision de cette frame
getCollisionContacts(opts?) => ReadonlyArray<ResolvedCollisionContact>Lit les paires de contact actives
getSensorState(entityId: EntityId, sensorId: number) => SensorStateLit l'état de chevauchement d'un sensor

TIP

La plupart des manipulations de corps (forces, vélocités, impulsions) se font via le handle retourné par useDynamicBody() — pas directement via usePhysics2D(). L'API service est principalement utilisée pour le polling des événements de collision et les requêtes spatiales.

Exemple:

ts
const physics = usePhysics2D();

// Appliquer une impulsion via l'API service
physics.applyImpulse(entityId, 0, 500)

// Polling des événements de collision chaque frame
onUpdate(() => {
  const batch = physics.getCollisionEventsBatch()
  // traitement du batch...
})

Systèmes

createPhysicsKinematicSyncSystem(opts)

Signature:

ts
function createPhysicsKinematicSyncSystem(opts?: {
  syncPosition?: boolean;
  syncRotation?: boolean;
}): SystemDef

Description. Crée un système qui synchronise les positions/rotations des corps cinématiques basées sur les composants Transform.

Retourne: SystemDef

Exemple:

ts
const scene = defineScene({
  systems: [
    createPhysicsKinematicSyncSystem({ syncPosition: true, syncRotation: true })
  ]
});

createPlatformerGroundedSystem(opts)

Signature:

ts
function createPlatformerGroundedSystem(opts?: {
  groundLayer?: LayerMask;
  raycastDistance?: number;
}): SystemDef

Description. Crée un système qui suivre lesquelles entités sont sur le sol (debout sur un sol solide). Utile pour les platformers.

Retourne: SystemDef

Exemple:

ts
export const MyScene = defineScene({
  name: 'game',
  systems: [
    createPlatformerGroundedSystem({ raycastDistance: 0.1 }),
  ],
})

Support Tilemap

buildTilemapPhysicsChunks(opts)

Signature:

ts
function buildTilemapPhysicsChunks(opts: {
  tilemap: TilemapData;
  tileSize: number;
  solidTiles: number[];
  chunkSize?: number;
}): void

Description. Construit les colliders de physique pour une tilemap utilisant le chunking pour la performance.

Paramètres:

ParamètreTypeDescription
opts.tilemapTilemapDataDonnées de tilemap
opts.tileSizenumberTaille des tuiles en unités
opts.solidTilesnumber[]IDs des tuiles qui sont solides
opts.chunkSizenumberTaille de la grille de chunks (optionnel)

Retourne: void

patchTilemapPhysicsChunk(opts)

Signature:

ts
function patchTilemapPhysicsChunk(opts: {
  tilemap: TilemapData;
  chunkX: number;
  chunkY: number;
}): void

Description. Reconstruit la physique pour un seul chunk de tilemap (pour les éditions de tilemap dynamiques).

Paramètres:

ParamètreTypeDescription
opts.chunkXnumberChunk grille X
opts.chunkYnumberChunk grille Y

Retourne: void

Intégration Vite

physics2dVitePlugin(options?)

Signature:

ts
function physics2dVitePlugin(options?: Physics2DVitePluginOptions): VitePlugin
// interface Physics2DVitePluginOptions { debug?: boolean }

Description. Plugin Vite pour bundler Rapier2D WASM. Enregistré automatiquement quand le plugin physics2d est utilisé. Émet un avertissement au moment du build si une couche est définie avec defineLayers() mais jamais référencée dans le même fichier — permet de détecter les définitions de couches inutilisées tôt.

Paramètres:

ParamètreTypeDescription
optionsPhysics2DVitePluginOptionsOptions optionnelles du plugin au moment du build
options.debugbooleanActiver les logs de débogage pour l'intégration des couches (défaut: false)

Retourne: VitePlugin

Note: Lors de l'utilisation de la config du module, passez les options du plugin Vite via la sous-clé vite :

ts
modules: [['@gwenjs/physics2d', {
  gravity: -9.81,
  vite: { debug: true }  // Options du plugin Vite (build uniquement)
}]]

Définitions de type

BoxColliderOptions

ts
interface BoxColliderOptions {
  width: number;
  height: number;
  sensor?: boolean;
  density?: number;
}

SphereColliderOptions

ts
interface SphereColliderOptions {
  radius: number;
  sensor?: boolean;
  density?: number;
}

CapsuleColliderOptions

ts
interface CapsuleColliderOptions {
  halfHeight: number;
  radius: number;
  sensor?: boolean;
  density?: number;
}

DynamicBodyOptions

ts
interface DynamicBodyOptions {
  mass?: number;
  linearDamping?: number;
  angularDamping?: number;
  gravityScale?: number;
  restitution?: number;
  friction?: number;
  ccdEnabled?: boolean;
}

KinematicBodyOptions

ts
interface KinematicBodyOptions {
  friction?: number;
  restitution?: number;
}

StaticBodyOptions

ts
interface StaticBodyOptions {
  friction?: number;
}