@newkrok/nape-js 3.30.4 → 3.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-263GQ5UK.js +2 -0
- package/dist/chunk-HQH77APJ.cjs +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +691 -1
- package/dist/index.d.ts +691 -1
- package/dist/index.js +1 -1
- package/dist/serialization/index.cjs +1 -1
- package/dist/serialization/index.js +1 -1
- package/llms-full.txt +267 -1
- package/llms.txt +12 -1
- package/package.json +1 -1
- package/dist/chunk-OFVSWS4I.cjs +0 -2
- package/dist/chunk-ZNBQE3PX.js +0 -2
package/dist/index.d.ts
CHANGED
|
@@ -1539,6 +1539,20 @@ interface CharacterControllerOptions {
|
|
|
1539
1539
|
* @default null
|
|
1540
1540
|
*/
|
|
1541
1541
|
filter?: InteractionFilter | null;
|
|
1542
|
+
/**
|
|
1543
|
+
* World-space "down" direction used for ground / wall raycasts.
|
|
1544
|
+
*
|
|
1545
|
+
* Default `Vec2(0, 1)` matches a standard top-down-Y platformer (gravity
|
|
1546
|
+
* points along +Y). Override for radial-gravity / planet-platformer
|
|
1547
|
+
* scenarios — set `cc.down` each frame to the unit vector pointing from
|
|
1548
|
+
* the character toward whatever you treat as "down" (e.g. the nearest
|
|
1549
|
+
* planet's centre). Walls are detected perpendicular to this direction.
|
|
1550
|
+
*
|
|
1551
|
+
* The vector is normalized internally; magnitude is ignored.
|
|
1552
|
+
*
|
|
1553
|
+
* @default Vec2(0, 1)
|
|
1554
|
+
*/
|
|
1555
|
+
down?: Vec2;
|
|
1542
1556
|
}
|
|
1543
1557
|
/**
|
|
1544
1558
|
* Velocity-based character controller for 2D platformers.
|
|
@@ -1585,6 +1599,8 @@ declare class CharacterController {
|
|
|
1585
1599
|
private _maxSlopeAngle;
|
|
1586
1600
|
private _maxSlopeCos;
|
|
1587
1601
|
private _filter;
|
|
1602
|
+
private _downX;
|
|
1603
|
+
private _downY;
|
|
1588
1604
|
private _oneWayListener;
|
|
1589
1605
|
private _grounded;
|
|
1590
1606
|
private _groundNormal;
|
|
@@ -1601,6 +1617,16 @@ declare class CharacterController {
|
|
|
1601
1617
|
get timeSinceGrounded(): number;
|
|
1602
1618
|
get maxSlopeAngle(): number;
|
|
1603
1619
|
set maxSlopeAngle(v: number);
|
|
1620
|
+
/**
|
|
1621
|
+
* Current world-space "down" direction used for ground / wall raycasts.
|
|
1622
|
+
* Returns a fresh `Vec2` each call; mutate via {@link setDown} or by
|
|
1623
|
+
* assigning a new `Vec2` to this property.
|
|
1624
|
+
*/
|
|
1625
|
+
get down(): Vec2;
|
|
1626
|
+
set down(value: Vec2);
|
|
1627
|
+
/** Update the down direction from raw components (normalized internally). */
|
|
1628
|
+
setDown(x: number, y: number): void;
|
|
1629
|
+
private _setDown;
|
|
1604
1630
|
/**
|
|
1605
1631
|
* Set the character body's velocity. Call this each frame **before**
|
|
1606
1632
|
* `space.step()`.
|
|
@@ -1860,6 +1886,670 @@ interface FractureResult {
|
|
|
1860
1886
|
*/
|
|
1861
1887
|
declare function fractureBody(body: Body, impactPoint: Vec2, options?: FractureOptions): FractureResult;
|
|
1862
1888
|
|
|
1889
|
+
/** A 2D row-major grid of tile values. `grid[y][x]` is the cell at row `y`, column `x`. */
|
|
1890
|
+
type TilemapGrid = ArrayLike<ArrayLike<number>>;
|
|
1891
|
+
/** Predicate deciding whether a tile value at `(x, y)` represents a solid (collidable) cell. */
|
|
1892
|
+
type TilemapSolidPredicate = (value: number, x: number, y: number) => boolean;
|
|
1893
|
+
/**
|
|
1894
|
+
* Strategy for combining adjacent solid tiles into fewer rectangles.
|
|
1895
|
+
*
|
|
1896
|
+
* - `"none"` — every solid tile becomes its own 1x1 rectangle
|
|
1897
|
+
* - `"rows"` — horizontally-adjacent solid tiles within a row are merged
|
|
1898
|
+
* - `"greedy"` — runs are extended both horizontally and vertically using a
|
|
1899
|
+
* greedy meshing pass (default — produces the fewest rectangles)
|
|
1900
|
+
*/
|
|
1901
|
+
type TilemapMergeMode = "none" | "rows" | "greedy";
|
|
1902
|
+
/** Tile width and height in pixels. */
|
|
1903
|
+
interface TilemapTileSize {
|
|
1904
|
+
/** Tile width in pixels. */
|
|
1905
|
+
w: number;
|
|
1906
|
+
/** Tile height in pixels. */
|
|
1907
|
+
h: number;
|
|
1908
|
+
}
|
|
1909
|
+
/** Configuration options for {@link buildTilemapBody} / {@link meshTilemap}. */
|
|
1910
|
+
interface TilemapOptions {
|
|
1911
|
+
/** Tile size in pixels — either a square size or `{ w, h }` for non-square tiles. */
|
|
1912
|
+
tileSize: number | TilemapTileSize;
|
|
1913
|
+
/** Body position (top-left corner of the map in world space). Default `(0, 0)`. */
|
|
1914
|
+
position?: Vec2;
|
|
1915
|
+
/**
|
|
1916
|
+
* Predicate deciding which cells are solid. Default treats any non-zero
|
|
1917
|
+
* value as solid.
|
|
1918
|
+
*/
|
|
1919
|
+
solid?: TilemapSolidPredicate;
|
|
1920
|
+
/** Merge strategy — defaults to `"greedy"`. */
|
|
1921
|
+
merge?: TilemapMergeMode;
|
|
1922
|
+
/** Material applied to every generated shape. */
|
|
1923
|
+
material?: Material;
|
|
1924
|
+
/** InteractionFilter applied to every generated shape. */
|
|
1925
|
+
filter?: InteractionFilter;
|
|
1926
|
+
/** CbTypes added to every generated shape. */
|
|
1927
|
+
cbTypes?: CbType[];
|
|
1928
|
+
/** Body type — defaults to `BodyType.STATIC`. Ignored when `body` is provided. */
|
|
1929
|
+
bodyType?: BodyType;
|
|
1930
|
+
/**
|
|
1931
|
+
* Append shapes to this existing body instead of creating a new one. Useful
|
|
1932
|
+
* for chunked maps where many tilemap layers share one body, or when adding
|
|
1933
|
+
* a collision mesh to a body that already exists.
|
|
1934
|
+
*/
|
|
1935
|
+
body?: Body;
|
|
1936
|
+
}
|
|
1937
|
+
/** A rectangle in tile coordinates produced by {@link meshTilemap}. */
|
|
1938
|
+
interface TilemapRect {
|
|
1939
|
+
/** Tile column of the rectangle's left edge. */
|
|
1940
|
+
x: number;
|
|
1941
|
+
/** Tile row of the rectangle's top edge. */
|
|
1942
|
+
y: number;
|
|
1943
|
+
/** Width in tiles (>= 1). */
|
|
1944
|
+
w: number;
|
|
1945
|
+
/** Height in tiles (>= 1). */
|
|
1946
|
+
h: number;
|
|
1947
|
+
}
|
|
1948
|
+
/** Subset of a Tiled JSON tile layer needed for grid extraction. */
|
|
1949
|
+
interface TiledTileLayer {
|
|
1950
|
+
/** Flat row-major array of tile GIDs. */
|
|
1951
|
+
data: ArrayLike<number>;
|
|
1952
|
+
/** Width of the layer in tiles. */
|
|
1953
|
+
width: number;
|
|
1954
|
+
/** Height of the layer in tiles. */
|
|
1955
|
+
height: number;
|
|
1956
|
+
}
|
|
1957
|
+
/** Subset of an LDtk IntGrid layer instance needed for grid extraction. */
|
|
1958
|
+
interface LDtkIntGridLayer {
|
|
1959
|
+
/** Row-major flat array of int values (0 = empty). */
|
|
1960
|
+
intGridCsv: ArrayLike<number>;
|
|
1961
|
+
/** Cell-grid width (LDtk's `__cWid`, falls back to `cWid`). */
|
|
1962
|
+
__cWid?: number;
|
|
1963
|
+
/** Cell-grid height (LDtk's `__cHei`, falls back to `cHei`). */
|
|
1964
|
+
__cHei?: number;
|
|
1965
|
+
/** Alternate width key. */
|
|
1966
|
+
cWid?: number;
|
|
1967
|
+
/** Alternate height key. */
|
|
1968
|
+
cHei?: number;
|
|
1969
|
+
}
|
|
1970
|
+
/**
|
|
1971
|
+
* Convert a 2D grid of tile values into the minimal set of axis-aligned
|
|
1972
|
+
* rectangles that cover the solid cells, using the requested merge strategy.
|
|
1973
|
+
*
|
|
1974
|
+
* The result is geometry-only — no `Body` or `Shape` is created — which makes
|
|
1975
|
+
* this function reusable for debug overlays, rendering, or custom body
|
|
1976
|
+
* construction. {@link buildTilemapBody} is a thin wrapper that converts the
|
|
1977
|
+
* rectangles to `Polygon` shapes.
|
|
1978
|
+
*
|
|
1979
|
+
* Greedy meshing reduces shape count dramatically for typical platformer
|
|
1980
|
+
* maps. A 50-tile floor strip becomes one rectangle; a solid 10x10 block
|
|
1981
|
+
* becomes one rectangle instead of 100. Fewer shapes = smaller broadphase
|
|
1982
|
+
* footprint, faster narrowphase, less debug-draw work.
|
|
1983
|
+
*
|
|
1984
|
+
* @param grid - 2D row-major tile grid (`grid[y][x]`).
|
|
1985
|
+
* @param options - Optional `solid` predicate and `merge` strategy.
|
|
1986
|
+
* @returns The list of merged rectangles in tile coordinates.
|
|
1987
|
+
*
|
|
1988
|
+
* @example
|
|
1989
|
+
* ```ts
|
|
1990
|
+
* const rects = meshTilemap([
|
|
1991
|
+
* [1, 1, 1, 0, 1],
|
|
1992
|
+
* [1, 1, 1, 0, 1],
|
|
1993
|
+
* [0, 0, 0, 0, 1],
|
|
1994
|
+
* ]);
|
|
1995
|
+
* // -> [{x:0,y:0,w:3,h:2}, {x:4,y:0,w:1,h:3}]
|
|
1996
|
+
* ```
|
|
1997
|
+
*/
|
|
1998
|
+
declare function meshTilemap(grid: TilemapGrid, options?: {
|
|
1999
|
+
solid?: TilemapSolidPredicate;
|
|
2000
|
+
merge?: TilemapMergeMode;
|
|
2001
|
+
}): TilemapRect[];
|
|
2002
|
+
/**
|
|
2003
|
+
* Build a single physics `Body` from a 2D tile grid.
|
|
2004
|
+
*
|
|
2005
|
+
* Each merged rectangle becomes a `Polygon` shape on the body. Tiles are laid
|
|
2006
|
+
* out with `(0, 0)` at the top-left of tile `(0, 0)`, so the body's
|
|
2007
|
+
* `position` (defaults to origin) is the world-space location of that
|
|
2008
|
+
* top-left corner.
|
|
2009
|
+
*
|
|
2010
|
+
* Defaults to `BodyType.STATIC` and `merge: "greedy"`, matching the most
|
|
2011
|
+
* common gamedev use case (level collision geometry from a Tiled / LDtk map).
|
|
2012
|
+
*
|
|
2013
|
+
* @param grid - 2D row-major tile grid.
|
|
2014
|
+
* @param options - Tile size + body / shape options.
|
|
2015
|
+
* @returns A `Body` containing one `Polygon` shape per merged rectangle.
|
|
2016
|
+
* The returned body is not yet attached to a `Space` — set `body.space`
|
|
2017
|
+
* to insert it.
|
|
2018
|
+
*
|
|
2019
|
+
* @example
|
|
2020
|
+
* ```ts
|
|
2021
|
+
* const grid = [
|
|
2022
|
+
* [1, 1, 1, 0, 1, 1, 1],
|
|
2023
|
+
* [0, 0, 0, 0, 0, 0, 0],
|
|
2024
|
+
* [1, 1, 1, 1, 1, 1, 1],
|
|
2025
|
+
* ];
|
|
2026
|
+
* const body = buildTilemapBody(grid, { tileSize: 32, position: Vec2.get(0, 100) });
|
|
2027
|
+
* body.space = space;
|
|
2028
|
+
* ```
|
|
2029
|
+
*/
|
|
2030
|
+
declare function buildTilemapBody(grid: TilemapGrid, options: TilemapOptions): Body;
|
|
2031
|
+
/**
|
|
2032
|
+
* Convert a Tiled JSON tile layer into a 2D row-major grid suitable for
|
|
2033
|
+
* {@link meshTilemap} / {@link buildTilemapBody}.
|
|
2034
|
+
*
|
|
2035
|
+
* Only the `data`, `width`, and `height` fields of the layer are read — the
|
|
2036
|
+
* helper has no runtime dependency on a Tiled SDK and accepts any object with
|
|
2037
|
+
* that shape.
|
|
2038
|
+
*
|
|
2039
|
+
* @param layer - A Tiled tile layer (e.g. `map.layers[i]` from a Tiled JSON export).
|
|
2040
|
+
* @returns A 2D number array, with `0` representing empty tiles.
|
|
2041
|
+
*/
|
|
2042
|
+
declare function tiledLayerToGrid(layer: TiledTileLayer): number[][];
|
|
2043
|
+
/**
|
|
2044
|
+
* Convert an LDtk IntGrid layer instance into a 2D row-major grid.
|
|
2045
|
+
*
|
|
2046
|
+
* Reads `intGridCsv` plus the cell-dimension fields (`__cWid` / `__cHei`,
|
|
2047
|
+
* with `cWid` / `cHei` accepted as fallbacks). LDtk uses `0` for empty
|
|
2048
|
+
* IntGrid cells, which the default `solid` predicate already treats as
|
|
2049
|
+
* non-solid.
|
|
2050
|
+
*
|
|
2051
|
+
* @param layer - An LDtk IntGrid layer instance.
|
|
2052
|
+
* @returns A 2D number array, with `0` representing empty cells.
|
|
2053
|
+
*/
|
|
2054
|
+
declare function ldtkLayerToGrid(layer: LDtkIntGridLayer): number[][];
|
|
2055
|
+
|
|
2056
|
+
/**
|
|
2057
|
+
* Falloff law for {@link RadialGravityField}.
|
|
2058
|
+
*
|
|
2059
|
+
* - `"inverse-square"` — `F = strength / d²` (Newtonian gravity, default)
|
|
2060
|
+
* - `"inverse"` — `F = strength / d` (line-source gravity)
|
|
2061
|
+
* - `"constant"` — `F = strength` (constant pull regardless of distance)
|
|
2062
|
+
* - `(distance) => number` — custom multiplier, applied as `F = strength * fn(d)`
|
|
2063
|
+
*/
|
|
2064
|
+
type GravityFalloff = "inverse-square" | "inverse" | "constant" | ((distance: number) => number);
|
|
2065
|
+
/** Per-body filter — `false` skips the body. */
|
|
2066
|
+
type BodyFilter = (body: Body) => boolean;
|
|
2067
|
+
/** Configuration options for {@link RadialGravityField}. */
|
|
2068
|
+
interface RadialGravityFieldOptions {
|
|
2069
|
+
/**
|
|
2070
|
+
* The field's anchor point. May be a `Vec2` (fixed world position — captured
|
|
2071
|
+
* by reference, so mutating it after construction moves the field), or a
|
|
2072
|
+
* `Body` (the field tracks `body.position` automatically each step).
|
|
2073
|
+
*/
|
|
2074
|
+
source: Vec2 | Body;
|
|
2075
|
+
/** Field strength scaling — units depend on `falloff` (see {@link GravityFalloff}). */
|
|
2076
|
+
strength: number;
|
|
2077
|
+
/** Falloff law. @default `"inverse-square"` */
|
|
2078
|
+
falloff?: GravityFalloff;
|
|
2079
|
+
/** Multiply the resulting force by `body.mass` (Newtonian gravity). @default `true` */
|
|
2080
|
+
scaleByMass?: boolean;
|
|
2081
|
+
/**
|
|
2082
|
+
* Bodies farther than this from the source receive zero force — useful for
|
|
2083
|
+
* bounded gravity wells with hard edges.
|
|
2084
|
+
* @default `Infinity`
|
|
2085
|
+
*/
|
|
2086
|
+
maxRadius?: number;
|
|
2087
|
+
/**
|
|
2088
|
+
* Distance values used in the falloff calculation are clamped to be at
|
|
2089
|
+
* least this — prevents singularities at the source center.
|
|
2090
|
+
* @default `1`
|
|
2091
|
+
*/
|
|
2092
|
+
minRadius?: number;
|
|
2093
|
+
/**
|
|
2094
|
+
* Softening epsilon added to `d²` for the inverse-square falloff (smooths
|
|
2095
|
+
* out near-source spikes without disabling the pull). Has no effect on
|
|
2096
|
+
* other falloff laws.
|
|
2097
|
+
* @default `0`
|
|
2098
|
+
*/
|
|
2099
|
+
softening?: number;
|
|
2100
|
+
/**
|
|
2101
|
+
* Predicate deciding which bodies the field affects. `null` (default)
|
|
2102
|
+
* means "all dynamic bodies". Static and kinematic bodies are always
|
|
2103
|
+
* skipped (forces have no effect on them anyway).
|
|
2104
|
+
* @default `null`
|
|
2105
|
+
*/
|
|
2106
|
+
bodyFilter?: BodyFilter | null;
|
|
2107
|
+
/** When `false`, calls to {@link RadialGravityField.apply} are no-ops. @default `true` */
|
|
2108
|
+
enabled?: boolean;
|
|
2109
|
+
}
|
|
2110
|
+
/**
|
|
2111
|
+
* A point-source gravity field — pulls bodies toward an anchor with a chosen
|
|
2112
|
+
* falloff law.
|
|
2113
|
+
*
|
|
2114
|
+
* Replaces the manual `for (body of space.bodies) body.force = ...` loops
|
|
2115
|
+
* commonly written for orbital / planet / multi-body gravity scenarios.
|
|
2116
|
+
* Multiple fields compose naturally via {@link RadialGravityFieldGroup} or
|
|
2117
|
+
* by calling `apply()` on each one in sequence — each call **adds** to the
|
|
2118
|
+
* existing accumulated force, so userland `body.force` writes are preserved.
|
|
2119
|
+
*
|
|
2120
|
+
* @example
|
|
2121
|
+
* ```ts
|
|
2122
|
+
* // Mario-Galaxy-style planet pulling everything toward its center
|
|
2123
|
+
* const planet = new Body(BodyType.STATIC, new Vec2(400, 300));
|
|
2124
|
+
* planet.shapes.add(new Circle(40));
|
|
2125
|
+
* planet.space = space;
|
|
2126
|
+
*
|
|
2127
|
+
* const field = new RadialGravityField({
|
|
2128
|
+
* source: planet,
|
|
2129
|
+
* strength: 800000,
|
|
2130
|
+
* maxRadius: 250,
|
|
2131
|
+
* softening: 100,
|
|
2132
|
+
* });
|
|
2133
|
+
*
|
|
2134
|
+
* // Each frame, BEFORE space.step():
|
|
2135
|
+
* field.apply(space);
|
|
2136
|
+
* space.step(1 / 60);
|
|
2137
|
+
* ```
|
|
2138
|
+
*/
|
|
2139
|
+
declare class RadialGravityField {
|
|
2140
|
+
source: Vec2 | Body;
|
|
2141
|
+
strength: number;
|
|
2142
|
+
falloff: GravityFalloff;
|
|
2143
|
+
scaleByMass: boolean;
|
|
2144
|
+
maxRadius: number;
|
|
2145
|
+
minRadius: number;
|
|
2146
|
+
softening: number;
|
|
2147
|
+
bodyFilter: BodyFilter | null;
|
|
2148
|
+
enabled: boolean;
|
|
2149
|
+
constructor(options: RadialGravityFieldOptions);
|
|
2150
|
+
/**
|
|
2151
|
+
* Current world-space center of the field.
|
|
2152
|
+
*
|
|
2153
|
+
* Returns the anchor's `(x, y)` — for a `Body` source this reflects the
|
|
2154
|
+
* body's current position each call, so the field automatically tracks
|
|
2155
|
+
* a moving anchor.
|
|
2156
|
+
*/
|
|
2157
|
+
getPosition(): {
|
|
2158
|
+
x: number;
|
|
2159
|
+
y: number;
|
|
2160
|
+
};
|
|
2161
|
+
/**
|
|
2162
|
+
* Compute (but do not apply) the force this field would exert on `body`
|
|
2163
|
+
* given its current position. Returns `(0, 0)` when the field is disabled,
|
|
2164
|
+
* the body is static, the body is filtered out, or the body is outside
|
|
2165
|
+
* `maxRadius`.
|
|
2166
|
+
*
|
|
2167
|
+
* The returned `Vec2` is fresh and owned by the caller.
|
|
2168
|
+
*/
|
|
2169
|
+
forceOn(body: Body): Vec2;
|
|
2170
|
+
/**
|
|
2171
|
+
* Add this field's force contribution to every eligible body in `space`.
|
|
2172
|
+
*
|
|
2173
|
+
* Adds to (does not replace) each body's existing accumulated force, so
|
|
2174
|
+
* multiple fields and userland force writes all stack naturally. Call
|
|
2175
|
+
* once per frame, before `space.step()`.
|
|
2176
|
+
*/
|
|
2177
|
+
apply(space: Space): void;
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* A composable collection of {@link RadialGravityField} instances. Calling
|
|
2181
|
+
* `apply()` runs every member field once — convenient for multi-source
|
|
2182
|
+
* scenarios (binary stars, three-body, planet platformers).
|
|
2183
|
+
*/
|
|
2184
|
+
declare class RadialGravityFieldGroup {
|
|
2185
|
+
/** Ordered list of fields. Mutate via {@link add} / {@link remove}. */
|
|
2186
|
+
readonly fields: RadialGravityField[];
|
|
2187
|
+
/** Add a field to the group and return it. */
|
|
2188
|
+
add(field: RadialGravityField): RadialGravityField;
|
|
2189
|
+
/** Remove a field from the group. Returns `true` if it was present. */
|
|
2190
|
+
remove(field: RadialGravityField): boolean;
|
|
2191
|
+
/** Remove all fields. */
|
|
2192
|
+
clear(): void;
|
|
2193
|
+
/** Number of fields currently in the group. */
|
|
2194
|
+
get length(): number;
|
|
2195
|
+
/**
|
|
2196
|
+
* Apply every field's force contribution to all eligible bodies in `space`.
|
|
2197
|
+
* Forces stack additively, preserving any userland `body.force` writes.
|
|
2198
|
+
*/
|
|
2199
|
+
apply(space: Space): void;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
/** Shape used for each spawned particle body. */
|
|
2203
|
+
type ParticleShape = "circle" | "polygon";
|
|
2204
|
+
/** State snapshot passed to the `onSpawn` hook. */
|
|
2205
|
+
interface ParticleSpawnState {
|
|
2206
|
+
/** World-space spawn position. */
|
|
2207
|
+
position: Vec2;
|
|
2208
|
+
/** Initial linear velocity. */
|
|
2209
|
+
velocity: Vec2;
|
|
2210
|
+
/** Initial rotation (rad). */
|
|
2211
|
+
angle: number;
|
|
2212
|
+
/** Initial angular velocity (rad/s). */
|
|
2213
|
+
angularVelocity: number;
|
|
2214
|
+
/** Lifetime in seconds. `<= 0` disables auto-death. */
|
|
2215
|
+
lifetime: number;
|
|
2216
|
+
/** Free-form per-particle payload (color, frame index, damage, etc.). */
|
|
2217
|
+
userData: unknown;
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Spawn-position pattern. Position is sampled once per particle, in
|
|
2221
|
+
* emitter-local space (relative to {@link ParticleEmitter.origin}), then
|
|
2222
|
+
* translated into world space.
|
|
2223
|
+
*
|
|
2224
|
+
* - `point` — always at the origin.
|
|
2225
|
+
* - `rect` — uniform inside an axis-aligned rectangle centred on the origin.
|
|
2226
|
+
* - `circle` — uniform inside a disk; `hollow: true` samples the rim only.
|
|
2227
|
+
* - `arc` — on the rim of a circular arc, `angle*` in radians.
|
|
2228
|
+
* - `custom` — user-provided sampler. Receives the emitter's RNG.
|
|
2229
|
+
*/
|
|
2230
|
+
type SpawnPattern = {
|
|
2231
|
+
kind: "point";
|
|
2232
|
+
} | {
|
|
2233
|
+
kind: "rect";
|
|
2234
|
+
width: number;
|
|
2235
|
+
height: number;
|
|
2236
|
+
} | {
|
|
2237
|
+
kind: "circle";
|
|
2238
|
+
radius: number;
|
|
2239
|
+
hollow?: boolean;
|
|
2240
|
+
} | {
|
|
2241
|
+
kind: "arc";
|
|
2242
|
+
radius: number;
|
|
2243
|
+
angleStart: number;
|
|
2244
|
+
angleEnd: number;
|
|
2245
|
+
} | {
|
|
2246
|
+
kind: "custom";
|
|
2247
|
+
sample: (rng: () => number) => Vec2;
|
|
2248
|
+
};
|
|
2249
|
+
/**
|
|
2250
|
+
* Initial-velocity pattern. The local spawn position is passed to the
|
|
2251
|
+
* `radial` and `custom` samplers so the velocity can depend on where the
|
|
2252
|
+
* particle was spawned (radial = "outward from origin").
|
|
2253
|
+
*
|
|
2254
|
+
* - `fixed` — every particle gets the same velocity vector.
|
|
2255
|
+
* - `cone` — uniformly random direction inside a cone of half-width
|
|
2256
|
+
* `spread` rad, centred on `direction` rad. Speed uniform in
|
|
2257
|
+
* `[speedMin, speedMax]`.
|
|
2258
|
+
* - `radial` — outward from the spawn point relative to the origin.
|
|
2259
|
+
* Speed uniform in `[speedMin, speedMax]`. If the spawn point is exactly
|
|
2260
|
+
* at the origin, falls back to a random direction.
|
|
2261
|
+
* - `custom` — user-provided sampler. Receives RNG and the local spawn
|
|
2262
|
+
* position.
|
|
2263
|
+
*/
|
|
2264
|
+
type VelocityPattern = {
|
|
2265
|
+
kind: "fixed";
|
|
2266
|
+
value: Vec2;
|
|
2267
|
+
} | {
|
|
2268
|
+
kind: "cone";
|
|
2269
|
+
direction: number;
|
|
2270
|
+
spread: number;
|
|
2271
|
+
speedMin: number;
|
|
2272
|
+
speedMax: number;
|
|
2273
|
+
} | {
|
|
2274
|
+
kind: "radial";
|
|
2275
|
+
speedMin: number;
|
|
2276
|
+
speedMax: number;
|
|
2277
|
+
} | {
|
|
2278
|
+
kind: "custom";
|
|
2279
|
+
sample: (rng: () => number, localPos: Vec2) => Vec2;
|
|
2280
|
+
};
|
|
2281
|
+
/**
|
|
2282
|
+
* What to do when {@link ParticleEmitterOptions.maxParticles} is full and a
|
|
2283
|
+
* new spawn is requested.
|
|
2284
|
+
*
|
|
2285
|
+
* - `drop-oldest` (default) — kill the oldest live particle to make room for
|
|
2286
|
+
* the new one. Keeps emitter responsive (e.g. bullets always come out).
|
|
2287
|
+
* - `drop-new` — silently drop the new spawn. Protects already-visible
|
|
2288
|
+
* particles from churn.
|
|
2289
|
+
*/
|
|
2290
|
+
type ParticleOverflowPolicy = "drop-oldest" | "drop-new";
|
|
2291
|
+
/** Reason a particle was killed, passed to `onDeath`. */
|
|
2292
|
+
type ParticleDeathReason = "lifetime" | "manual" | "bounds";
|
|
2293
|
+
/** World-space rectangle outside which particles auto-die. */
|
|
2294
|
+
interface ParticleBounds {
|
|
2295
|
+
x: number;
|
|
2296
|
+
y: number;
|
|
2297
|
+
w: number;
|
|
2298
|
+
h: number;
|
|
2299
|
+
}
|
|
2300
|
+
/** Configuration options for {@link ParticleEmitter}. */
|
|
2301
|
+
interface ParticleEmitterOptions {
|
|
2302
|
+
/** Space the emitted particle bodies live in. Required. */
|
|
2303
|
+
space: Space;
|
|
2304
|
+
/**
|
|
2305
|
+
* Spawn anchor. A `Vec2` is captured by reference (mutating it after
|
|
2306
|
+
* construction moves the emitter); a `Body` is tracked by position each
|
|
2307
|
+
* spawn (the body does not need to be in the same space). Required.
|
|
2308
|
+
*/
|
|
2309
|
+
origin: Vec2 | Body;
|
|
2310
|
+
/** Spawn-position pattern. @default `{ kind: "point" }` */
|
|
2311
|
+
spawn?: SpawnPattern;
|
|
2312
|
+
/** Initial velocity pattern. @default `{ kind: "fixed", value: (0, 0) }` */
|
|
2313
|
+
velocity?: VelocityPattern;
|
|
2314
|
+
/**
|
|
2315
|
+
* Continuous spawn rate in particles/second. Accumulated across `update()`
|
|
2316
|
+
* calls — fractional rates work. `0` disables continuous spawning (use
|
|
2317
|
+
* {@link ParticleEmitter.emit} for manual bursts).
|
|
2318
|
+
* @default `0`
|
|
2319
|
+
*/
|
|
2320
|
+
rate?: number;
|
|
2321
|
+
/**
|
|
2322
|
+
* Periodic-burst count (particles per burst). Combined with
|
|
2323
|
+
* `burstInterval`, fires a burst every `burstInterval` seconds.
|
|
2324
|
+
* @default `0`
|
|
2325
|
+
*/
|
|
2326
|
+
burstCount?: number;
|
|
2327
|
+
/**
|
|
2328
|
+
* Period of automatic bursts in seconds. Has no effect when `burstCount`
|
|
2329
|
+
* is `0`.
|
|
2330
|
+
* @default `0`
|
|
2331
|
+
*/
|
|
2332
|
+
burstInterval?: number;
|
|
2333
|
+
/**
|
|
2334
|
+
* Maximum simultaneously alive particles. The pool size is capped at this
|
|
2335
|
+
* value too. @default `512`
|
|
2336
|
+
*/
|
|
2337
|
+
maxParticles?: number;
|
|
2338
|
+
/** Lifetime range minimum (s). @default `1` */
|
|
2339
|
+
lifetimeMin?: number;
|
|
2340
|
+
/** Lifetime range maximum (s). @default `1` */
|
|
2341
|
+
lifetimeMax?: number;
|
|
2342
|
+
/** Body shape for each particle. @default `"circle"` */
|
|
2343
|
+
particleShape?: ParticleShape;
|
|
2344
|
+
/** Radius for circle particles. Ignored for polygon. @default `2` */
|
|
2345
|
+
particleRadius?: number;
|
|
2346
|
+
/**
|
|
2347
|
+
* Polygon vertices in body-local space (used when
|
|
2348
|
+
* `particleShape: "polygon"`). Defaults to a small square.
|
|
2349
|
+
*/
|
|
2350
|
+
particlePolygon?: Vec2[];
|
|
2351
|
+
/** Material applied to every particle shape. @default `new Material()` */
|
|
2352
|
+
particleMaterial?: Material;
|
|
2353
|
+
/**
|
|
2354
|
+
* Filter applied to every particle shape. If omitted and `selfCollision`
|
|
2355
|
+
* is `false`, the emitter generates a self-excluding filter automatically.
|
|
2356
|
+
*/
|
|
2357
|
+
particleFilter?: InteractionFilter;
|
|
2358
|
+
/**
|
|
2359
|
+
* Collision-callback type tagged on every particle body. Required for
|
|
2360
|
+
* `onCollide` to fire. The emitter never auto-creates one — pass your own
|
|
2361
|
+
* if you need it (so multiple emitters can share a type, or a single
|
|
2362
|
+
* emitter can match a user-defined cbType).
|
|
2363
|
+
*/
|
|
2364
|
+
particleCbType?: CbType;
|
|
2365
|
+
/** Whether particles can rotate. @default `true` */
|
|
2366
|
+
allowRotation?: boolean;
|
|
2367
|
+
/**
|
|
2368
|
+
* When `false` and no explicit `particleFilter` is given, particles
|
|
2369
|
+
* receive a generated filter that skips its own group — particles in the
|
|
2370
|
+
* same emitter never collide with each other. Has no effect when
|
|
2371
|
+
* `particleFilter` is provided. @default `false`
|
|
2372
|
+
*/
|
|
2373
|
+
selfCollision?: boolean;
|
|
2374
|
+
/** Policy when `maxParticles` is reached. @default `"drop-oldest"` */
|
|
2375
|
+
overflowPolicy?: ParticleOverflowPolicy;
|
|
2376
|
+
/** Optional world-space bounds — particles outside die instantly. */
|
|
2377
|
+
bounds?: ParticleBounds;
|
|
2378
|
+
/**
|
|
2379
|
+
* Deterministic RNG. All emitter randomness (spawn jitter, velocity cone,
|
|
2380
|
+
* lifetime sampling) flows through this. @default `Math.random` */
|
|
2381
|
+
random?: () => number;
|
|
2382
|
+
/** Whether the emitter is active. @default `true` */
|
|
2383
|
+
enabled?: boolean;
|
|
2384
|
+
/** Fired once per spawn, after the body is in the space. */
|
|
2385
|
+
onSpawn?: (state: ParticleSpawnState, body: Body) => void;
|
|
2386
|
+
/** Fired every `update()` for each live particle (ages > 0). */
|
|
2387
|
+
onUpdate?: (body: Body, age: number, dt: number) => void;
|
|
2388
|
+
/** Fired when a particle dies (lifetime, bounds, manual, or `killAll`). */
|
|
2389
|
+
onDeath?: (body: Body, reason: ParticleDeathReason) => void;
|
|
2390
|
+
/**
|
|
2391
|
+
* Fired when a particle's body collides with another body. Requires
|
|
2392
|
+
* `particleCbType` to be set. The handler runs from inside a Space
|
|
2393
|
+
* callback — do not mutate the space synchronously; use
|
|
2394
|
+
* {@link ParticleEmitter.requestKill} for deferred cleanup.
|
|
2395
|
+
*/
|
|
2396
|
+
onCollide?: (body: Body, other: Body) => void;
|
|
2397
|
+
}
|
|
2398
|
+
/**
|
|
2399
|
+
* Physics-aware particle emitter — a pooled, lifecycle-managed swarm of
|
|
2400
|
+
* dynamic bodies. Each particle is a real {@link Body} with a {@link Circle}
|
|
2401
|
+
* or {@link Polygon} shape, so it collides with the world, reacts to
|
|
2402
|
+
* gravity / fluids / forces, and triggers callbacks like any other body.
|
|
2403
|
+
*
|
|
2404
|
+
* @example
|
|
2405
|
+
* ```ts
|
|
2406
|
+
* // Volcano: emit lava drops upward in a 40-deg cone.
|
|
2407
|
+
* const volcano = new ParticleEmitter({
|
|
2408
|
+
* space,
|
|
2409
|
+
* origin: new Vec2(400, 100),
|
|
2410
|
+
* velocity: {
|
|
2411
|
+
* kind: "cone",
|
|
2412
|
+
* direction: -Math.PI / 2,
|
|
2413
|
+
* spread: Math.PI / 9,
|
|
2414
|
+
* speedMin: 350,
|
|
2415
|
+
* speedMax: 600,
|
|
2416
|
+
* },
|
|
2417
|
+
* rate: 80,
|
|
2418
|
+
* lifetimeMin: 4,
|
|
2419
|
+
* lifetimeMax: 8,
|
|
2420
|
+
* particleRadius: 3,
|
|
2421
|
+
* maxParticles: 600,
|
|
2422
|
+
* });
|
|
2423
|
+
*
|
|
2424
|
+
* // Each frame, before space.step():
|
|
2425
|
+
* volcano.update(1 / 60);
|
|
2426
|
+
* space.step(1 / 60);
|
|
2427
|
+
* ```
|
|
2428
|
+
*/
|
|
2429
|
+
declare class ParticleEmitter {
|
|
2430
|
+
enabled: boolean;
|
|
2431
|
+
origin: Vec2 | Body;
|
|
2432
|
+
spawn: SpawnPattern;
|
|
2433
|
+
velocity: VelocityPattern;
|
|
2434
|
+
rate: number;
|
|
2435
|
+
burstCount: number;
|
|
2436
|
+
burstInterval: number;
|
|
2437
|
+
maxParticles: number;
|
|
2438
|
+
lifetimeMin: number;
|
|
2439
|
+
lifetimeMax: number;
|
|
2440
|
+
allowRotation: boolean;
|
|
2441
|
+
overflowPolicy: ParticleOverflowPolicy;
|
|
2442
|
+
bounds: ParticleBounds | null;
|
|
2443
|
+
onSpawn: ((state: ParticleSpawnState, body: Body) => void) | null;
|
|
2444
|
+
onUpdate: ((body: Body, age: number, dt: number) => void) | null;
|
|
2445
|
+
onDeath: ((body: Body, reason: ParticleDeathReason) => void) | null;
|
|
2446
|
+
onCollide: ((body: Body, other: Body) => void) | null;
|
|
2447
|
+
readonly space: Space;
|
|
2448
|
+
readonly particleShape: ParticleShape;
|
|
2449
|
+
readonly particleRadius: number;
|
|
2450
|
+
readonly particlePolygon: Vec2[] | null;
|
|
2451
|
+
readonly particleMaterial: Material;
|
|
2452
|
+
readonly particleFilter: InteractionFilter;
|
|
2453
|
+
readonly particleCbType: CbType | null;
|
|
2454
|
+
readonly random: () => number;
|
|
2455
|
+
private _alive;
|
|
2456
|
+
private _ages;
|
|
2457
|
+
private _lifetimes;
|
|
2458
|
+
private _pool;
|
|
2459
|
+
private _totalSpawned;
|
|
2460
|
+
private _rateAccumulator;
|
|
2461
|
+
private _burstAccumulator;
|
|
2462
|
+
private _killSet;
|
|
2463
|
+
private _listener;
|
|
2464
|
+
private _destroyed;
|
|
2465
|
+
constructor(options: ParticleEmitterOptions);
|
|
2466
|
+
/** Live particle bodies. Read-only — do not mutate. */
|
|
2467
|
+
get active(): ReadonlyArray<Body>;
|
|
2468
|
+
/**
|
|
2469
|
+
* Per-particle age in seconds, indexed parallel to {@link active}.
|
|
2470
|
+
* Read-only — do not mutate. Useful for renderers that fade particles
|
|
2471
|
+
* by `age / lifetime`.
|
|
2472
|
+
*/
|
|
2473
|
+
get ages(): ReadonlyArray<number>;
|
|
2474
|
+
/**
|
|
2475
|
+
* Per-particle lifetime in seconds, indexed parallel to {@link active}.
|
|
2476
|
+
* Read-only — do not mutate.
|
|
2477
|
+
*/
|
|
2478
|
+
get lifetimes(): ReadonlyArray<number>;
|
|
2479
|
+
/** Number of bodies currently in the recycle pool. */
|
|
2480
|
+
get poolSize(): number;
|
|
2481
|
+
/** Total spawn count over the lifetime of this emitter. */
|
|
2482
|
+
get totalSpawned(): number;
|
|
2483
|
+
private _originXY;
|
|
2484
|
+
/** Sample a position in emitter-local space. */
|
|
2485
|
+
private _sampleSpawn;
|
|
2486
|
+
/** Sample initial velocity given the local spawn position. */
|
|
2487
|
+
private _sampleVelocity;
|
|
2488
|
+
private _sampleLifetime;
|
|
2489
|
+
private _buildBody;
|
|
2490
|
+
/** Take a body out of the pool, or build a new one. */
|
|
2491
|
+
private _acquire;
|
|
2492
|
+
/**
|
|
2493
|
+
* Reset a body's per-life mutable state and add it to the space at the
|
|
2494
|
+
* given world position with the given velocity.
|
|
2495
|
+
*/
|
|
2496
|
+
private _reviveBody;
|
|
2497
|
+
/**
|
|
2498
|
+
* Spawn `count` particles immediately. Returns the live bodies that were
|
|
2499
|
+
* spawned (length may be < `count` when the emitter is full and
|
|
2500
|
+
* `overflowPolicy` is `"drop-new"`).
|
|
2501
|
+
*/
|
|
2502
|
+
emit(count: number): Body[];
|
|
2503
|
+
/** Spawn a single particle. Returns the body or `null` if dropped. */
|
|
2504
|
+
private _spawnOne;
|
|
2505
|
+
/** Remove the live particle at `index` (swap-pop) and return it to the pool. */
|
|
2506
|
+
private _killAt;
|
|
2507
|
+
/**
|
|
2508
|
+
* Mark a body for death at the start of the next `update()` call. Safe to
|
|
2509
|
+
* call from inside collision callbacks. No-op if the body is not a live
|
|
2510
|
+
* particle of this emitter.
|
|
2511
|
+
*/
|
|
2512
|
+
requestKill(body: Body): void;
|
|
2513
|
+
private _flushKillSet;
|
|
2514
|
+
/** Kill every live particle. Bodies return to the pool. */
|
|
2515
|
+
killAll(): void;
|
|
2516
|
+
/**
|
|
2517
|
+
* Advance lifetimes, fire `onUpdate`, kill expired / out-of-bounds
|
|
2518
|
+
* particles, and run continuous / periodic spawning.
|
|
2519
|
+
*
|
|
2520
|
+
* Call once per frame, **before** `space.step()`. `dt` should match the
|
|
2521
|
+
* step size you'll pass to `space.step()`.
|
|
2522
|
+
*/
|
|
2523
|
+
update(dt: number): void;
|
|
2524
|
+
/**
|
|
2525
|
+
* Remove every body (live + pooled) from the space, drop the listener,
|
|
2526
|
+
* and mark the emitter unusable. Subsequent `update` / `emit` calls
|
|
2527
|
+
* throw.
|
|
2528
|
+
*/
|
|
2529
|
+
destroy(): void;
|
|
2530
|
+
private _installCollisionListener;
|
|
2531
|
+
}
|
|
2532
|
+
/**
|
|
2533
|
+
* Composable collection of {@link ParticleEmitter}s — analogous to
|
|
2534
|
+
* {@link RadialGravityFieldGroup}. One `update(dt)` runs every member emitter.
|
|
2535
|
+
*/
|
|
2536
|
+
declare class ParticleEmitterGroup {
|
|
2537
|
+
/** Ordered list of emitters. Mutate via {@link add} / {@link remove}. */
|
|
2538
|
+
readonly emitters: ParticleEmitter[];
|
|
2539
|
+
/** Add an emitter to the group and return it. */
|
|
2540
|
+
add(emitter: ParticleEmitter): ParticleEmitter;
|
|
2541
|
+
/** Remove an emitter from the group. Returns `true` if it was present. */
|
|
2542
|
+
remove(emitter: ParticleEmitter): boolean;
|
|
2543
|
+
/** Remove all emitters (does NOT call `destroy` on them). */
|
|
2544
|
+
clear(): void;
|
|
2545
|
+
/** Number of emitters currently in the group. */
|
|
2546
|
+
get length(): number;
|
|
2547
|
+
/** Advance every emitter. */
|
|
2548
|
+
update(dt: number): void;
|
|
2549
|
+
/** Call `destroy()` on every emitter and clear the group. */
|
|
2550
|
+
destroyAll(): void;
|
|
2551
|
+
}
|
|
2552
|
+
|
|
1863
2553
|
declare const VERSION: string;
|
|
1864
2554
|
|
|
1865
|
-
export { AABB, AngleJoint, Arbiter, Body, BodyCallback, BodyListener, BodyType, Callback, Capsule, CbEvent, CbType, CharacterController, type CharacterControllerOptions, Circle, CollisionArbiter, type ConcaveBodyOptions, Constraint, ConstraintCallback, ConstraintListener, Contact, DebugDrawFlags, DistanceJoint, type FractureOptions, type FractureResult, Geom, GeomPoly, InteractionCallback, InteractionFilter, InteractionListener, InteractionType, Interactor, LineJoint, Listener, MarchingSquares, MatMN, Material, MotorJoint, type MoveResult, OptionType, PivotJoint, PreCallback, PreFlag, PreListener, PulleyJoint, Shape, ShapeType, Space, SpringJoint, type TriggerHandler, TriggerZone, type TriggerZoneOptions, UserConstraint, VERSION, ValidationResult, Vec2, Vec3, type VoronoiCell, type VoronoiPoint, type VoronoiResult, WeldJoint, Winding, computeVoronoi, createConcaveBody, fractureBody, generateFractureSites };
|
|
2555
|
+
export { AABB, AngleJoint, Arbiter, Body, BodyCallback, type BodyFilter, BodyListener, BodyType, Callback, Capsule, CbEvent, CbType, CharacterController, type CharacterControllerOptions, Circle, CollisionArbiter, type ConcaveBodyOptions, Constraint, ConstraintCallback, ConstraintListener, Contact, DebugDrawFlags, DistanceJoint, type FractureOptions, type FractureResult, Geom, GeomPoly, type GravityFalloff, InteractionCallback, InteractionFilter, InteractionListener, InteractionType, Interactor, type LDtkIntGridLayer, LineJoint, Listener, MarchingSquares, MatMN, Material, MotorJoint, type MoveResult, OptionType, type ParticleBounds, type ParticleDeathReason, ParticleEmitter, ParticleEmitterGroup, type ParticleEmitterOptions, type ParticleOverflowPolicy, type ParticleShape, type ParticleSpawnState, PivotJoint, PreCallback, PreFlag, PreListener, PulleyJoint, RadialGravityField, RadialGravityFieldGroup, type RadialGravityFieldOptions, Shape, ShapeType, Space, type SpawnPattern, SpringJoint, type TiledTileLayer, type TilemapGrid, type TilemapMergeMode, type TilemapOptions, type TilemapRect, type TilemapSolidPredicate, type TilemapTileSize, type TriggerHandler, TriggerZone, type TriggerZoneOptions, UserConstraint, VERSION, ValidationResult, Vec2, Vec3, type VelocityPattern, type VoronoiCell, type VoronoiPoint, type VoronoiResult, WeldJoint, Winding, buildTilemapBody, computeVoronoi, createConcaveBody, fractureBody, generateFractureSites, ldtkLayerToGrid, meshTilemap, tiledLayerToGrid };
|