@adatechnology/game-destruction-three 0.11.1 → 0.12.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/README.md CHANGED
@@ -157,6 +157,12 @@ heatColor(temperatureC: number): number // 0xRRGGBB, 0 below ~450 C, dark red ~5
157
157
  `RendererOptions`: `scene`, `world`, `quality`, `maxFragments`, `maxParticles`, `fragmentLife`, `groundAt`, `gravity`, `autoSplit`, `onPiece`, `onSound`,
158
158
  `vfx` (shared effects world), `camera` (of the own world, when `vfx` is not given), `pointScale` (point size in pixels per metre at 1 m; about `viewportHeight / (2 tan(fov / 2))`, default 700).
159
159
 
160
+ How long debris stays: `fragmentLife` is the seconds a resting fragment stays before it shrinks away (default 12, `0` = forever), or a `FragmentLifeRule`
161
+ `(fragment, objectId) => seconds` that decides per fragment from its `material`, `size` and `shape` and the object it came from, e.g. rubble that stays and chips that go:
162
+ `fragmentLife: (f) => (Math.max(...f.size) > 0.1 ? 0 : f.material === 'glass' ? 30 : 12)`. `maxFragments` caps how many live at once (the oldest fades first).
163
+ Loose pieces (a door, a leg, a slab that breaks off whole) never fade: they stay in the map with collision. Dust, smoke and chip sprites have the life of their kind
164
+ in `@adatechnology/game-vfx` (`patchSpriteKinds(SPRITE_KINDS, { dust: { life: [10, 30] } })` on the effects world).
165
+
160
166
  `DestructionRenderer`: `bind`, `unbind`, `makePiece`, `pieces`, `piece`, `impulse`, `update`, `emit`, `explode(point, energy, radius, { effect?, direction?, visual? })` (`visual: false` keeps only the shove and the sound, for a host that played the effect itself), `clear`, `restore`, `stats`, `dispose`.
161
167
  `clear()` removes fragments, decals, puddles and particles from the scene and restores every bound mesh; `dispose()` also unsubscribes from the world.
162
168
 
package/dist/index.d.ts CHANGED
@@ -1,10 +1,13 @@
1
- import { Vec3, DebrisKind, HitResult, DestructionWorld, MaterialId, DestructibleSpec, MaterialDef } from '@adatechnology/game-destruction';
1
+ import { Fragment, Vec3, DebrisKind, HitResult, DestructionWorld, MaterialId, DestructibleSpec, MaterialDef } from '@adatechnology/game-destruction';
2
2
  export { Quat, Vec3 } from '@adatechnology/game-destruction';
3
3
  import * as THREE_NS from 'three';
4
4
  import { WarmUpProbes, BlastShoveOptions, Vec3 as Vec3$1 } from '@adatechnology/game-contracts';
5
5
  import { VfxWorld, SpriteKind } from '@adatechnology/game-vfx';
6
6
  import { LoopRecipe, SoundBank, SoundRecipe, AudioEngine } from '@adatechnology/game-audio';
7
7
 
8
+ /** What a fragment's resting time can depend on: the fragment (its material, size, shape) and the id of the object it came from. */
9
+ type FragmentLifeRule = (fragment: Fragment, objectId: string) => number;
10
+
8
11
  /**
9
12
  * Public types of @adatechnology/game-destruction-three.
10
13
  *
@@ -25,10 +28,19 @@ interface RendererOptions {
25
28
  quality?: Quality;
26
29
  /** Upper bound of live fragment meshes (default 160; oldest fade first). */
27
30
  maxFragments?: number;
31
+ /**
32
+ * Milliseconds of one `update` spent applying queued world events (default `Infinity`: every event is drawn
33
+ * in the `update` that receives it, so what a caller reads right after is final). A game loop sets a finite budget (the test room uses 8): what is left waits for the
34
+ * next frame, in order; at least one event is applied per frame, so 0 means one at a time.
35
+ */
36
+ eventBudgetMs?: number;
28
37
  /** Upper bound of live particles (default 2500). */
29
38
  maxParticles?: number;
30
- /** Seconds a resting fragment stays before it fades (default 12; 0 = forever). */
31
- fragmentLife?: number;
39
+ /**
40
+ * Seconds a resting fragment stays before it fades (default 12; 0 = forever). A rule gives it per fragment from its material, size and object, e.g. a brick chunk
41
+ * that stays as rubble and a chip that goes: `(f) => (Math.max(...f.size) > 0.1 ? 0 : f.material === 'glass' ? 30 : 12)`. Loose pieces (what breaks off whole) never fade.
42
+ */
43
+ fragmentLife?: number | FragmentLifeRule;
32
44
  /** Ground height at (x, z) for fragments, pieces and drips (default 0). */
33
45
  groundAt?: (x: number, z: number) => number;
34
46
  gravity?: number;
@@ -46,8 +58,8 @@ interface RendererOptions {
46
58
  * reaches with enough speed, the renderer makes it a piece (`makePiece`) and shoves it, and tells `onLoosened`. Without it only the pieces move. Never answer true for a wall or a fixture.
47
59
  */
48
60
  shoveable?: (objectId: string) => boolean;
49
- /** Called when a blast made a bound object a piece (see `shoveable`). */
50
- onLoosened?: (objectId: string, piece: Piece) => void;
61
+ /** Called when the renderer made a bound object a piece on its own: a blast shoved it (`blast`, see `shoveable`), or furniture came apart and what stayed is loose too (`apart`). */
62
+ onLoosened?: (objectId: string, piece: Piece, cause: 'blast' | 'apart') => void;
51
63
  /** Called when a sound should play; the host maps keys to audio (e.g. `impact_metal`, `shatter_glass`, `ignite`, `explode`). `burn_loop` is sent when a part starts to burn and `burn_end` when it burns out or is put out. */
52
64
  onSound?: (key: string, point: Vec3, volume: number) => void;
53
65
  /**
@@ -90,6 +102,8 @@ interface BindOptions {
90
102
  parts?: Record<string, Object3D | MeshRange | Array<Object3D | MeshRange>>;
91
103
  /** Keep the world transform in sync from the root's matrixWorld every update (default true). */
92
104
  syncTransform?: boolean;
105
+ /** Called from every `update`, after the queued events were applied: where the host finishes the drawing of this object that it deferred (a wall repainted once per frame). */
106
+ onFrame?: (dt: number) => void;
93
107
  }
94
108
  /** A body the renderer moves with its light physics: a loose piece of an object after a detach (or a whole object handed to it). */
95
109
  interface Piece {
@@ -171,6 +185,11 @@ interface DestructionRenderer {
171
185
  explode(point: Vec3, energy: number, radius: number, options?: ExplodeOptions): void;
172
186
  /** Remove every fragment, decal and particle, restore every bound mesh to its original geometry and colours. */
173
187
  clear(): void;
188
+ /**
189
+ * `clear` and back to the start: the random streams (the scatter of the shove points of a blast, the spin of the fragments) return to their seed and the clock to 0,
190
+ * so a run after it does what the same run does on a new renderer (a host that replays a scene, as the test room before each scenario).
191
+ */
192
+ reset(): void;
174
193
  /** Restore one object (after `world.reset`). */
175
194
  restore(objectId: string): void;
176
195
  stats(): {
@@ -211,7 +230,6 @@ interface SpecFromObjectResult {
211
230
  declare function impactKey(def: MaterialDef | undefined): string;
212
231
  /** Sound key (`drag_*`) of a base of this material dragged on a floor. */
213
232
  declare const dragSoundKey: (def: MaterialDef | undefined) => string;
214
- /** Create the renderer. See `DestructionRenderer`. */
215
233
  declare function createDestructionRenderer(THREE: ThreeNamespace, options: RendererOptions): DestructionRenderer;
216
234
 
217
235
  /** What `userData.destructionPart` says: a string (the part id) or an object `{ id, material?, parent?, kind? }`. */
@@ -226,7 +244,7 @@ interface PartHint {
226
244
  * axis-aligned box in metres in the root's frame (its position and rotation removed, its world scale kept; rotation omitted), with the material taken from `options.materialOf`, `userData.destructionMaterial`
227
245
  * or a guess from the names. Tiny meshes are merged into the part they overlap most; joints are inferred from touching parts.
228
246
  *
229
- * `userData.destructionContains` (`{ fluid, liters }`) makes the part a container: a hole through it leaks. `root.userData.destructionMass` (kg) fixes the total mass, split between the parts in proportion to their volume, density and fill.
247
+ * `userData.destructionContains` (`{ fluid, liters }`) makes the part a container: a hole through it leaks. `userData.destructionPowder` (`{ color }`) fills it with a dry powder or flakes that puff out of a hole. `root.userData.destructionMass` (kg) fixes the total mass, split between the parts in proportion to their volume, density and fill.
230
248
  * A mesh with `userData.destructionSkin` (a label, a coat) joins the part it overlaps most instead of becoming a part: it stays drawn and bound to that part (decals, dents) but never breaks off.
231
249
  * Meshes that are invisible or have `userData.destructionIgnore` (or sit under such an object) are skipped. The result also tells which meshes
232
250
  * became which part, ready to be passed to `bind`.
@@ -307,4 +325,4 @@ declare function createDestructionSound(engine: AudioEngine, options?: Destructi
307
325
  /** Every particle kind the renderer can emit (the game's sprite kinds, see `@adatechnology/game-vfx`). */
308
326
  type ParticleKind = SpriteKind;
309
327
 
310
- export { BURN_LOOP, type BindOptions, DEFAULT_FIRE, DESTRUCTION_SOUND_BANK, DESTRUCTION_SOUND_KEYS, DRAG_SOUNDS, type DestructionRenderer, type DestructionSound, type DestructionSoundOptions, type DestructionSoundStyle, EXPLOSION_BOOM, type ExplodeOptions, type LooseBody, type Mesh, type MeshRange, type Object3D, type PartHint, type ParticleKind, type Piece, type Quality, type RendererOptions, SCENE_SOUNDS, type SolidBox, type SoundKeyRule, type SpecFromObjectOptions, type SpecFromObjectResult, type ThreeNamespace, createDestructionRenderer, createDestructionSound, dragSoundKey, heatColor, impactKey, specFromObject3D };
328
+ export { BURN_LOOP, type BindOptions, DEFAULT_FIRE, DESTRUCTION_SOUND_BANK, DESTRUCTION_SOUND_KEYS, DRAG_SOUNDS, type DestructionRenderer, type DestructionSound, type DestructionSoundOptions, type DestructionSoundStyle, EXPLOSION_BOOM, type ExplodeOptions, type FragmentLifeRule, type LooseBody, type Mesh, type MeshRange, type Object3D, type PartHint, type ParticleKind, type Piece, type Quality, type RendererOptions, SCENE_SOUNDS, type SolidBox, type SoundKeyRule, type SpecFromObjectOptions, type SpecFromObjectResult, type ThreeNamespace, createDestructionRenderer, createDestructionSound, dragSoundKey, heatColor, impactKey, specFromObject3D };