@vworlds/vecs-physics 1.0.26 → 1.0.27
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/adapter/{state.d.ts → engine.d.ts} +12 -5
- package/adapter/{state.js → engine.js} +19 -21
- package/adapter/engine.js.map +1 -0
- package/adapter/queries.d.ts +68 -0
- package/adapter/queries.js +145 -0
- package/adapter/queries.js.map +1 -0
- package/adapter/runtime.d.ts +4 -0
- package/adapter/runtime.js +20 -0
- package/adapter/runtime.js.map +1 -1
- package/components/body.js +1 -1
- package/components/body.js.map +1 -1
- package/components/geometry.d.ts +15 -8
- package/components/geometry.js +26 -14
- package/components/geometry.js.map +1 -1
- package/components/material.d.ts +5 -0
- package/components/material.js +5 -0
- package/components/material.js.map +1 -1
- package/index.d.ts +3 -1
- package/index.js +4 -2
- package/index.js.map +1 -1
- package/module.js +25 -22
- package/module.js.map +1 -1
- package/package.json +2 -2
- package/systems/chain_lifecycle.d.ts +6 -0
- package/systems/chain_lifecycle.js +102 -0
- package/systems/chain_lifecycle.js.map +1 -0
- package/systems/debug.d.ts +2 -2
- package/systems/debug.js +17 -17
- package/systems/debug.js.map +1 -1
- package/systems/event_opt_in_sync.d.ts +2 -2
- package/systems/event_opt_in_sync.js +53 -28
- package/systems/event_opt_in_sync.js.map +1 -1
- package/systems/events.d.ts +2 -2
- package/systems/events.js +34 -34
- package/systems/events.js.map +1 -1
- package/systems/forces.d.ts +2 -2
- package/systems/forces.js +9 -9
- package/systems/forces.js.map +1 -1
- package/systems/impulse_accumulate.d.ts +3 -3
- package/systems/impulse_accumulate.js +28 -26
- package/systems/impulse_accumulate.js.map +1 -1
- package/systems/impulse_zero.d.ts +2 -2
- package/systems/impulse_zero.js +4 -4
- package/systems/impulse_zero.js.map +1 -1
- package/systems/index.d.ts +3 -3
- package/systems/index.js +31 -28
- package/systems/index.js.map +1 -1
- package/systems/kinematic.d.ts +2 -2
- package/systems/kinematic.js +26 -25
- package/systems/kinematic.js.map +1 -1
- package/systems/lifecycle.d.ts +2 -2
- package/systems/lifecycle.js +21 -21
- package/systems/lifecycle.js.map +1 -1
- package/systems/mass_recompute.d.ts +2 -2
- package/systems/mass_recompute.js +12 -12
- package/systems/mass_recompute.js.map +1 -1
- package/systems/material_filter_sync.d.ts +2 -2
- package/systems/material_filter_sync.js +48 -34
- package/systems/material_filter_sync.js.map +1 -1
- package/systems/pose_sync_in.d.ts +2 -2
- package/systems/pose_sync_in.js +14 -11
- package/systems/pose_sync_in.js.map +1 -1
- package/systems/pose_sync_out.d.ts +2 -2
- package/systems/pose_sync_out.js +6 -6
- package/systems/pose_sync_out.js.map +1 -1
- package/systems/shape_lifecycle.d.ts +29 -4
- package/systems/shape_lifecycle.js +46 -86
- package/systems/shape_lifecycle.js.map +1 -1
- package/systems/shape_pose_sync.d.ts +2 -2
- package/systems/shape_pose_sync.js +28 -13
- package/systems/shape_pose_sync.js.map +1 -1
- package/systems/shape_predicates.d.ts +8 -3
- package/systems/shape_predicates.js +3 -2
- package/systems/shape_predicates.js.map +1 -1
- package/systems/step.d.ts +2 -2
- package/systems/step.js +5 -5
- package/systems/step.js.map +1 -1
- package/util/resolve_body.d.ts +1 -1
- package/util/resolve_body.js +1 -3
- package/util/resolve_body.js.map +1 -1
- package/adapter/state.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ArrayMap, type EID, type World } from "@vworlds/vecs";
|
|
2
2
|
import { type WarnSink, WarnDedupe } from "../util/warn.js";
|
|
3
|
+
import { type PhysicsQueries } from "./queries.js";
|
|
3
4
|
import { type Box2DModule } from "./runtime.js";
|
|
4
5
|
export type EntityId = EID;
|
|
5
6
|
export type b2WorldId = ReturnType<Box2DModule["b2CreateWorld"]>;
|
|
@@ -7,6 +8,11 @@ export type b2BodyId = ReturnType<Box2DModule["b2CreateBody"]>;
|
|
|
7
8
|
export type b2ShapeId = ReturnType<Box2DModule["b2CreateCircleShape"]>;
|
|
8
9
|
export type b2ChainId = ReturnType<Box2DModule["b2CreateChain"]>;
|
|
9
10
|
export type b2Vec2 = ReturnType<Box2DModule["b2Body_GetPosition"]>;
|
|
11
|
+
export type b2QueryFilter = Parameters<Box2DModule["b2World_OverlapAABB"]>[2];
|
|
12
|
+
export type b2AABB = Parameters<Box2DModule["b2World_OverlapAABB"]>[1];
|
|
13
|
+
/** The transient result object passed to a `b2World_CastRay` collector callback
|
|
14
|
+
* (the binding types the callback parameter as `any`). */
|
|
15
|
+
export type b2RayCallbackResult = InstanceType<Box2DModule["b2RayCallbackResult"]>;
|
|
10
16
|
/** Fully-resolved engine configuration: every `PhysicsOptions` field with its
|
|
11
17
|
* default applied. Built by `PhysicsModule`; the source of truth for tunables
|
|
12
18
|
* the engine reads at runtime. */
|
|
@@ -33,10 +39,10 @@ export interface ResolvedPhysicsOptions {
|
|
|
33
39
|
export declare class PhysicsSystemTag {
|
|
34
40
|
}
|
|
35
41
|
export declare function registerInternalComponents(world: World): void;
|
|
36
|
-
export declare function
|
|
37
|
-
export declare function
|
|
38
|
-
export declare function
|
|
39
|
-
export declare class
|
|
42
|
+
export declare function attachPhysicsEngine(world: World, engine: PhysicsEngine): void;
|
|
43
|
+
export declare function getPhysicsEngine(world: World): PhysicsEngine;
|
|
44
|
+
export declare function hasPhysicsEngine(world: World): boolean;
|
|
45
|
+
export declare class PhysicsEngine {
|
|
40
46
|
worldId: b2WorldId;
|
|
41
47
|
readonly box2d: Box2DModule;
|
|
42
48
|
readonly gravityX: number;
|
|
@@ -69,6 +75,7 @@ export declare class PhysicsState {
|
|
|
69
75
|
value: number;
|
|
70
76
|
wake: boolean;
|
|
71
77
|
}>;
|
|
72
|
-
|
|
78
|
+
queries?: PhysicsQueries;
|
|
79
|
+
constructor();
|
|
73
80
|
constructor(box2d: Box2DModule, options: ResolvedPhysicsOptions, warnSink?: WarnSink);
|
|
74
81
|
}
|
|
@@ -8,30 +8,29 @@ import { WarnDedupe } from "../util/warn.js";
|
|
|
8
8
|
export class PhysicsSystemTag {
|
|
9
9
|
}
|
|
10
10
|
export function registerInternalComponents(world) {
|
|
11
|
-
world.component(
|
|
11
|
+
world.component(PhysicsEngine);
|
|
12
12
|
world.component(PhysicsSystemTag);
|
|
13
13
|
}
|
|
14
|
-
export function
|
|
15
|
-
world.component(
|
|
16
|
-
world.
|
|
14
|
+
export function attachPhysicsEngine(world, engine) {
|
|
15
|
+
world.component(PhysicsEngine).add(Singleton);
|
|
16
|
+
world.component(PhysicsEngine).attach(PhysicsEngine, engine);
|
|
17
17
|
}
|
|
18
|
-
export function
|
|
19
|
-
const
|
|
20
|
-
if (!
|
|
21
|
-
throw new Error("world.module(PhysicsModule) must be called before reading physics
|
|
18
|
+
export function getPhysicsEngine(world) {
|
|
19
|
+
const engine = world.get(PhysicsEngine);
|
|
20
|
+
if (!engine) {
|
|
21
|
+
throw new Error("world.module(PhysicsModule) must be called before reading physics engine");
|
|
22
22
|
}
|
|
23
|
-
return
|
|
23
|
+
return engine;
|
|
24
24
|
}
|
|
25
|
-
export function
|
|
26
|
-
if (!world._classRegistry.has(
|
|
25
|
+
export function hasPhysicsEngine(world) {
|
|
26
|
+
if (!world._classRegistry.has(PhysicsEngine)) {
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
return root?.state !== undefined;
|
|
29
|
+
return world.get(PhysicsEngine) !== undefined;
|
|
31
30
|
}
|
|
32
|
-
export class
|
|
31
|
+
export class PhysicsEngine {
|
|
33
32
|
constructor(box2d, options, warnSink) {
|
|
34
|
-
// Forward handles live on components: Body._bodyId and
|
|
33
|
+
// Forward handles live on components: Body._bodyId, SingleShape._shapeId, and Chain._chainId.
|
|
35
34
|
// Index-keyed reverse ArrayMaps resolve Box2D event IDs back to entities.
|
|
36
35
|
// Emscripten returns fresh wrapper objects for b2*Id fields on events, so
|
|
37
36
|
// Map<b2*Id, EntityId> misses by object identity. Public index1 slot 0 is
|
|
@@ -43,7 +42,7 @@ export class PhysicsState {
|
|
|
43
42
|
// Bodies whose mass needs recomputing this step (populated by shape lifecycle).
|
|
44
43
|
this.dirtyMassBodies = new Set();
|
|
45
44
|
// Per-step event tracking sets for PhysicsEvents (M7-8 should-fix: moved from
|
|
46
|
-
// closure-local to
|
|
45
|
+
// closure-local to engine so they survive future pause/resume cycles).
|
|
47
46
|
// Populated by PhysicsEvents at the end of each step; persist into the next
|
|
48
47
|
// step to detect which entities stopped receiving events.
|
|
49
48
|
this.prevTouchedContact = new Set();
|
|
@@ -59,6 +58,9 @@ export class PhysicsState {
|
|
|
59
58
|
// looking up event wrappers.
|
|
60
59
|
this.pendingLinearImpulse = new Map();
|
|
61
60
|
this.pendingAngularImpulse = new Map();
|
|
61
|
+
if (box2d === undefined || options === undefined) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
62
64
|
this.box2d = box2d;
|
|
63
65
|
this.gravityX = options.gravityX;
|
|
64
66
|
this.gravityY = options.gravityY;
|
|
@@ -74,10 +76,6 @@ export class PhysicsState {
|
|
|
74
76
|
this.maximumLinearSpeed = options.maximumLinearSpeed;
|
|
75
77
|
this.enableSleep = options.enableSleep;
|
|
76
78
|
this.enableContinuous = options.enableContinuous;
|
|
77
|
-
this.scratchVec2 = new box2d.b2Vec2();
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
|
-
|
|
81
|
-
class PhysicsRoot {
|
|
82
|
-
}
|
|
83
|
-
//# sourceMappingURL=state.js.map
|
|
81
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/adapter/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type Entity, type World } from "@vworlds/vecs";
|
|
2
|
+
import { type Vec2 } from "../components/geometry.js";
|
|
3
|
+
/** Category/mask filter applied to a query. Unlike a shape's own filter
|
|
4
|
+
* (default `categoryBits = 1`), a query's default `categoryBits` is
|
|
5
|
+
* `0xffffffff` so the query is not itself filtered out. */
|
|
6
|
+
export interface QueryFilter {
|
|
7
|
+
/** Bits this query "is". Default `0xffffffff` (matches every category). */
|
|
8
|
+
categoryBits?: number;
|
|
9
|
+
/** Bits this query "sees". Default `0xffffffff` (sees every category). */
|
|
10
|
+
maskBits?: number;
|
|
11
|
+
}
|
|
12
|
+
/** A single ray-cast hit, resolved to a Vecs shape entity with plain-data
|
|
13
|
+
* geometry — never a Box2D handle. */
|
|
14
|
+
export interface RayHit {
|
|
15
|
+
/** The shape entity that was hit. */
|
|
16
|
+
entity: Entity;
|
|
17
|
+
/** World-space hit point. */
|
|
18
|
+
point: Vec2;
|
|
19
|
+
/** World-space unit surface normal at the hit point. */
|
|
20
|
+
normal: Vec2;
|
|
21
|
+
/** Fraction along `from` → `to`, in `[0, 1]`. */
|
|
22
|
+
fraction: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stable, world-scoped facade for synchronous read-only physics queries: ray
|
|
26
|
+
* casts and spatial overlaps. Obtained via {@link physics}. Never mutates the
|
|
27
|
+
* world, never creates or destroys entities, and never wakes bodies.
|
|
28
|
+
*/
|
|
29
|
+
export interface PhysicsQueries {
|
|
30
|
+
/** Casts a ray from `from` to `to` and returns the closest hit, or `undefined`
|
|
31
|
+
* if the ray hits nothing (or only hits shapes whose entity has since been
|
|
32
|
+
* destroyed / removed). */
|
|
33
|
+
rayCastClosest(query: {
|
|
34
|
+
from: Vec2;
|
|
35
|
+
to: Vec2;
|
|
36
|
+
filter?: QueryFilter;
|
|
37
|
+
}): RayHit | undefined;
|
|
38
|
+
/** Casts a ray from `from` to `to` and returns every hit along the way. */
|
|
39
|
+
rayCastAll(query: {
|
|
40
|
+
from: Vec2;
|
|
41
|
+
to: Vec2;
|
|
42
|
+
filter?: QueryFilter;
|
|
43
|
+
}): RayHit[];
|
|
44
|
+
/** Returns every shape entity whose fat AABB overlaps `[min, max]`. This is
|
|
45
|
+
* a broad-phase query: it can over-report relative to exact shape
|
|
46
|
+
* overlap. */
|
|
47
|
+
overlapAABB(query: {
|
|
48
|
+
min: Vec2;
|
|
49
|
+
max: Vec2;
|
|
50
|
+
filter?: QueryFilter;
|
|
51
|
+
}): Entity[];
|
|
52
|
+
/** Returns every shape entity that precisely overlaps a circle centered at
|
|
53
|
+
* `center` with the given `radius`. */
|
|
54
|
+
overlapCircle(query: {
|
|
55
|
+
center: Vec2;
|
|
56
|
+
radius: number;
|
|
57
|
+
filter?: QueryFilter;
|
|
58
|
+
}): Entity[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the {@link PhysicsQueries} facade for `world`.
|
|
62
|
+
*
|
|
63
|
+
* Throws if `world.module(PhysicsModule)` has not been called (the error
|
|
64
|
+
* message comes from `getPhysicsEngine`). The returned facade is stable: repeated
|
|
65
|
+
* calls for the same world return the same instance, so it never
|
|
66
|
+
* re-allocates.
|
|
67
|
+
*/
|
|
68
|
+
export declare function physics(world: World): PhysicsQueries;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// M8-3 — Query foundation: `physics(world)` accessor + `PhysicsQueries` facade.
|
|
2
|
+
//
|
|
3
|
+
// The ONE narrow imperative entry point vecs-physics exposes: world-scoped,
|
|
4
|
+
// read-only queries against the live Box2D world. Results are always Vecs
|
|
5
|
+
// entities (shape entities) and plain data — never Box2D handles.
|
|
6
|
+
//
|
|
7
|
+
// box2d3-wasm imports are confined to `src/adapter/`; this file is part of
|
|
8
|
+
// that boundary. Scratch allocations (b2Vec2, b2QueryFilter, b2AABB) reuse
|
|
9
|
+
// global pools allocated at module load. Transient allocations like b2RayResult
|
|
10
|
+
// are freed via explicit `finally { .delete() }`.
|
|
11
|
+
import { scr_b2AABB, scr_b2QueryFilter, scr_b2Vec2 } from "./runtime.js";
|
|
12
|
+
import { getPhysicsEngine, } from "./engine.js";
|
|
13
|
+
/**
|
|
14
|
+
* Returns the {@link PhysicsQueries} facade for `world`.
|
|
15
|
+
*
|
|
16
|
+
* Throws if `world.module(PhysicsModule)` has not been called (the error
|
|
17
|
+
* message comes from `getPhysicsEngine`). The returned facade is stable: repeated
|
|
18
|
+
* calls for the same world return the same instance, so it never
|
|
19
|
+
* re-allocates.
|
|
20
|
+
*/
|
|
21
|
+
export function physics(world) {
|
|
22
|
+
const engine = getPhysicsEngine(world);
|
|
23
|
+
return (engine.queries ?? (engine.queries = new PhysicsQueriesImpl(world, engine)));
|
|
24
|
+
}
|
|
25
|
+
class PhysicsQueriesImpl {
|
|
26
|
+
constructor(world, engine) {
|
|
27
|
+
this.world = world;
|
|
28
|
+
this.engine = engine;
|
|
29
|
+
}
|
|
30
|
+
rayCastClosest(query) {
|
|
31
|
+
const { box2d, worldId } = this.engine;
|
|
32
|
+
const origin = scr_b2Vec2[0];
|
|
33
|
+
origin.Set(query.from.x, query.from.y);
|
|
34
|
+
const translation = scr_b2Vec2[1];
|
|
35
|
+
translation.Set(query.to.x - query.from.x, query.to.y - query.from.y);
|
|
36
|
+
const result = box2d.b2World_CastRayClosest(worldId, origin, translation, to_b2QueryFilter(query.filter));
|
|
37
|
+
try {
|
|
38
|
+
if (!result.hit) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
|
|
42
|
+
if (entity === undefined) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
entity,
|
|
47
|
+
point: { x: result.point.x, y: result.point.y },
|
|
48
|
+
normal: { x: result.normal.x, y: result.normal.y },
|
|
49
|
+
fraction: result.fraction,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
result.delete();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
rayCastAll(query) {
|
|
57
|
+
const { box2d, worldId } = this.engine;
|
|
58
|
+
const origin = scr_b2Vec2[0];
|
|
59
|
+
origin.Set(query.from.x, query.from.y);
|
|
60
|
+
const translation = scr_b2Vec2[1];
|
|
61
|
+
translation.Set(query.to.x - query.from.x, query.to.y - query.from.y);
|
|
62
|
+
const hits = [];
|
|
63
|
+
box2d.b2World_CastRay(worldId, origin, translation, to_b2QueryFilter(query.filter), (result) => {
|
|
64
|
+
const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
|
|
65
|
+
if (entity !== undefined) {
|
|
66
|
+
hits.push({
|
|
67
|
+
entity,
|
|
68
|
+
point: { x: result.point.x, y: result.point.y },
|
|
69
|
+
normal: { x: result.normal.x, y: result.normal.y },
|
|
70
|
+
fraction: result.fraction,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return 1;
|
|
74
|
+
});
|
|
75
|
+
return hits;
|
|
76
|
+
}
|
|
77
|
+
overlapAABB(query) {
|
|
78
|
+
const { box2d, worldId } = this.engine;
|
|
79
|
+
const aabb = scr_b2AABB;
|
|
80
|
+
aabb.lowerBound.Set(query.min.x, query.min.y);
|
|
81
|
+
aabb.upperBound.Set(query.max.x, query.max.y);
|
|
82
|
+
const entities = [];
|
|
83
|
+
const seen = new Set();
|
|
84
|
+
box2d.b2World_OverlapAABB(worldId, aabb, to_b2QueryFilter(query.filter), (result) => {
|
|
85
|
+
const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
|
|
86
|
+
if (entity !== undefined && !seen.has(entity.eid)) {
|
|
87
|
+
seen.add(entity.eid);
|
|
88
|
+
entities.push(entity);
|
|
89
|
+
}
|
|
90
|
+
return true;
|
|
91
|
+
});
|
|
92
|
+
return entities;
|
|
93
|
+
}
|
|
94
|
+
overlapCircle(query) {
|
|
95
|
+
const { box2d, worldId } = this.engine;
|
|
96
|
+
const centerVec = scr_b2Vec2[0];
|
|
97
|
+
centerVec.Set(query.center.x, query.center.y);
|
|
98
|
+
const proxy = box2d.b2MakeProxy(centerVec, 1, query.radius);
|
|
99
|
+
try {
|
|
100
|
+
const entities = [];
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
box2d.b2World_OverlapShape(worldId, proxy, to_b2QueryFilter(query.filter), (result) => {
|
|
103
|
+
const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
|
|
104
|
+
if (entity !== undefined && !seen.has(entity.eid)) {
|
|
105
|
+
seen.add(entity.eid);
|
|
106
|
+
entities.push(entity);
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
});
|
|
110
|
+
return entities;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
proxy.delete();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Maps a {@link QueryFilter} (default `0xffffffff`/`0xffffffff` — "sees and
|
|
118
|
+
* is seen by everything") and returns a scratch `b2QueryFilter`. `b2QueryFilter` is not
|
|
119
|
+
* `b2DefaultQueryFilter` here: the default-constructed filter is all zeros,
|
|
120
|
+
* which would match nothing.
|
|
121
|
+
* to_b2QueryFilter cannot be called again until the returned b2QueryFilter is no longer in use
|
|
122
|
+
* */
|
|
123
|
+
function to_b2QueryFilter(filter) {
|
|
124
|
+
const target = scr_b2QueryFilter[0];
|
|
125
|
+
target.categoryBits = filter?.categoryBits ?? 0xffffffff;
|
|
126
|
+
target.maskBits = filter?.maskBits ?? 0xffffffff;
|
|
127
|
+
return target;
|
|
128
|
+
}
|
|
129
|
+
/** Resolves a Box2D shape hit back to its Vecs shape entity, mirroring the
|
|
130
|
+
* `PhysicsEvents` shape→entity resolution (`src/systems/events.ts`):
|
|
131
|
+
* `entityByShapeIndex.get(shapeId.index1)` → `EID` → live `Entity`. Returns
|
|
132
|
+
* `undefined` (drop silently) if the slot is empty or the entity has been
|
|
133
|
+
* destroyed — the same rule as `PhysicsEvents`. */
|
|
134
|
+
function resolveShapeEntity(engine, world, shapeId) {
|
|
135
|
+
const eid = engine.entityByShapeIndex.get(shapeId.index1);
|
|
136
|
+
if (eid === undefined) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
const entity = world.getEntity(eid);
|
|
140
|
+
if (entity === undefined || entity.destroyed) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
return entity;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../../src/adapter/queries.ts"],"names":[],"mappings":"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"}
|
package/adapter/runtime.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import Box2DFactory from "box2d3-wasm";
|
|
2
|
+
import type { b2AABB, b2QueryFilter, b2Vec2 } from "./engine.js";
|
|
2
3
|
export type Box2DModule = Awaited<ReturnType<typeof Box2DFactory>>;
|
|
4
|
+
export declare const scr_b2Vec2: b2Vec2[];
|
|
5
|
+
export declare const scr_b2QueryFilter: b2QueryFilter[];
|
|
6
|
+
export declare let scr_b2AABB: b2AABB | null;
|
|
3
7
|
export declare function preloadPhysics(): Promise<void>;
|
|
4
8
|
export declare function getBox2D(): Box2DModule;
|
package/adapter/runtime.js
CHANGED
|
@@ -2,6 +2,11 @@ import { cpus } from "node:os";
|
|
|
2
2
|
import Box2DFactory from "box2d3-wasm";
|
|
3
3
|
let modulePromise = null;
|
|
4
4
|
let module = null;
|
|
5
|
+
// Global scratch pools for common Box2D structs. Allocated once at module load,
|
|
6
|
+
// reused across queries and other non-reentrant operations.
|
|
7
|
+
export const scr_b2Vec2 = [];
|
|
8
|
+
export const scr_b2QueryFilter = [];
|
|
9
|
+
export let scr_b2AABB = null;
|
|
5
10
|
export async function preloadPhysics() {
|
|
6
11
|
var _a;
|
|
7
12
|
if (modulePromise) {
|
|
@@ -14,10 +19,25 @@ export async function preloadPhysics() {
|
|
|
14
19
|
(_a = global.navigator).hardwareConcurrency ?? (_a.hardwareConcurrency = cpus().length);
|
|
15
20
|
modulePromise = Box2DFactory().then((loadedModule) => {
|
|
16
21
|
module = loadedModule;
|
|
22
|
+
initializeScratchPools(loadedModule);
|
|
17
23
|
return loadedModule;
|
|
18
24
|
});
|
|
19
25
|
await modulePromise;
|
|
20
26
|
}
|
|
27
|
+
function initializeScratchPools(box2d) {
|
|
28
|
+
// b2Vec2: ray casts need 2 simultaneous (origin + translation), polygon/chain creation
|
|
29
|
+
// can reuse serially. Allocate 3 for safety margin.
|
|
30
|
+
for (let i = 0; i < 3; i++) {
|
|
31
|
+
scr_b2Vec2.push(new box2d.b2Vec2());
|
|
32
|
+
}
|
|
33
|
+
// b2QueryFilter: queries and material_filter_sync each need at most 1 simultaneously.
|
|
34
|
+
// Allocate 2 for safety.
|
|
35
|
+
for (let i = 0; i < 2; i++) {
|
|
36
|
+
scr_b2QueryFilter.push(new box2d.b2QueryFilter());
|
|
37
|
+
}
|
|
38
|
+
// b2AABB: overlapAABB needs exactly 1.
|
|
39
|
+
scr_b2AABB = new box2d.b2AABB();
|
|
40
|
+
}
|
|
21
41
|
export function getBox2D() {
|
|
22
42
|
if (!module) {
|
|
23
43
|
throw new Error("Box2D module not loaded. Call `await preloadPhysics()` before `world.module(PhysicsModule)`.");
|
package/adapter/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../src/adapter/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,YAAY,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../src/adapter/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,YAAY,MAAM,aAAa,CAAC;AAMvC,IAAI,aAAa,GAAgC,IAAI,CAAC;AACtD,IAAI,MAAM,GAAuB,IAAI,CAAC;AAEtC,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAa,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAoB,EAAE,CAAC;AACrD,MAAM,CAAC,IAAI,UAAU,GAAkB,IAAI,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,cAAc;;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,aAAa,CAAC;QACpB,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,MAAM,GAAG,UAA2D,CAAC;IAC3E,MAAM,CAAC,SAAS,KAAhB,MAAM,CAAC,SAAS,GAAK,EAAE,EAAC;IACxB,MAAC,MAAM,CAAC,SAA8C,EAAC,mBAAmB,QAAnB,mBAAmB,GAAK,IAAI,EAAE,CAAC,MAAM,EAAC;IAE7F,aAAa,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE;QACnD,MAAM,GAAG,YAAY,CAAC;QACtB,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACrC,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;IACH,MAAM,aAAa,CAAC;AACtB,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAkB;IAChD,uFAAuF;IACvF,oDAAoD;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,sFAAsF;IACtF,yBAAyB;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,iBAAiB,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,uCAAuC;IACvC,UAAU,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/components/body.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Body-level components: the entity-marking `Body` plus the canonical pose and
|
|
2
|
-
// velocity
|
|
2
|
+
// velocity data. Defaults match Box2D's `b2DefaultBodyDef()` (see
|
|
3
3
|
// `box2d/src/types.c`). Public API — see `docs/components.md`.
|
|
4
4
|
//
|
|
5
5
|
// These are plain data classes: every field is initialised on the class body so
|
package/components/body.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../../../src/components/body.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../../../src/components/body.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kEAAkE;AAClE,+DAA+D;AAC/D,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAI3C,8CAA8C;AAC9C,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,gCAAgC;IAChC,6BAAiB,CAAA;IACjB,2EAA2E;IAC3E,mCAAuB,CAAA;IACvB,2DAA2D;IAC3D,+BAAmB,CAAA;AACrB,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAED,kFAAkF;AAClF,MAAM,OAAO,IAAI;IAAjB;QACE,SAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;QACvB,WAAM,GAAG,KAAK,CAAC;QACf,YAAO,GAAG,IAAI,CAAC;QACf,sBAAiB,GAAG,KAAK,CAAC;QAC1B,8FAA8F;QAC9F,YAAO,GAAyB,SAAS,CAAC;IAC5C,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,QAAQ;IAArB;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,8EAA8E;AAC9E,MAAM,OAAO,QAAQ;IAArB;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,cAAc;IAA3B;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,mDAAmD;AACnD,MAAM,OAAO,eAAe;IAA5B;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA"}
|
package/components/geometry.d.ts
CHANGED
|
@@ -4,13 +4,20 @@ export type Vec2 = {
|
|
|
4
4
|
y: number;
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Empty umbrella marker for the six geometry components. Every shape entity carries
|
|
8
8
|
* exactly one concrete geometry (`Box`, `Circle`, `Capsule`, `Segment`,
|
|
9
|
-
* `Polygon`, or `Chain`); each
|
|
10
|
-
*
|
|
9
|
+
* `Polygon`, or `Chain`); each implements `Shape` so queries and systems can
|
|
10
|
+
* match any geometry without enumerating every concrete type.
|
|
11
11
|
*/
|
|
12
12
|
export declare abstract class Shape {
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Internal marker for geometries backed by one Box2D `b2ShapeId`. Chains are
|
|
16
|
+
* intentionally excluded because Box2D creates them through `b2ChainId` and
|
|
17
|
+
* exposes their collision segments separately.
|
|
18
|
+
*/
|
|
19
|
+
export declare abstract class SingleShape extends Shape {
|
|
20
|
+
}
|
|
14
21
|
/**
|
|
15
22
|
* Axis-aligned box in local shape space, stored as half extents (`hx`/`hy`) to
|
|
16
23
|
* match Box2D's internal representation. The `width`/`height` accessors are
|
|
@@ -20,7 +27,7 @@ export declare abstract class Shape {
|
|
|
20
27
|
* still go through `entity.set(Box, …)` or `entity.modified(Box)` for physics
|
|
21
28
|
* to notice. See PLAN → Box accessors.
|
|
22
29
|
*/
|
|
23
|
-
export declare class Box extends
|
|
30
|
+
export declare class Box extends SingleShape {
|
|
24
31
|
hx: number;
|
|
25
32
|
hy: number;
|
|
26
33
|
get width(): number;
|
|
@@ -29,11 +36,11 @@ export declare class Box extends Shape {
|
|
|
29
36
|
set height(value: number);
|
|
30
37
|
}
|
|
31
38
|
/** Circle geometry. */
|
|
32
|
-
export declare class Circle extends
|
|
39
|
+
export declare class Circle extends SingleShape {
|
|
33
40
|
radius: number;
|
|
34
41
|
}
|
|
35
42
|
/** Capsule geometry: two local endpoints joined by a radius. */
|
|
36
|
-
export declare class Capsule extends
|
|
43
|
+
export declare class Capsule extends SingleShape {
|
|
37
44
|
x1: number;
|
|
38
45
|
y1: number;
|
|
39
46
|
x2: number;
|
|
@@ -41,7 +48,7 @@ export declare class Capsule extends Shape {
|
|
|
41
48
|
radius: number;
|
|
42
49
|
}
|
|
43
50
|
/** Line-segment geometry. */
|
|
44
|
-
export declare class Segment extends
|
|
51
|
+
export declare class Segment extends SingleShape {
|
|
45
52
|
x1: number;
|
|
46
53
|
y1: number;
|
|
47
54
|
x2: number;
|
|
@@ -52,7 +59,7 @@ export declare class Segment extends Shape {
|
|
|
52
59
|
* Convexity and vertex count are validated on shape creation, not on every
|
|
53
60
|
* update. See PLAN → Vec2 in Polygon / Chain.
|
|
54
61
|
*/
|
|
55
|
-
export declare class Polygon extends
|
|
62
|
+
export declare class Polygon extends SingleShape {
|
|
56
63
|
vertices: Vec2[];
|
|
57
64
|
radius: number;
|
|
58
65
|
}
|
package/components/geometry.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
// Geometry components. Exactly one per shape entity;
|
|
2
|
-
// `
|
|
3
|
-
// one evicts any previous geometry).
|
|
1
|
+
// Geometry components. Exactly one per shape entity; every concrete geometry
|
|
2
|
+
// implements the `Shape` umbrella so `PhysicsModule` enforces mutual exclusivity
|
|
3
|
+
// (setting one evicts any previous geometry). Single Box2D shapes also implement
|
|
4
|
+
// the internal `SingleShape` tier; `Chain` is separate because Box2D exposes it
|
|
5
|
+
// through `b2ChainId` plus underlying segment shapes.
|
|
4
6
|
// Public API — see `docs/components.md`.
|
|
5
7
|
//
|
|
6
8
|
// These are plain data classes: every field is initialised on the class body so
|
|
@@ -8,16 +10,22 @@
|
|
|
8
10
|
// contract). No imports from systems/ or adapter/ beyond type-only `b2*Id`
|
|
9
11
|
// handle types — components are pure data.
|
|
10
12
|
/**
|
|
11
|
-
*
|
|
13
|
+
* Empty umbrella marker for the six geometry components. Every shape entity carries
|
|
12
14
|
* exactly one concrete geometry (`Box`, `Circle`, `Capsule`, `Segment`,
|
|
13
|
-
* `Polygon`, or `Chain`); each
|
|
14
|
-
*
|
|
15
|
+
* `Polygon`, or `Chain`); each implements `Shape` so queries and systems can
|
|
16
|
+
* match any geometry without enumerating every concrete type.
|
|
15
17
|
*/
|
|
16
18
|
export class Shape {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Internal marker for geometries backed by one Box2D `b2ShapeId`. Chains are
|
|
22
|
+
* intentionally excluded because Box2D creates them through `b2ChainId` and
|
|
23
|
+
* exposes their collision segments separately.
|
|
24
|
+
*/
|
|
25
|
+
export class SingleShape extends Shape {
|
|
17
26
|
constructor() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* until then. */
|
|
27
|
+
super(...arguments);
|
|
28
|
+
/** @internal Engine-owned Box2D shape handle. Set by the single-shape lifecycle system. */
|
|
21
29
|
this._shapeId = undefined;
|
|
22
30
|
}
|
|
23
31
|
}
|
|
@@ -30,7 +38,7 @@ export class Shape {
|
|
|
30
38
|
* still go through `entity.set(Box, …)` or `entity.modified(Box)` for physics
|
|
31
39
|
* to notice. See PLAN → Box accessors.
|
|
32
40
|
*/
|
|
33
|
-
export class Box extends
|
|
41
|
+
export class Box extends SingleShape {
|
|
34
42
|
constructor() {
|
|
35
43
|
super(...arguments);
|
|
36
44
|
this.hx = 0.5;
|
|
@@ -50,14 +58,14 @@ export class Box extends Shape {
|
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
/** Circle geometry. */
|
|
53
|
-
export class Circle extends
|
|
61
|
+
export class Circle extends SingleShape {
|
|
54
62
|
constructor() {
|
|
55
63
|
super(...arguments);
|
|
56
64
|
this.radius = 0.5;
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
/** Capsule geometry: two local endpoints joined by a radius. */
|
|
60
|
-
export class Capsule extends
|
|
68
|
+
export class Capsule extends SingleShape {
|
|
61
69
|
constructor() {
|
|
62
70
|
super(...arguments);
|
|
63
71
|
this.x1 = -0.5;
|
|
@@ -68,7 +76,7 @@ export class Capsule extends Shape {
|
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
/** Line-segment geometry. */
|
|
71
|
-
export class Segment extends
|
|
79
|
+
export class Segment extends SingleShape {
|
|
72
80
|
constructor() {
|
|
73
81
|
super(...arguments);
|
|
74
82
|
this.x1 = -0.5;
|
|
@@ -82,7 +90,7 @@ export class Segment extends Shape {
|
|
|
82
90
|
* Convexity and vertex count are validated on shape creation, not on every
|
|
83
91
|
* update. See PLAN → Vec2 in Polygon / Chain.
|
|
84
92
|
*/
|
|
85
|
-
export class Polygon extends
|
|
93
|
+
export class Polygon extends SingleShape {
|
|
86
94
|
constructor() {
|
|
87
95
|
super(...arguments);
|
|
88
96
|
this.vertices = [];
|
|
@@ -93,6 +101,10 @@ export class Polygon extends Shape {
|
|
|
93
101
|
export class Chain extends Shape {
|
|
94
102
|
constructor() {
|
|
95
103
|
super(...arguments);
|
|
104
|
+
/** @internal Engine-owned Box2D chain handle. Set by the chain lifecycle system. */
|
|
105
|
+
this._chainId = undefined;
|
|
106
|
+
/** @internal Public shape indices of the chain's generated segment shapes. */
|
|
107
|
+
this._segmentIndices = [];
|
|
96
108
|
this.points = [];
|
|
97
109
|
this.loop = false;
|
|
98
110
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../../../src/components/geometry.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../../../src/components/geometry.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iFAAiF;AACjF,iFAAiF;AACjF,gFAAgF;AAChF,sDAAsD;AACtD,yCAAyC;AACzC,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAO3C;;;;;GAKG;AACH,MAAM,OAAgB,KAAK;CAAG;AAE9B;;;;GAIG;AACH,MAAM,OAAgB,WAAY,SAAQ,KAAK;IAA/C;;QACE,2FAA2F;QAC3F,aAAQ,GAA0B,SAAS,CAAC;IAC9C,CAAC;CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,GAAI,SAAQ,WAAW;IAApC;;QACE,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,GAAG,CAAC;IAiBX,CAAC;IAfC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,KAAK,CAAC,KAAa;QACrB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,CAAC,KAAa;QACtB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;CACF;AAED,uBAAuB;AACvB,MAAM,OAAO,MAAO,SAAQ,WAAW;IAAvC;;QACE,WAAM,GAAG,GAAG,CAAC;IACf,CAAC;CAAA;AAED,gEAAgE;AAChE,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;QACP,WAAM,GAAG,IAAI,CAAC;IAChB,CAAC;CAAA;AAED,6BAA6B;AAC7B,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;IACT,CAAC;CAAA;AAED;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,aAAQ,GAAW,EAAE,CAAC;QACtB,WAAM,GAAG,CAAC,CAAC;IACb,CAAC;CAAA;AAED,qEAAqE;AACrE,MAAM,OAAO,KAAM,SAAQ,KAAK;IAAhC;;QACE,oFAAoF;QACpF,aAAQ,GAA0B,SAAS,CAAC;QAC5C,8EAA8E;QAC9E,oBAAe,GAAa,EAAE,CAAC;QAC/B,WAAM,GAAW,EAAE,CAAC;QACpB,SAAI,GAAG,KAAK,CAAC;IACf,CAAC;CAAA"}
|
package/components/material.d.ts
CHANGED
|
@@ -16,3 +16,8 @@ export declare class CollisionFilter {
|
|
|
16
16
|
/** Marks a shape as an overlap-only sensor (no collision response). */
|
|
17
17
|
export declare class Sensor {
|
|
18
18
|
}
|
|
19
|
+
/** Marks a (typically solid) shape as detectable by sensor overlaps. Without it,
|
|
20
|
+
* Box2D v3 will not report this shape to overlapping sensors. It does NOT make
|
|
21
|
+
* the shape a sensor, and the shape does not itself receive sensor events. */
|
|
22
|
+
export declare class Detectable {
|
|
23
|
+
}
|
package/components/material.js
CHANGED
|
@@ -29,4 +29,9 @@ export class CollisionFilter {
|
|
|
29
29
|
/** Marks a shape as an overlap-only sensor (no collision response). */
|
|
30
30
|
export class Sensor {
|
|
31
31
|
}
|
|
32
|
+
/** Marks a (typically solid) shape as detectable by sensor overlaps. Without it,
|
|
33
|
+
* Box2D v3 will not report this shape to overlapping sensors. It does NOT make
|
|
34
|
+
* the shape a sensor, and the shape does not itself receive sensor events. */
|
|
35
|
+
export class Detectable {
|
|
36
|
+
}
|
|
32
37
|
//# sourceMappingURL=material.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"material.js","sourceRoot":"","sources":["../../../../src/components/material.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAC3E,4DAA4D;AAE5D,+EAA+E;AAC/E,MAAM,OAAO,QAAQ;IAArB;QACE,YAAO,GAAG,CAAC,CAAC;QACZ,aAAQ,GAAG,GAAG,CAAC;QACf,gBAAW,GAAG,CAAC,CAAC;QAChB,sBAAiB,GAAG,CAAC,CAAC;QACtB,iBAAY,GAAG,CAAC,CAAC;QACjB,mBAAc,GAAG,CAAC,CAAC;IACrB,CAAC;CAAA;AAED,kFAAkF;AAClF,MAAM,OAAO,eAAe;IAA5B;QACE,iBAAY,GAAG,CAAC,CAAC;QACjB,aAAQ,GAAG,UAAU,CAAC;QACtB,eAAU,GAAG,CAAC,CAAC;IACjB,CAAC;CAAA;AAED,uEAAuE;AACvE,MAAM,OAAO,MAAM;CAAG"}
|
|
1
|
+
{"version":3,"file":"material.js","sourceRoot":"","sources":["../../../../src/components/material.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAC3E,4DAA4D;AAE5D,+EAA+E;AAC/E,MAAM,OAAO,QAAQ;IAArB;QACE,YAAO,GAAG,CAAC,CAAC;QACZ,aAAQ,GAAG,GAAG,CAAC;QACf,gBAAW,GAAG,CAAC,CAAC;QAChB,sBAAiB,GAAG,CAAC,CAAC;QACtB,iBAAY,GAAG,CAAC,CAAC;QACjB,mBAAc,GAAG,CAAC,CAAC;IACrB,CAAC;CAAA;AAED,kFAAkF;AAClF,MAAM,OAAO,eAAe;IAA5B;QACE,iBAAY,GAAG,CAAC,CAAC;QACjB,aAAQ,GAAG,UAAU,CAAC;QACtB,eAAU,GAAG,CAAC,CAAC;IACjB,CAAC;CAAA;AAED,uEAAuE;AACvE,MAAM,OAAO,MAAM;CAAG;AAEtB;;8EAE8E;AAC9E,MAAM,OAAO,UAAU;CAAG"}
|
package/index.d.ts
CHANGED
|
@@ -4,7 +4,9 @@ export { Body, BodyType, Position, Rotation, LinearVelocity, AngularVelocity, }
|
|
|
4
4
|
export { Damping, GravityScale, MotionLocks, Sleep } from "./components/body_tuning.js";
|
|
5
5
|
export { ShapePosition, ShapeRotation } from "./components/shape_pose.js";
|
|
6
6
|
export { Shape, Box, Circle, Capsule, Segment, Polygon, Chain, type Vec2, } from "./components/geometry.js";
|
|
7
|
-
export { Material, CollisionFilter, Sensor } from "./components/material.js";
|
|
7
|
+
export { Material, CollisionFilter, Sensor, Detectable } from "./components/material.js";
|
|
8
8
|
export { Force, Torque, Impulse, AngularImpulse } from "./components/force.js";
|
|
9
9
|
export { KinematicTargetPosition, KinematicTargetRotation } from "./components/target.js";
|
|
10
10
|
export { ContactEvents, type ContactEvent, SensorEvents, type SensorEvent, HitEvents, type HitEvent, } from "./components/events.js";
|
|
11
|
+
export { physics } from "./adapter/queries.js";
|
|
12
|
+
export type { PhysicsQueries, QueryFilter, RayHit } from "./adapter/queries.js";
|