@adatechnology/game-destruction 0.6.0 → 0.7.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 +57 -2
- package/dist/index.d.ts +44 -8
- package/dist/index.global.js +379 -64
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +379 -64
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -181,6 +181,59 @@ panels), `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`, `glass_p
|
|
|
181
181
|
- **Holes stay on the pieces.** Every `fracture` and breach fragment carries `marks` (`FragmentMark`: point, normal and diameter in the fragment's own
|
|
182
182
|
axes) for the holes that fell inside it, at most 12 per fragment.
|
|
183
183
|
|
|
184
|
+
## Blasts: shelter, fragment hits and confinement
|
|
185
|
+
|
|
186
|
+
All three are options, **off by default** (a blast then does exactly what it always did, goldens included). Set them for the world with
|
|
187
|
+
`createDestruction({ blast: { shelter: true, ... } })`, or per call: `world.explode(point, energy, radius, source, { shelter: true })`, or on the
|
|
188
|
+
explosive `Hit` (`hit.blast`, `hit.confinement`). A call overrides the world default (`shelter: false` turns it off). Every number below is an
|
|
189
|
+
option; the defaults are exported as `SHELTER_DEFAULTS`, `FRAGMENT_HIT_DEFAULTS` and `CONFINEMENT_DEFAULTS`. This is the kit's own model (no team
|
|
190
|
+
delivery has it), approved by the owner on 2026-10-24.
|
|
191
|
+
|
|
192
|
+
**Shelter.** For each part (or impl) in range, a segment from the centre to the nearest point of the target is cut against every other part of
|
|
193
|
+
every object, skipping parts already lost and the target itself. A part crossed along a path `p` lets through `exp(-r / k)` of the energy, with
|
|
194
|
+
`r = hpPerKg * density * p * damageScale.shelter` (the hit points of the slab it crosses, per m²) and `k = 2800`. The energy that reaches the target
|
|
195
|
+
is `E * product(t_i)`, and it is used for both the damage and the push. Parts are served from the nearest to the farthest, so a wall takes the blast
|
|
196
|
+
(damage, dents, maybe breaking) before what is behind it. A blocker the same blast destroys or breaches lets `brokenTransmission` (0.5) of what it
|
|
197
|
+
held back go through: `t' = t + (1 - t) * 0.5`. An opening (a breach, a bare rebar cage) from before the blast lets everything through. Impls
|
|
198
|
+
(characters, animals) get one hit with the energy-weighted mean of the share that reaches their parts, and `Hit.shelter` carries it. Impls do not
|
|
199
|
+
shelter anything (they have no material).
|
|
200
|
+
|
|
201
|
+
| Blocker | Path | Lets through |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| glass pane | 6 mm | 83% (`damageScale.shelter: 3` in the material) |
|
|
204
|
+
| wooden door (softwood) | 4 cm | 53% |
|
|
205
|
+
| brick wall | 20 cm | 19% |
|
|
206
|
+
| reinforced concrete column | 30 cm | 3% |
|
|
207
|
+
|
|
208
|
+
**Fragment hits.** The fragments of a part the blast fractures or breaches (the `fracture` and `stage` events) become hits on the first part or impl
|
|
209
|
+
along their flight, in order of energy, at most `max` (24) per blast. Each is a `blunt` hit (or `ballistic` with its mass in grams and a calibre from
|
|
210
|
+
its size) of `energyFactor * m * v² / 2` (0.5), thrown up to `min(range 6 m, speed * flightTime 0.4 s)` within a seeded `spread` (10°) of its
|
|
211
|
+
direction. With `shelter` on, a fragment of a blocker whose line to a target is within `aim` (40°) of its flight goes for that target. The flights
|
|
212
|
+
depend only on the world seed, the blast and the fragment, never on what the world did before. Fragments of what a fragment breaks are not thrown
|
|
213
|
+
again. Events: `fragment_hit` (before the target's own events).
|
|
214
|
+
|
|
215
|
+
**Confinement.** `confinement: true` shoots `rays` (26) seeded rays from the centre as far as `radius * reach` (1.5) against the world's parts (impls
|
|
216
|
+
do not count; open doors, windows and breaches are absent parts). With `c` the share of rays that hit and `d` their mean distance:
|
|
217
|
+
`multiplier = min(max, 1 + gain * c^power * clamp(radius / d, 0, 2))` with `gain` 1.5, `power` 2, `max` 3. The energy of the whole blast is
|
|
218
|
+
multiplied. Open ground gives 1, a closed room of 6 m about 3, the same room with one wall missing about 2. A number (`confinement: 2.5`, or
|
|
219
|
+
`Hit.confinement`) is the multiplier itself, for a host that knows the room volume.
|
|
220
|
+
|
|
221
|
+
**What comes back.** `HitResult.blast = { shelter, parts?, confinement, fragmentHits }` per target (`shelter` is the most exposed part's share),
|
|
222
|
+
and one `blast` event per blast (`energy` after confinement, `shelter` per target, `fragmentHits`). `@adatechnology/game-destruction-three` takes
|
|
223
|
+
the results for the push on pieces: `renderer.explode(point, energy, radius, { report: results })`.
|
|
224
|
+
|
|
225
|
+
### Bullets and blasts against beams and columns
|
|
226
|
+
|
|
227
|
+
`tests/beams-and-columns.test.ts` documents calibres of `@adatechnology/game-weapons` against a reinforced concrete column and beam, a steel
|
|
228
|
+
I-beam, a hardwood beam and a brick pillar. Two options came out of it, both off or neutral by default:
|
|
229
|
+
|
|
230
|
+
- `Hit.piercing` (6th argument of `shoot`): how well the bullet cuts through for its energy; the energy compared with the penetration of a hard
|
|
231
|
+
material (metal, masonry) is `energy * piercing`. `PIERCING_BY_KIND` (fmj 1, hp 0.6, ap 1.6, buck 0.5, slug 0.25) and `PIERCING_BY_CALIBER`
|
|
232
|
+
(5.56, 5.45 and .22 0.5) give the numbers from `CaliberDef.kind` (`piercingOf(id, kind)`). Without it a 12 ga slug (3000 J) went through 8.5 mm of
|
|
233
|
+
steel.
|
|
234
|
+
- `breach.blastReach` (default `Infinity`, 0.12 recommended): a blast only opens a breach within `blastReach * cbrt(energy / 1000)` metres of the
|
|
235
|
+
part. With 0.12 a hand grenade (200 kJ) at 1 m no longer cuts a reinforced column in two (at 0.2 m it strips it).
|
|
236
|
+
|
|
184
237
|
## Contracts: implement your own or use the default world
|
|
185
238
|
|
|
186
239
|
The kit defines contracts; each game module implements them for the objects it owns, and the world in this package is the optional default
|
|
@@ -228,9 +281,9 @@ world continues with the same events as the original. The loading world must use
|
|
|
228
281
|
|
|
229
282
|
`createDestruction(options)` returns a `DestructionWorld`: `add`, `remove`, `has`, `ids`, `setTransform`, `splitGroup`, `hit`, `hitPart`, `explode`,
|
|
230
283
|
`raycast`, `shoot`, `disassemble`, `workableJoints`, `nearestJoint`, `extinguish`, `setLiters`, `update`, `state`, `part`, `reset`, `on`,
|
|
231
|
-
`register`, `serialize`, `load`, `time`. `state()` and `part()` return live views; do not mutate them.
|
|
284
|
+
`register`, `serialize`, `load`, `time`. `explode(point, energy, radius, source?, blastOptions?)`; `shoot(origin, direction, energy, caliber, source?, piercing?)`. `state()` and `part()` return live views; do not mutate them.
|
|
232
285
|
|
|
233
|
-
Also exported: `buildFrame`, `sizeStructure`, `assemblyPart`, `registerAssembly`, `getAssembly`, `ASSEMBLIES`, `assemblyDepth`, `partCapacity`, `checkDestructible`, `checkHit`, `IMPACT_CONTRACT`, `MATERIALS`, `JOINT_DEFAULTS`, `JOINT_BY_MATERIALS`, `inferJoints`, `guessMaterial`, `partVolume`, `partMass`, `partThickness`, the
|
|
286
|
+
Also exported: `SHELTER_DEFAULTS`, `FRAGMENT_HIT_DEFAULTS`, `CONFINEMENT_DEFAULTS`, `PIERCING_BY_KIND`, `PIERCING_BY_CALIBER`, `piercingOf`, `buildFrame`, `sizeStructure`, `assemblyPart`, `registerAssembly`, `getAssembly`, `ASSEMBLIES`, `assemblyDepth`, `partCapacity`, `checkDestructible`, `checkHit`, `IMPACT_CONTRACT`, `MATERIALS`, `JOINT_DEFAULTS`, `JOINT_BY_MATERIALS`, `inferJoints`, `guessMaterial`, `partVolume`, `partMass`, `partThickness`, the
|
|
234
287
|
helpers `vec`, `quat`, `quatFromEuler`, `rotateVec`, `toLocal`, `toWorld`, the locale (`locales`, `resolveStrings`, `DestructionStrings`) and all types.
|
|
235
288
|
|
|
236
289
|
The locale table has `en` and `pt-BR` strings for material names, part statuses, joint kinds, tools, damage types, event labels and fracture styles:
|
|
@@ -244,3 +297,5 @@ plástico derretem e pingam. As juntas cedem com impacto, quando a peça é dest
|
|
|
244
297
|
parafuso, chave inglesa para porca e parafuso, maçarico para solda). O mundo devolve tudo como eventos para o renderizador desenhar. É
|
|
245
298
|
determinístico (semente fixa) e serializável, então um host de LAN pode rodar o mundo e enviar só as entradas. Os nomes em português
|
|
246
299
|
(materiais, ferramentas, juntas, eventos) estão em `resolveStrings('pt-BR')`.
|
|
300
|
+
|
|
301
|
+
Explosões: `blast.shelter` (paredes e portas entre a explosão e o alvo ficam com a sua parte: tijolo de 20 cm deixa passar ~19%, porta de madeira ~53%, vidro ~83%; a parede que quebra na mesma explosão deixa passar metade do que segurou), `blast.fragmentHits` (os pedaços do que quebra viram golpes de baixa energia no que está atrás) e `blast.confinement` (pressão num ambiente fechado, de 1 a 3 vezes). Tudo desligado por padrão, por opção do mundo ou da chamada, com os números em `SHELTER_DEFAULTS`, `FRAGMENT_HIT_DEFAULTS` e `CONFINEMENT_DEFAULTS`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, ToolKind, JointState, PartState, DestructionEventType, StructureRole, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape, SurfaceLayer, PartUnits, Reinforcement, PartBreach, PartStatus } from '@adatechnology/game-contracts';
|
|
2
|
-
export { ChainDelay, Crack, DamageStage, DamageType, DebrisKind, Dent, DestructibleImpl, DestructibleSpec, DestructionEvent, DestructionEventType, ExplosionChain, FluidKind, FractureStyle, Fragment, FragmentMark, Hit, HitResult, Hole, IMPACT_CONTRACT, ImpactContract, JointKind, JointSpec, JointState, MaterialId, ObjectState, PartBreach, PartShape, PartSpec, PartState, PartStatus, PartUnits, Quat, RayHit, Reinforcement, StructureRole, SurfaceLayer, ToolKind, Vec3, checkHit } from '@adatechnology/game-contracts';
|
|
1
|
+
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, BlastOptions, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, ToolKind, JointState, PartState, DestructionEventType, StructureRole, ConfinementOptions, FragmentHitOptions, ShelterOptions, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape, SurfaceLayer, PartUnits, Reinforcement, PartBreach, PartStatus } from '@adatechnology/game-contracts';
|
|
2
|
+
export { BlastOptions, BlastReport, ChainDelay, ConfinementOptions, Crack, DamageStage, DamageType, DebrisKind, Dent, DestructibleImpl, DestructibleSpec, DestructionEvent, DestructionEventType, ExplosionChain, FluidKind, FractureStyle, Fragment, FragmentHitOptions, FragmentMark, Hit, HitResult, Hole, IMPACT_CONTRACT, ImpactContract, JointKind, JointSpec, JointState, MaterialId, ObjectState, PartBreach, PartShape, PartSpec, PartState, PartStatus, PartUnits, Quat, RayHit, Reinforcement, ShelterOptions, StructureRole, SurfaceLayer, ToolKind, Vec3, checkHit } from '@adatechnology/game-contracts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Public types of @adatechnology/game-destruction.
|
|
@@ -52,8 +52,8 @@ interface MaterialDef {
|
|
|
52
52
|
fracture: FractureStyle;
|
|
53
53
|
/** Fragment size range in metres (default `[0.04, 0.2]`). */
|
|
54
54
|
fragmentSize?: [number, number];
|
|
55
|
-
/** Damage multipliers per damage type (default 1). */
|
|
56
|
-
damageScale?: Partial<Record<DamageType, number>>;
|
|
55
|
+
/** Damage multipliers per damage type (default 1); `shelter` multiplies the resistance the material adds between a blast and a target (`blast.shelter`). */
|
|
56
|
+
damageScale?: Partial<Record<DamageType | 'shelter', number>>;
|
|
57
57
|
/** Debris emitted on a hit that does not break the part. */
|
|
58
58
|
hitDebris: DebrisKind;
|
|
59
59
|
/** Debris emitted when the part fractures. */
|
|
@@ -101,12 +101,23 @@ interface DestructionOptions {
|
|
|
101
101
|
radius?: number;
|
|
102
102
|
/** Multiplier of the breach area a blast makes over a blow of the same damage: a blast loads the whole crater (default 6). */
|
|
103
103
|
blastFactor?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Metres of reach per cube root of kilojoule: a blast only opens a breach in a part within `blastReach * cbrt(energy / 1000)` of the centre
|
|
106
|
+
* (a hand grenade of 200 kJ: 0.7 m; 2 MJ: 1.5 m). Farther away it still damages, dents and cracks. Without it a falloff that is gentle over a
|
|
107
|
+
* large radius let a grenade at 1 m cut a reinforced column in two. Default `Infinity` (off, so the goldens stay as they were); 0.12 is the value that matches real charges.
|
|
108
|
+
*/
|
|
109
|
+
blastReach?: number;
|
|
104
110
|
};
|
|
105
111
|
/**
|
|
106
112
|
* Speed of the blast front in m/s. A glass part at distance `d` from an explosion breaks `d / blastFrontSpeed` seconds later, in `update`
|
|
107
113
|
* (the speed of sound is 340). Default off: every part takes the blast at once.
|
|
108
114
|
*/
|
|
109
115
|
blastFrontSpeed?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Defaults of every blast (`explode`, an explosive `hit`, a part that explodes); each call can override them. All off by default, and a world
|
|
118
|
+
* with all of them off gives the results it always gave. See `ShelterOptions`, `FragmentHitOptions` and `ConfinementOptions`.
|
|
119
|
+
*/
|
|
120
|
+
blast?: BlastOptions;
|
|
110
121
|
}
|
|
111
122
|
interface SizeStructureOptions {
|
|
112
123
|
/** Stress every structural part has at rest after sizing (`load / capacity`), 0..1 (default 0.65). */
|
|
@@ -161,12 +172,16 @@ interface DestructionWorld {
|
|
|
161
172
|
hit(objectId: string, hit: Hit): HitResult;
|
|
162
173
|
/** Apply a hit to a known part (e.g. after the host's own raycast). */
|
|
163
174
|
hitPart(objectId: string, partId: string, hit: Hit): HitResult;
|
|
164
|
-
/**
|
|
165
|
-
|
|
175
|
+
/**
|
|
176
|
+
* A blast in world space against every object in range. With `options` (else `DestructionOptions.blast`) the blast can be sheltered by what
|
|
177
|
+
* stands in the way, throw the fragments of what it breaks and gain pressure in an enclosed volume; each `HitResult.blast` says what it did to
|
|
178
|
+
* that target, and a `blast` event sums it up.
|
|
179
|
+
*/
|
|
180
|
+
explode(point: Vec3, energy: number, radius: number, source?: string, options?: BlastOptions): HitResult[];
|
|
166
181
|
/** Raycast against every part shape (world space). */
|
|
167
182
|
raycast(origin: Vec3, direction: Vec3, maxDistance?: number): RayHit | null;
|
|
168
183
|
/** Ballistic shot: raycast, hit, and continue through with the exit energy (up to 4 objects/parts). */
|
|
169
|
-
shoot(origin: Vec3, direction: Vec3, energy: number, caliber: number, source?: string): HitResult[];
|
|
184
|
+
shoot(origin: Vec3, direction: Vec3, energy: number, caliber: number, source?: string, piercing?: number): HitResult[];
|
|
170
185
|
/**
|
|
171
186
|
* Work on a joint with a tool for `dt` seconds (call every frame while the player holds the button). Returns the progress 0..1, or -1 when the
|
|
172
187
|
* tool cannot undo this joint. At 1 the joint opens (`detach` with `by: 'tool'`).
|
|
@@ -257,6 +272,15 @@ interface DestructionSnapshot {
|
|
|
257
272
|
}>;
|
|
258
273
|
}
|
|
259
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Blast options (all off until asked for). Shelter: a part the line from the blast to the target crosses lets through `exp(-r / k)`, `r` being the
|
|
277
|
+
* hit points of the slab it crosses per square metre (`hpPerKg * density * path * damageScale.shelter`). Fragment hits: up to 24 fragments, half their
|
|
278
|
+
* kinetic energy lands as a blunt hit, thrown at most 6 m (and `speed * 0.4 s`) within 10 degrees of their aim. Confinement: 26 rays reaching
|
|
279
|
+
* `1.5 * radius`, multiplier `1 + 1.5 * closedShare^2 * clamp(radius / meanDistance, 0, 2)` up to 3.
|
|
280
|
+
*/
|
|
281
|
+
declare const SHELTER_DEFAULTS: Required<ShelterOptions>;
|
|
282
|
+
declare const FRAGMENT_HIT_DEFAULTS: Required<FragmentHitOptions>;
|
|
283
|
+
declare const CONFINEMENT_DEFAULTS: Required<ConfinementOptions>;
|
|
260
284
|
declare const createDestruction: (options?: DestructionOptions) => DestructionWorld;
|
|
261
285
|
|
|
262
286
|
/** What can set an explosive part off from outside, in the order a hit can carry it. */
|
|
@@ -280,6 +304,18 @@ interface ExplosivePartOptions {
|
|
|
280
304
|
*/
|
|
281
305
|
declare const explosivePart: (explosive: WorldExplosive, part: Omit<PartSpec, "explodes">, options?: ExplosivePartOptions) => PartSpec;
|
|
282
306
|
|
|
307
|
+
/**
|
|
308
|
+
* How well a bullet cuts through for its energy (`Hit.piercing`, the 6th argument of `shoot`). The material's `penetration` is joules per
|
|
309
|
+
* millimetre for a hard bullet; soft lead deforms on steel and concrete and a core of hardened steel does better. A host that knows the kind
|
|
310
|
+
* of the bullet (`CaliberDef.kind` of `@adatechnology/game-weapons`) takes the number from here, or replaces the tables with its own.
|
|
311
|
+
*
|
|
312
|
+
* Reference: a 12 ga slug (3000 J) does not go through 8 mm of mild steel, a .50 BMG (18000 J) goes through 20 mm and more.
|
|
313
|
+
*/
|
|
314
|
+
declare const PIERCING_BY_KIND: Readonly<Record<string, number>>;
|
|
315
|
+
/** Caliber ids whose bullet is lighter on the target than its kind says (a soft-core 5.56 ball does not go through a steel flange). */
|
|
316
|
+
declare const PIERCING_BY_CALIBER: Readonly<Record<string, number>>;
|
|
317
|
+
declare const piercingOf: (caliber: string, kind?: string) => number;
|
|
318
|
+
|
|
283
319
|
/** Built-in materials (data in `src/data/materials.json`). Override or extend with the `materials` option of `createDestruction`. */
|
|
284
320
|
declare const MATERIALS: MaterialDef[];
|
|
285
321
|
/** Default joint strength (joint hit points), tools that undo it and seconds of tool work. */
|
|
@@ -481,4 +517,4 @@ declare const checkDestructible: (impl: DestructibleImpl, options?: CheckOptions
|
|
|
481
517
|
problems: string[];
|
|
482
518
|
};
|
|
483
519
|
|
|
484
|
-
export { ASSEMBLIES, type AddOptions, type AssemblyDef, type AssemblyPartOptions, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, type FrameOptions, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MATERIALS, type MaterialDef, type MaterialThermal, type ObjectRuntime, type PartRuntime, type SizeStructureOptions, type WorldExplosive, assemblyDepth, assemblyPart, buildFrame, checkDestructible, createDestruction, explosivePart, fragility, getAssembly, guessMaterial, inferJoints, locales, partCapacity, partMass, partThickness, partVolume, quat, quatFromEuler, registerAssembly, resolveStrings, rotateVec, sizeStructure, toLocal, toWorld, vec };
|
|
520
|
+
export { ASSEMBLIES, type AddOptions, type AssemblyDef, type AssemblyPartOptions, CONFINEMENT_DEFAULTS, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, FRAGMENT_HIT_DEFAULTS, type FrameOptions, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MATERIALS, type MaterialDef, type MaterialThermal, type ObjectRuntime, PIERCING_BY_CALIBER, PIERCING_BY_KIND, type PartRuntime, SHELTER_DEFAULTS, type SizeStructureOptions, type WorldExplosive, assemblyDepth, assemblyPart, buildFrame, checkDestructible, createDestruction, explosivePart, fragility, getAssembly, guessMaterial, inferJoints, locales, partCapacity, partMass, partThickness, partVolume, piercingOf, quat, quatFromEuler, registerAssembly, resolveStrings, rotateVec, sizeStructure, toLocal, toWorld, vec };
|