incanto 0.64.1 → 0.66.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/2d.d.ts +38 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +130 -3
- package/dist/3d.js +5 -5
- package/dist/{audio-player-D5GJgb_x.d.ts → audio-player-_UAcHxnC.d.ts} +1 -1
- package/dist/{behavior-DsgayMsH.d.ts → behavior-BXNLfIJk.d.ts} +128 -0
- package/dist/{create-game-B746rYbr.js → create-game-DYJCIzO0.js} +67 -6
- package/dist/{create-game-B1KM6dA6.js → create-game-Dd7H4bJV.js} +6 -6
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-BOOKmkQ7.js → duplicate-CqSAtdrh.js} +1 -1
- package/dist/{environment-presets-D2vzw583.js → environment-presets-BlPsEmq6.js} +70 -6
- package/dist/{gameplay-CLgFdkh5.js → gameplay-D1RADWu3.js} +374 -18
- package/dist/gameplay.d.ts +94 -3
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -5
- package/dist/{loader-DolLJWJn.d.ts → loader-Cga7FVP4.d.ts} +1 -1
- package/dist/{loader-zDynoew_.js → loader-lQDCwNag.js} +59 -3
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{physics-2d-BPJcJRRP.js → physics-2d-Cji5A6sX.js} +32 -4
- package/dist/{physics-3d-BOO58xzw.js → physics-3d-BkHjwJgI.js} +49 -5
- package/dist/{quiet-rapier-BAJ4K94N.js → quiet-rapier-C6fW4zcW.js} +14 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-Btm7_Emq.js → register-BmuqYTiY.js} +44 -1
- package/dist/{register-dGsbnJ87.js → register-D0CxCveZ.js} +38 -4
- package/dist/{replay-C5x2vPF5.d.ts → replay-BHoB6fCU.d.ts} +1 -1
- package/dist/{replay-DKRmiVjk.js → replay-IsZbNu6d.js} +2 -2
- package/dist/{split-screen-Dx0LvzqS.js → split-screen-D_i7GRcY.js} +2 -2
- package/dist/{split-screen-D7OopelJ.d.ts → split-screen-eJUFjhi1.d.ts} +2 -2
- package/dist/{src-CNS2xQB1.js → src-BTLbXFPZ.js} +1 -1
- package/dist/{teardown-BwhkcNt8.js → teardown-byR9USax.js} +1 -1
- package/dist/{test-Ccob3X5i.js → test-DgrD0jHD.js} +13 -13
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-Di-UEn5O.js → agent8-9N-Pd_YS.js} +1 -1
- package/editor/assets/{debug-DWztJ5_y.js → debug-CkbJICYp.js} +1 -1
- package/editor/assets/{index-fct4H89G.js → index-CeDhIPTC.js} +53 -53
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +19 -0
- package/skills/incanto-3d-character.md +11 -1
- package/skills/incanto-behaviors-and-scripts.md +21 -0
- package/skills/incanto-gameplay-behaviors.md +177 -9
- package/skills/incanto-node-reference.md +59 -1
- package/skills/incanto-physics-and-input.md +84 -1
- package/skills/incanto-web-integration.md +24 -3
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/coverage.json +0 -9
- package/templates-app/platformer-2d/coverage.json +0 -5
- package/templates-app/star-survivor/coverage.json +0 -5
- package/templates-app/tps-3d/coverage.json +0 -5
- package/templates-app/village-quest-3d/coverage.json +0 -9
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, t as Behavior } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
@@ -11,6 +11,8 @@ import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
|
11
11
|
* it leaves), so wire it to an attack.
|
|
12
12
|
* - `loseRange` (>0) gives up the chase when the target gets that far away,
|
|
13
13
|
* emitting `lostTarget` once.
|
|
14
|
+
* - `facePath`/`turnSpeed` turn a skin toward the direction of travel — the job
|
|
15
|
+
* `CharacterController3D` does for the player and nobody did for an NPC.
|
|
14
16
|
* - `moveParent` (default false) moves the parent node instead of this one.
|
|
15
17
|
* A node carries ONE behavior, so an enemy whose ROOT must hold `Health`
|
|
16
18
|
* (e.g. for `Health.freeOnDeath` clone-safe cleanup) puts `Chase` on a CHILD
|
|
@@ -25,6 +27,8 @@ declare class Chase extends Behavior {
|
|
|
25
27
|
stopRange: number;
|
|
26
28
|
loseRange: number;
|
|
27
29
|
moveParent: boolean;
|
|
30
|
+
facePath: string;
|
|
31
|
+
turnSpeed: number;
|
|
28
32
|
private inRange;
|
|
29
33
|
private lost;
|
|
30
34
|
override onReady(): void;
|
|
@@ -56,6 +60,37 @@ declare class Collector extends Behavior {
|
|
|
56
60
|
override deserialize(data: JsonValue): void;
|
|
57
61
|
}
|
|
58
62
|
//#endregion
|
|
63
|
+
//#region src/gameplay/currency.d.ts
|
|
64
|
+
/**
|
|
65
|
+
* Money. Earn it, spend it, and refuse what you cannot afford.
|
|
66
|
+
*
|
|
67
|
+
* `ScoreKeeper` is the closest thing the library had and it is a SCORE: it
|
|
68
|
+
* counts up, it has no spend, no affordability question, and its counter is
|
|
69
|
+
* already wired to the win condition. So a tower defense built on 0.65.0 wrote
|
|
70
|
+
* its own wallet — and so does every shop, every build mode, every upgrade tree
|
|
71
|
+
* and every economy game.
|
|
72
|
+
*
|
|
73
|
+
* `spend` is the whole point: it returns whether it went through, and emits
|
|
74
|
+
* `refused` when it did not, so "you cannot afford that" is a wire rather than
|
|
75
|
+
* a comparison every caller repeats and one caller forgets.
|
|
76
|
+
*/
|
|
77
|
+
declare class Currency extends Behavior {
|
|
78
|
+
static readonly props: PropSchema;
|
|
79
|
+
static readonly signals: readonly string[];
|
|
80
|
+
amount: number;
|
|
81
|
+
max: number;
|
|
82
|
+
/** Can this be paid right now? */
|
|
83
|
+
canAfford(cost: number): boolean;
|
|
84
|
+
/** Pay `cost` if it is there. Returns whether it went through. */
|
|
85
|
+
spend(cost: number): boolean;
|
|
86
|
+
/** Take payment in. */
|
|
87
|
+
earn(gain: number): void;
|
|
88
|
+
/** Set it outright (a shop that grants, a cheat, a restore). */
|
|
89
|
+
setAmount(next: number): void;
|
|
90
|
+
override serialize(): JsonValue;
|
|
91
|
+
override deserialize(data: JsonValue): void;
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
59
94
|
//#region src/gameplay/health.d.ts
|
|
60
95
|
/**
|
|
61
96
|
* Hit points with regeneration and post-hit invulnerability (i-frames) —
|
|
@@ -158,7 +193,9 @@ declare class Health extends Behavior {
|
|
|
158
193
|
* - `repeatEvery` (seconds, 0 = off) re-damages targets that STAY overlapped —
|
|
159
194
|
* lava pools, poison clouds, an enemy standing on you. Contact events fire
|
|
160
195
|
* only on entry/exit; this is the "and it keeps hurting" knob.
|
|
161
|
-
* - `destroySelf` frees the hazard after a hit (single-use projectiles)
|
|
196
|
+
* - `destroySelf` frees the hazard after a hit (single-use projectiles), and
|
|
197
|
+
* `freeParent` makes that free the PARENT — a bullet whose hitbox is a child,
|
|
198
|
+
* which is the only shape a node-carries-one-script engine allows.
|
|
162
199
|
*
|
|
163
200
|
* SCORING PATTERN (clone-safe): wire the KILLER's `dealtDamage` →
|
|
164
201
|
* `ScoreKeeper.addScore`. The weapon is usually a non-cloned node (it lives on
|
|
@@ -173,6 +210,7 @@ declare class DamageOnContact extends Behavior {
|
|
|
173
210
|
oncePerTarget: boolean;
|
|
174
211
|
repeatEvery: number;
|
|
175
212
|
destroySelf: boolean;
|
|
213
|
+
freeParent: boolean;
|
|
176
214
|
private readonly hit;
|
|
177
215
|
/** Targets currently overlapping → seconds until their next repeat tick. */
|
|
178
216
|
private readonly inside;
|
|
@@ -181,6 +219,42 @@ declare class DamageOnContact extends Behavior {
|
|
|
181
219
|
private tryDamage;
|
|
182
220
|
}
|
|
183
221
|
//#endregion
|
|
222
|
+
//#region src/gameplay/face-target.d.ts
|
|
223
|
+
/**
|
|
224
|
+
* Turn toward the nearest thing in a group, and say when you are on it.
|
|
225
|
+
*
|
|
226
|
+
* A turret is the shape every tower defense, sentry gun, security camera and
|
|
227
|
+
* idle-NPC-that-watches-you needs, and it could not be composed. `Chase`
|
|
228
|
+
* already finds the nearest target and turns toward it — and then MOVES, which
|
|
229
|
+
* is the one thing a turret must not do; `Patrol`/`Chase`'s `facePath` only
|
|
230
|
+
* turns as a side effect of locomotion, so a stationary node cannot use it.
|
|
231
|
+
* A tower defense built on 0.65.0 hand-wrote acquisition (~20 lines) and
|
|
232
|
+
* turn-and-gate-the-shot (~15) because of that.
|
|
233
|
+
*
|
|
234
|
+
* `aimed` fires when the facing settles onto the target and `lostAim` when it
|
|
235
|
+
* comes off, so "only fire while actually pointed at it" is a wire rather than
|
|
236
|
+
* an angle comparison you write yourself.
|
|
237
|
+
*/
|
|
238
|
+
declare class FaceTarget extends Behavior {
|
|
239
|
+
static readonly props: PropSchema;
|
|
240
|
+
static readonly signals: readonly string[];
|
|
241
|
+
targetGroup: string;
|
|
242
|
+
range: number;
|
|
243
|
+
facePath: string;
|
|
244
|
+
turnSpeed: number;
|
|
245
|
+
aimTolerance: number;
|
|
246
|
+
/** The node currently being tracked, or null. */
|
|
247
|
+
target: Node | null;
|
|
248
|
+
/** True while the facing is within `aimTolerance` of the target. */
|
|
249
|
+
onTarget: boolean;
|
|
250
|
+
override onReady(): void;
|
|
251
|
+
override update(dt: number): void;
|
|
252
|
+
private nearest;
|
|
253
|
+
/** Is the turret's forward within tolerance of the direction to the target? */
|
|
254
|
+
private pointedAt;
|
|
255
|
+
private setAim;
|
|
256
|
+
}
|
|
257
|
+
//#endregion
|
|
184
258
|
//#region src/gameplay/follow-camera.d.ts
|
|
185
259
|
/**
|
|
186
260
|
* Make the node it sits on chase a target's position — THE camera-follow
|
|
@@ -235,6 +309,10 @@ declare class Interactable extends Behavior {
|
|
|
235
309
|
* pickups that vanish. Accumulates `dt`; on elapse emits `expired` then
|
|
236
310
|
* `queueFree()`s its node.
|
|
237
311
|
*
|
|
312
|
+
* `freeParent: true` frees the node's PARENT instead — the shape a bullet needs,
|
|
313
|
+
* since a node carries ONE script so `Projectile`, the damage and the timer have
|
|
314
|
+
* to live on separate nodes.
|
|
315
|
+
*
|
|
238
316
|
* With `startOnSignal: true` the countdown is armed manually via `startTimer()`
|
|
239
317
|
* (wire a signal → `startTimer`), so the lifetime begins on an event rather
|
|
240
318
|
* than at spawn.
|
|
@@ -244,6 +322,7 @@ declare class Lifetime extends Behavior {
|
|
|
244
322
|
static readonly signals: readonly string[];
|
|
245
323
|
seconds: number;
|
|
246
324
|
startOnSignal: boolean;
|
|
325
|
+
freeParent: boolean;
|
|
247
326
|
private elapsed;
|
|
248
327
|
private running;
|
|
249
328
|
private fired;
|
|
@@ -327,6 +406,13 @@ declare class Oscillate extends Behavior {
|
|
|
327
406
|
*
|
|
328
407
|
* - `loop` (default) — after the last point, head back to the first.
|
|
329
408
|
* - `mode: 'pingpong'` — reverse direction at each end instead of wrapping.
|
|
409
|
+
* - `moveParent` (default false) moves the parent node instead of this one,
|
|
410
|
+
* exactly as `Chase` does. A node carries ONE behavior, so a guard that must
|
|
411
|
+
* patrol AND hold `Health` on its body puts `Patrol` on a CHILD. Without
|
|
412
|
+
* this the patrolling body had to carry `Patrol` itself and could hold
|
|
413
|
+
* nothing else — so a patrolling enemy could not be hurt.
|
|
414
|
+
* - `facePath`/`turnSpeed` turn a skin toward the direction of travel, the job
|
|
415
|
+
* `CharacterController3D` does for the player and nobody did for an NPC.
|
|
330
416
|
*/
|
|
331
417
|
declare class Patrol extends Behavior {
|
|
332
418
|
static readonly props: PropSchema;
|
|
@@ -336,11 +422,16 @@ declare class Patrol extends Behavior {
|
|
|
336
422
|
loop: boolean;
|
|
337
423
|
mode: string;
|
|
338
424
|
pauseAt: number;
|
|
425
|
+
moveParent: boolean;
|
|
426
|
+
facePath: string;
|
|
427
|
+
turnSpeed: number;
|
|
339
428
|
private index;
|
|
340
429
|
private direction;
|
|
341
430
|
private pauseTimer;
|
|
342
431
|
override onReady(): void;
|
|
343
432
|
override update(dt: number): void;
|
|
433
|
+
/** Turn the skin toward the step just taken. */
|
|
434
|
+
private face;
|
|
344
435
|
/** Waypoints already reported dead, so a per-frame stall says it once. */
|
|
345
436
|
private readonly reportedDead;
|
|
346
437
|
/**
|
|
@@ -971,4 +1062,4 @@ declare function registerGameplayBehaviors(opts?: {
|
|
|
971
1062
|
replace?: boolean;
|
|
972
1063
|
}): void;
|
|
973
1064
|
//#endregion
|
|
974
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, type DayPhase, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, type GameFlowState, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
|
1065
|
+
export { CameraShake, Chase, Collector, Cooldown, Currency, DamageOnContact, DayNight, type DayPhase, FaceTarget, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, type GameFlowState, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
|
1
|
+
import { A as DamageOnContact, C as restartScene, D as FaceTarget, E as FloatAway, M as Currency, N as Collector, O as DayNight, P as Chase, S as goToScene, T as FollowCamera, _ as Cooldown, a as Wander, b as Interactable, c as SavePoint, d as Patrol, f as PathFollow, g as CameraShake, h as Lifetime, i as WaveSpawner, j as Health, k as phaseOf, l as Projectile, m as MoveTo, n as registerGameplayBehaviors, o as Spawner, p as Oscillate, r as ZombieAI, s as ScoreKeeper, t as GAMEPLAY_BEHAVIORS, u as Pickup, v as hitStop, x as GameFlow, y as screenFlash } from "./gameplay-D1RADWu3.js";
|
|
2
|
+
export { CameraShake, Chase, Collector, Cooldown, Currency, DamageOnContact, DayNight, FaceTarget, FloatAway, FollowCamera, GAMEPLAY_BEHAVIORS, GameFlow, Health, Interactable, Lifetime, MoveTo, Oscillate, PathFollow, Patrol, Pickup, Projectile, SavePoint, ScoreKeeper, Spawner, Wander, WaveSpawner, ZombieAI, goToScene, hitStop, phaseOf, registerGameplayBehaviors, restartScene, screenFlash };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { $ as T_PREFIX, A as SettingsValues, At as BusName, B as captureBehaviors, C as EngineStats, Ct as sfxDuration, Dt as MusicTrack, E as DeviceHints, Et as MusicManager, F as BehaviorState, Ft as LogLevel, G as ORDER_GROUP_BASE, H as savesWithoutUid, I as RestoreReport, It as LogManager, J as effectiveOrder, K as OrderGroup, L as SaveSlot, Lt as Signal, M as readDeviceHints, Mt as NodeLifecycle, N as suggestQuality, Nt as SceneTree, O as QualityTier, Ot as PlayMusicOptions, P as Scene, Pt as LogEntry, Q as Localization, R as SaveSlots, Rt as SignalListener, S as Scheduler, St as SynthOptions, T as RendererStats, Tt as MusicBackend, U as SaveStore, V as restoreBehaviors, W as createSaveStore, X as BASE_LOCALE, Y as resolveOrderGroups, Z as LocaleTables, _ as mergeStaticSignals, _t as spatialPan, a as clearBehaviors, at as EffectLog, b as Engine, bt as SfxParams, c as registeredBehaviors, ct as isAudioContextAvailable, d as PropSchema, dt as Listener, et as suggestLocale, f as clearRegistry, ft as ROLLOFF_MODELS, g as getNodeType, gt as spatialGain, h as getNodeSignals, ht as Vec3, i as behaviorSignals, it as EffectKind, j as qualityEnvironment, jt as Node, k as Settings, kt as AudioBuses, l as NodeCtor, lt as Voice, m as getNodeSchema, mt as SpatialParams, n as BehaviorCtor, nt as InputMap, o as getBehavior, ot as SfxEngine, p as createNode, pt as RolloffModel, q as OrderGroupTable, r as behaviorSchema, rt as EffectEvent, s as registerBehavior, st as SfxPlayOptions, t as Behavior, tt as translationKey, u as PropDef, ut as VoicePreset, v as registerNode, vt as SFX_PRESETS, w as GameStats, wt as synthSfx, x as EngineOptions, xt as SfxWave, y as registeredTypes, yt as SFX_PRESET_NAMES, z as behaviorsWithoutSave } from "./behavior-
|
|
1
|
+
import { $ as T_PREFIX, A as SettingsValues, At as BusName, B as captureBehaviors, C as EngineStats, Ct as sfxDuration, Dt as MusicTrack, E as DeviceHints, Et as MusicManager, F as BehaviorState, Ft as LogLevel, G as ORDER_GROUP_BASE, H as savesWithoutUid, I as RestoreReport, It as LogManager, J as effectiveOrder, K as OrderGroup, L as SaveSlot, Lt as Signal, M as readDeviceHints, Mt as NodeLifecycle, N as suggestQuality, Nt as SceneTree, O as QualityTier, Ot as PlayMusicOptions, P as Scene, Pt as LogEntry, Q as Localization, R as SaveSlots, Rt as SignalListener, S as Scheduler, St as SynthOptions, T as RendererStats, Tt as MusicBackend, U as SaveStore, V as restoreBehaviors, W as createSaveStore, X as BASE_LOCALE, Y as resolveOrderGroups, Z as LocaleTables, _ as mergeStaticSignals, _t as spatialPan, a as clearBehaviors, at as EffectLog, b as Engine, bt as SfxParams, c as registeredBehaviors, ct as isAudioContextAvailable, d as PropSchema, dt as Listener, et as suggestLocale, f as clearRegistry, ft as ROLLOFF_MODELS, g as getNodeType, gt as spatialGain, h as getNodeSignals, ht as Vec3, i as behaviorSignals, it as EffectKind, j as qualityEnvironment, jt as Node, k as Settings, kt as AudioBuses, l as NodeCtor, lt as Voice, m as getNodeSchema, mt as SpatialParams, n as BehaviorCtor, nt as InputMap, o as getBehavior, ot as SfxEngine, p as createNode, pt as RolloffModel, q as OrderGroupTable, r as behaviorSchema, rt as EffectEvent, s as registerBehavior, st as SfxPlayOptions, t as Behavior, tt as translationKey, u as PropDef, ut as VoicePreset, v as registerNode, vt as SFX_PRESETS, w as GameStats, wt as synthSfx, x as EngineOptions, xt as SfxWave, y as registeredTypes, yt as SFX_PRESET_NAMES, z as behaviorsWithoutSave } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
import { a as Rng, c as JsonValue, d as jsonKind, i as SceneJson, l as jsonClone, n as NodeJson, o as JsonKind, r as SCENE_FORMAT, s as JsonObject, t as ConnectionJson, u as jsonEquals } from "./schema-CFeioQRE.js";
|
|
3
|
-
import { n as loadScene, t as LoadSceneOptions } from "./loader-
|
|
3
|
+
import { n as loadScene, t as LoadSceneOptions } from "./loader-Cga7FVP4.js";
|
|
4
4
|
import { i as resolveFrames, n as AnimationEntry, r as resolveAnimation, t as AnimationDef } from "./sprite-animation-CMr6f1K2.js";
|
|
5
|
-
import { a as ParticleSimConfig, i as ParticleSim, n as AudioPlayer, o as ParticleView, t as AudioElementLike } from "./audio-player-
|
|
5
|
+
import { a as ParticleSimConfig, i as ParticleSim, n as AudioPlayer, o as ParticleView, t as AudioElementLike } from "./audio-player-_UAcHxnC.js";
|
|
6
6
|
import { i as gridFromRows, n as PathGrid, r as findPath, t as FindPathOptions } from "./pathfinding-_fGrCFmH.js";
|
|
7
|
-
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-
|
|
7
|
+
import { a as startRecording, c as IncantoErrorDetails, i as replay, l as auditScene, n as ReplayEvent, o as IncantoError, r as ReplayJson, s as IncantoErrorCode, t as Recorder } from "./replay-BHoB6fCU.js";
|
|
8
8
|
|
|
9
9
|
//#region src/core/audio/crossfade.d.ts
|
|
10
10
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-
|
|
2
|
-
import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-
|
|
1
|
+
import { A as describeRefProblem, B as registeredBehaviors, C as ORDER_GROUP_BASE, E as InputMap, F as behaviorSchema, I as behaviorSignals, L as clearBehaviors, M as resolveRefInJson, N as parseNodePath, O as Node, P as Behavior, R as getBehavior, S as createSaveStore, T as resolveOrderGroups, V as Signal, _ as SaveSlots, a as serializeNode, b as restoreBehaviors, d as computeViewport, f as resolveViewport, g as resolveConstants, h as isConstRef, i as Scene, j as nodeRefWarnings, m as CONST_REF_KEY, n as loadScene, o as SCENE_FORMAT, p as SceneTree, v as behaviorsWithoutSave, w as effectiveOrder, x as savesWithoutUid, y as captureBehaviors, z as registerBehavior } from "./loader-lQDCwNag.js";
|
|
2
|
+
import { A as UiBanner, B as isAudioContextAvailable, D as EffectLog, E as LogManager, F as T_PREFIX, G as SFX_PRESET_NAMES, H as spatialGain, I as suggestLocale, J as MusicManager, K as sfxDuration, M as UiText, N as BASE_LOCALE, O as HudLayer, P as Localization, Q as AudioBuses, R as translationKey, S as qualityEnvironment, T as suggestQuality, U as spatialPan, V as ROLLOFF_MODELS, W as SFX_PRESETS, X as crossfadeGains, Y as WebAudioMusicBackend, Z as fadeGain, _ as AudioPlayer, a as UiMuteToggle, b as Settings, c as UiRenderScaleSelect, d as UiToggle, f as UiVolumeSlider, g as UiDialogue, h as UiButton, i as UiLanguageSelect, j as UiBar, l as UiSelect, m as Respawn, n as UiFrameCapSelect, o as UiPanel, p as Timer, q as synthSfx, r as UiImage, s as UiQualitySelect, t as registerCoreNodes, u as UiSlider, v as Engine, w as readDeviceHints, z as SfxEngine } from "./register-BmuqYTiY.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { n as jsonEquals, r as jsonKind, t as jsonClone } from "./json-CwwhxQgb.js";
|
|
6
6
|
import { a as getNodeSignals, c as mergeStaticSignals, i as getNodeSchema, l as registerNode, n as clearRegistry, o as getNodeType, r as createNode, u as registeredTypes } from "./registry-CF70EArN.js";
|
|
7
|
-
import { n as startRecording, r as auditScene, t as replay } from "./replay-
|
|
7
|
+
import { n as startRecording, r as auditScene, t as replay } from "./replay-IsZbNu6d.js";
|
|
8
8
|
import { a as logReport, i as resolveRendering, n as attachTouchControls, o as logText, r as joystickVector, s as parseDrive, t as TouchControls } from "./touch-DESwnpOc.js";
|
|
9
9
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
10
10
|
import { a as PARTICLE_PRESETS, i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-CY-mrr1L.js";
|
|
11
|
-
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-
|
|
12
|
-
import { t as duplicateNode } from "./duplicate-
|
|
11
|
+
import { a as preloadUrls, i as preloadSceneAssets, n as newUid, o as findPath, r as assetUrls, s as gridFromRows, t as VERSION } from "./src-BTLbXFPZ.js";
|
|
12
|
+
import { t as duplicateNode } from "./duplicate-CqSAtdrh.js";
|
|
13
13
|
export { AudioBuses, AudioPlayer, BASE_LOCALE, Behavior, CONST_REF_KEY, EffectLog, Engine, HudLayer, IncantoError, InputMap, Localization, LogManager, MusicManager, Node, ORDER_GROUP_BASE, PARTICLE_PRESETS, PARTICLE_PRESET_NAMES, ParticleSim, ROLLOFF_MODELS, Respawn, Rng, SCENE_FORMAT, SFX_PRESETS, SFX_PRESET_NAMES, SaveSlots, Scene, SceneTree, Settings, SfxEngine, Signal, T_PREFIX, Timer, TouchControls, UiBanner, UiBar, UiButton, UiDialogue, UiFrameCapSelect, UiImage, UiLanguageSelect, UiMuteToggle, UiPanel, UiQualitySelect, UiRenderScaleSelect, UiSelect, UiSlider, UiText, UiToggle, UiVolumeSlider, VERSION, WebAudioMusicBackend, applyParticlePreset, assetUrls, attachTouchControls, auditScene, behaviorSchema, behaviorSignals, behaviorsWithoutSave, captureBehaviors, clearBehaviors, clearRegistry, computeViewport, createNode, createNoise2D, createSaveStore, crossfadeGains, describeRefProblem, duplicateNode, effectiveOrder, fadeGain, findPath, getBehavior, getNodeSchema, getNodeSignals, getNodeType, gridFromRows, isAudioContextAvailable, isConstRef, joystickVector, jsonClone, jsonEquals, jsonKind, loadScene, logReport, logText, mergeStaticSignals, newUid, nodeRefWarnings, parseDrive, parseNodePath, preloadSceneAssets, preloadUrls, qualityEnvironment, readDeviceHints, registerBehavior, registerCoreNodes, registerNode, registeredBehaviors, registeredTypes, replay, resolveAnimation, resolveConstants, resolveFrames, resolveOrderGroups, resolveRefInJson, resolveRendering, resolveViewport, restoreBehaviors, savesWithoutUid, serializeNode, sfxDuration, spatialGain, spatialPan, startRecording, suggestLocale, suggestQuality, synthSfx, translationKey };
|
|
@@ -42,7 +42,47 @@ var Signal = class {
|
|
|
42
42
|
* schema/defaults/delta model as node props.
|
|
43
43
|
*/
|
|
44
44
|
var Behavior = class {
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Every behavior accepts `enabled`, inherited down the static chain — see
|
|
47
|
+
* `enabled` below for why it is a universal prop rather than one each AI
|
|
48
|
+
* behavior declares for itself.
|
|
49
|
+
*/
|
|
50
|
+
static props = { enabled: { default: true } };
|
|
51
|
+
/**
|
|
52
|
+
* Whether this behavior's `update`/`fixedUpdate` run. `false` stops it
|
|
53
|
+
* without removing it — and this is what makes ENEMY AI expressible in JSON.
|
|
54
|
+
*
|
|
55
|
+
* A node holds ONE behavior, so `Patrol` and `Chase` cannot share one. Both
|
|
56
|
+
* can ride child nodes with `moveParent`, but then both run at once, and
|
|
57
|
+
* before this nothing could stop either — so "patrols until it spots you,
|
|
58
|
+
* then chases", the most ordinary AI there is, had to be hand-written in
|
|
59
|
+
* TypeScript, which is exactly what the gameplay library exists to prevent.
|
|
60
|
+
* With this the whole state machine is two wires:
|
|
61
|
+
*
|
|
62
|
+
* ```jsonc
|
|
63
|
+
* { "signal": "spotted", "from": "Eyes", "to": "Walk", "handler": "disable" },
|
|
64
|
+
* { "signal": "spotted", "from": "Eyes", "to": "Hunt", "handler": "enable" }
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* `Clickable` had already hand-rolled this exact prop for itself. One
|
|
68
|
+
* behavior needed it and solved it locally; nothing generalized it.
|
|
69
|
+
*
|
|
70
|
+
* Asleep is NOT detached: the behavior keeps its props and its accumulated
|
|
71
|
+
* state, stays reachable as `node.behavior`, keeps its signal connections,
|
|
72
|
+
* and still saves through `serialize()`. Only the per-frame hooks pause. The
|
|
73
|
+
* lifecycle hooks (`onEnterTree`/`onReady`/`onExitTree`) are not gated — they
|
|
74
|
+
* are structural, they fire once, and a behavior that skipped its own
|
|
75
|
+
* `onReady` would wake up uninitialized.
|
|
76
|
+
*/
|
|
77
|
+
enabled = true;
|
|
78
|
+
/** Start running again — a connection handler, so a wire can do it. */
|
|
79
|
+
enable() {
|
|
80
|
+
this.enabled = true;
|
|
81
|
+
}
|
|
82
|
+
/** Stop running without being removed — a connection handler. */
|
|
83
|
+
disable() {
|
|
84
|
+
this.enabled = false;
|
|
85
|
+
}
|
|
46
86
|
/**
|
|
47
87
|
* Custom signals this behavior emits via `this.emit(...)` — declared onto
|
|
48
88
|
* its node at load. Undeclared emits are hard errors (typo safety).
|
|
@@ -68,6 +108,22 @@ var Behavior = class {
|
|
|
68
108
|
get log() {
|
|
69
109
|
return this.engine.log;
|
|
70
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* The physics world, for the queries AI asks — `castRay` for line of sight,
|
|
113
|
+
* `castSphere` for a probe that must not skim past a wall.
|
|
114
|
+
*
|
|
115
|
+
* ```ts
|
|
116
|
+
* const hit = this.physics?.castRay(eye, dir, range, this.node);
|
|
117
|
+
* const blocked = hit !== null && hit.node !== player;
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* `null` in a game with no physics, so a behavior that only sometimes needs
|
|
121
|
+
* a ray degrades instead of throwing. Pass the caster as `exclude` — a ray
|
|
122
|
+
* that starts inside its own collider hits itself at distance 0.
|
|
123
|
+
*/
|
|
124
|
+
get physics() {
|
|
125
|
+
return this.node?.tree?.engine?.physics ?? null;
|
|
126
|
+
}
|
|
71
127
|
getNode(path) {
|
|
72
128
|
return this.node.getNode(path);
|
|
73
129
|
}
|
|
@@ -650,7 +706,7 @@ var Node = class {
|
|
|
650
706
|
} catch (error) {
|
|
651
707
|
this._quarantine("update", error, "node");
|
|
652
708
|
}
|
|
653
|
-
if (this.behavior && !this.behaviorErrored) try {
|
|
709
|
+
if (this.behavior && this.behavior.enabled !== false && !this.behaviorErrored) try {
|
|
654
710
|
this.behavior.update?.(dt);
|
|
655
711
|
} catch (error) {
|
|
656
712
|
this._quarantine("update", error, "behavior");
|
|
@@ -665,7 +721,7 @@ var Node = class {
|
|
|
665
721
|
} catch (error) {
|
|
666
722
|
this._quarantine("fixedUpdate", error, "node");
|
|
667
723
|
}
|
|
668
|
-
if (this.behavior && !this.behaviorErrored) try {
|
|
724
|
+
if (this.behavior && this.behavior.enabled !== false && !this.behaviorErrored) try {
|
|
669
725
|
this.behavior.fixedUpdate?.(dt);
|
|
670
726
|
} catch (error) {
|
|
671
727
|
this._quarantine("fixedUpdate", error, "behavior");
|
package/dist/net.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { d as PropSchema, jt as Node } from "./behavior-
|
|
2
|
-
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-
|
|
1
|
+
import { d as PropSchema, jt as Node } from "./behavior-BXNLfIJk.js";
|
|
2
|
+
import { a as NetworkManagerOptions, c as LocalGameServer, d as ServerClass, f as createLocalGameServer, g as Unsubscribe, h as NetworkTransport, i as NetworkManager, l as LocalGameServerOptions, m as LoopbackTransport, n as SplitScreenPlayer, o as applySyncPatch, p as LoopbackHub, r as createSplitScreen, s as CollectionOptions, t as SplitScreenOptions, u as LocalGameServerTransport } from "./split-screen-eJUFjhi1.js";
|
|
3
3
|
|
|
4
4
|
//#region src/net/agent8.d.ts
|
|
5
5
|
/**
|
package/dist/net.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as createAgent8Server } from "./agent8-CvsfVskX.js";
|
|
2
|
-
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-
|
|
2
|
+
import { a as NetworkManager, d as createLocalGameServer, f as LoopbackHub, l as LocalGameServer, n as registerNodesNet, o as applySyncPatch, p as LoopbackTransport, r as NetworkSpawner, t as createSplitScreen, u as LocalGameServerTransport } from "./split-screen-D_i7GRcY.js";
|
|
3
3
|
export { LocalGameServer, LocalGameServerTransport, LoopbackHub, LoopbackTransport, NetworkManager, NetworkSpawner, applySyncPatch, createAgent8Server, createLocalGameServer, createSplitScreen, registerNodesNet };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { k as diagnose } from "./loader-
|
|
2
|
+
import { k as diagnose } from "./loader-lQDCwNag.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-
|
|
4
|
+
import { _ as RigidBody2D, b as validateCollider2D, g as PhysicsBody2D, h as CharacterBody2D, m as Area2D, p as Joint2D, y as Node2D } from "./register-D0CxCveZ.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
|
-
import { t as withoutRapierInitNoise } from "./quiet-rapier-
|
|
6
|
+
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
7
|
//#region src/2d/physics/physics-2d.ts
|
|
8
8
|
var physics_2d_exports = /* @__PURE__ */ __exportAll({
|
|
9
9
|
Physics2D: () => Physics2D,
|
|
@@ -68,6 +68,7 @@ var Physics2D = class {
|
|
|
68
68
|
this.disconnectScene = engine.sceneChanged.connect(() => {
|
|
69
69
|
if (engine.scene) this.syncBodies();
|
|
70
70
|
});
|
|
71
|
+
engine.physics = this;
|
|
71
72
|
this.syncBodies();
|
|
72
73
|
}
|
|
73
74
|
/** @internal Driven by engine.fixedUpdated. */
|
|
@@ -118,6 +119,8 @@ var Physics2D = class {
|
|
|
118
119
|
const b = this.byColliderHandle.get(h2);
|
|
119
120
|
if (!a || !b) return;
|
|
120
121
|
const sig = started ? "triggerEnter" : "triggerExit";
|
|
122
|
+
this.trackOverlap(a, b, started);
|
|
123
|
+
this.trackOverlap(b, a, started);
|
|
121
124
|
try {
|
|
122
125
|
a.emit(sig, b);
|
|
123
126
|
b.emit(sig, a);
|
|
@@ -283,9 +286,33 @@ var Physics2D = class {
|
|
|
283
286
|
else if (joint.type === "rope") data = R.JointData.rope(length, a1, a2);
|
|
284
287
|
else if (joint.type === "spring") data = R.JointData.spring(length, joint.stiffness, joint.damping, a1, a2);
|
|
285
288
|
else data = R.JointData.revolute(a1, a2);
|
|
286
|
-
|
|
289
|
+
const made = this.world.createImpulseJoint(data, ea.body, eb.body, true);
|
|
290
|
+
made.setContactsEnabled(jointContacts(joint.type, joint.collide));
|
|
291
|
+
this.joints.set(joint, made);
|
|
287
292
|
}
|
|
288
293
|
}
|
|
294
|
+
/** Who is currently inside each sensor/body, maintained from the event drain. */
|
|
295
|
+
overlaps = /* @__PURE__ */ new Map();
|
|
296
|
+
trackOverlap(self, other, started) {
|
|
297
|
+
let set = this.overlaps.get(self);
|
|
298
|
+
if (started) {
|
|
299
|
+
if (!set) {
|
|
300
|
+
set = /* @__PURE__ */ new Set();
|
|
301
|
+
this.overlaps.set(self, set);
|
|
302
|
+
}
|
|
303
|
+
set.add(other);
|
|
304
|
+
} else if (set) {
|
|
305
|
+
set.delete(other);
|
|
306
|
+
if (set.size === 0) this.overlaps.delete(self);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/** The bodies currently overlapping `node`. Freed nodes are dropped on read. */
|
|
310
|
+
overlapping(node) {
|
|
311
|
+
const set = this.overlaps.get(node);
|
|
312
|
+
if (!set) return [];
|
|
313
|
+
for (const other of set) if (other.tree === null) set.delete(other);
|
|
314
|
+
return [...set];
|
|
315
|
+
}
|
|
289
316
|
/**
|
|
290
317
|
* World-space raycast in PIXELS (y-down). `exclude` skips that body — a
|
|
291
318
|
* shooter probing from inside its own collider needs it. Sensors (Area2D)
|
|
@@ -315,6 +342,7 @@ var Physics2D = class {
|
|
|
315
342
|
this.disconnect();
|
|
316
343
|
this.disconnectScene();
|
|
317
344
|
this.unregisterDebug();
|
|
345
|
+
if (this.engine.physics === this) this.engine.physics = null;
|
|
318
346
|
this.world.free();
|
|
319
347
|
}
|
|
320
348
|
lastStructure = -1;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { k as diagnose } from "./loader-
|
|
2
|
+
import { k as diagnose } from "./loader-lQDCwNag.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
|
-
import {
|
|
4
|
+
import { H as CharacterBody3D, K as Node3D, U as PhysicsBody3D, V as Area3D, W as RigidBody3D, q as validateCollider3D } from "./gameplay-D1RADWu3.js";
|
|
5
5
|
import { n as registerDebugSource } from "./debug-draw-BM3DsvtT.js";
|
|
6
|
-
import { t as withoutRapierInitNoise } from "./quiet-rapier-
|
|
7
|
-
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-
|
|
6
|
+
import { n as jointContacts, t as withoutRapierInitNoise } from "./quiet-rapier-C6fW4zcW.js";
|
|
7
|
+
import { A as Terrain3D, F as InstancedMesh3D, L as buildMeshGeometry, P as Joint3D } from "./environment-presets-BlPsEmq6.js";
|
|
8
8
|
import { Euler, Matrix4, Quaternion, Vector3 } from "three";
|
|
9
9
|
//#region src/3d/physics/collider-lines.ts
|
|
10
10
|
/**
|
|
@@ -264,6 +264,7 @@ var Physics3D = class {
|
|
|
264
264
|
this.disconnectScene = engine.sceneChanged.connect(() => {
|
|
265
265
|
if (engine.scene) this.syncBodies();
|
|
266
266
|
});
|
|
267
|
+
engine.physics = this;
|
|
267
268
|
this.syncBodies();
|
|
268
269
|
}
|
|
269
270
|
/** Whether the solver runs at all. False = collider outlines only. */
|
|
@@ -327,6 +328,11 @@ var Physics3D = class {
|
|
|
327
328
|
nv[0] = lv.x;
|
|
328
329
|
nv[1] = lv.y;
|
|
329
330
|
nv[2] = lv.z;
|
|
331
|
+
const av = e.body.angvel();
|
|
332
|
+
const na = node.angularVelocity;
|
|
333
|
+
na[0] = av.x;
|
|
334
|
+
na[1] = av.y;
|
|
335
|
+
na[2] = av.z;
|
|
330
336
|
e.lastV[0] = lv.x;
|
|
331
337
|
e.lastV[1] = lv.y;
|
|
332
338
|
e.lastV[2] = lv.z;
|
|
@@ -341,6 +347,8 @@ var Physics3D = class {
|
|
|
341
347
|
const b = this.byColliderHandle.get(h2);
|
|
342
348
|
if (!a || !b) return;
|
|
343
349
|
const sig = started ? "triggerEnter" : "triggerExit";
|
|
350
|
+
this.trackOverlap(a, b, started);
|
|
351
|
+
this.trackOverlap(b, a, started);
|
|
344
352
|
try {
|
|
345
353
|
a.emit(sig, b);
|
|
346
354
|
b.emit(sig, a);
|
|
@@ -472,6 +480,7 @@ var Physics3D = class {
|
|
|
472
480
|
this.disconnect();
|
|
473
481
|
this.disconnectScene();
|
|
474
482
|
this.unregisterDebug();
|
|
483
|
+
if (this.engine.physics === this) this.engine.physics = null;
|
|
475
484
|
this.world.free();
|
|
476
485
|
}
|
|
477
486
|
lastStructure = -1;
|
|
@@ -633,6 +642,11 @@ var Physics3D = class {
|
|
|
633
642
|
if (node instanceof RigidBody3D) {
|
|
634
643
|
desc.setGravityScale(node.gravityScale);
|
|
635
644
|
desc.setLinvel(node.linearVelocity[0] ?? 0, node.linearVelocity[1] ?? 0, node.linearVelocity[2] ?? 0);
|
|
645
|
+
desc.setAngvel({
|
|
646
|
+
x: node.angularVelocity[0] ?? 0,
|
|
647
|
+
y: node.angularVelocity[1] ?? 0,
|
|
648
|
+
z: node.angularVelocity[2] ?? 0
|
|
649
|
+
});
|
|
636
650
|
if (node.fixedRotation) desc.lockRotations();
|
|
637
651
|
}
|
|
638
652
|
const body = this.world.createRigidBody(desc);
|
|
@@ -789,10 +803,40 @@ var Physics3D = class {
|
|
|
789
803
|
else if (joint.type === "rope") data = R.JointData.rope(length, a1, a2);
|
|
790
804
|
else if (joint.type === "spring") data = R.JointData.spring(length, joint.stiffness, joint.damping, a1, a2);
|
|
791
805
|
else data = R.JointData.spherical(a1, a2);
|
|
792
|
-
|
|
806
|
+
const made = this.world.createImpulseJoint(data, ea.body, eb.body, true);
|
|
807
|
+
made.setContactsEnabled(jointContacts(joint.type, joint.collide));
|
|
808
|
+
this.joints.set(joint, made);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
/** Who is currently inside each sensor/body, maintained from the event drain. */
|
|
812
|
+
overlaps = /* @__PURE__ */ new Map();
|
|
813
|
+
trackOverlap(self, other, started) {
|
|
814
|
+
let set = this.overlaps.get(self);
|
|
815
|
+
if (started) {
|
|
816
|
+
if (!set) {
|
|
817
|
+
set = /* @__PURE__ */ new Set();
|
|
818
|
+
this.overlaps.set(self, set);
|
|
819
|
+
}
|
|
820
|
+
set.add(other);
|
|
821
|
+
} else if (set) {
|
|
822
|
+
set.delete(other);
|
|
823
|
+
if (set.size === 0) this.overlaps.delete(self);
|
|
793
824
|
}
|
|
794
825
|
}
|
|
795
826
|
/**
|
|
827
|
+
* The bodies currently overlapping `node` — the standing answer behind
|
|
828
|
+
* `triggerEnter`/`triggerExit`.
|
|
829
|
+
*
|
|
830
|
+
* Freed nodes are dropped on read rather than tracked, so a hazard that
|
|
831
|
+
* despawns inside a plate cannot leave a ghost holding a door open.
|
|
832
|
+
*/
|
|
833
|
+
overlapping(node) {
|
|
834
|
+
const set = this.overlaps.get(node);
|
|
835
|
+
if (!set) return [];
|
|
836
|
+
for (const other of set) if (other.tree === null) set.delete(other);
|
|
837
|
+
return [...set];
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
796
840
|
* World-space raycast (meters). `exclude` skips that body's collider —
|
|
797
841
|
* ground probes from inside a capsule need it. `opts.staticOnly` hits ONLY the
|
|
798
842
|
* fixed/static world (excludes both dynamic AND kinematic bodies): the camera
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
//#region src/core/joint-contacts.ts
|
|
2
|
+
/**
|
|
3
|
+
* Should these two jointed bodies collide with each other?
|
|
4
|
+
*
|
|
5
|
+
* `null` means "decide from the type": a PIVOT wants its bodies overlapping and
|
|
6
|
+
* must not let the contact solver fight the joint; a TETHER anchors something to
|
|
7
|
+
* the world and that something still has to rest on it.
|
|
8
|
+
*/
|
|
9
|
+
function jointContacts(type, collide) {
|
|
10
|
+
if (collide !== null) return collide;
|
|
11
|
+
return type === "rope" || type === "spring";
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
1
14
|
//#region src/core/quiet-rapier.ts
|
|
2
15
|
/**
|
|
3
16
|
* Swallow one wrong warning that rapier prints about itself.
|
|
@@ -43,4 +56,4 @@ async function withoutRapierInitNoise(boot, out = console) {
|
|
|
43
56
|
}
|
|
44
57
|
}
|
|
45
58
|
//#endregion
|
|
46
|
-
export { withoutRapierInitNoise as t };
|
|
59
|
+
export { jointContacts as n, withoutRapierInitNoise as t };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-
|
|
1
|
+
import { P as Scene, b as Engine, n as BehaviorCtor } from "./behavior-BXNLfIJk.js";
|
|
2
2
|
import { c as JsonValue } from "./schema-CFeioQRE.js";
|
|
3
3
|
import { CSSProperties, ReactNode } from "react";
|
|
4
4
|
|
package/dist/react.js
CHANGED
|
@@ -156,7 +156,7 @@ function IncantoCanvas(props) {
|
|
|
156
156
|
pointer: latest.pointer,
|
|
157
157
|
...keyboard !== void 0 ? { keyboard } : {}
|
|
158
158
|
};
|
|
159
|
-
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-
|
|
159
|
+
const next = await (_gameFactory ?? (mode === "3d" ? async (o) => (await import("./create-game-DYJCIzO0.js").then((n) => n.n)).createGame3D(o) : async (o) => (await import("./create-game-Dd7H4bJV.js").then((n) => n.n)).createGame2D(o)))(opts);
|
|
160
160
|
if (disposed) {
|
|
161
161
|
next.dispose();
|
|
162
162
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import { C as ORDER_GROUP_BASE, E as InputMap, O as Node, S as createSaveStore, T as resolveOrderGroups, V as Signal, b as restoreBehaviors, k as diagnose, y as captureBehaviors } from "./loader-
|
|
2
|
+
import { C as ORDER_GROUP_BASE, E as InputMap, O as Node, S as createSaveStore, T as resolveOrderGroups, V as Signal, b as restoreBehaviors, k as diagnose, y as captureBehaviors } from "./loader-lQDCwNag.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
5
|
import { l as registerNode } from "./registry-CF70EArN.js";
|
|
@@ -2365,6 +2365,20 @@ var Engine = class {
|
|
|
2365
2365
|
sceneChanged = new Signal();
|
|
2366
2366
|
/** Declarative input — scene `input{}` declarations load on setScene. */
|
|
2367
2367
|
input = new InputMap();
|
|
2368
|
+
/**
|
|
2369
|
+
* The physics world, once something enabled it — `null` in a game that has
|
|
2370
|
+
* none, which is most 2D puzzle games and every menu scene.
|
|
2371
|
+
*
|
|
2372
|
+
* `enablePhysics2D/3D` set this, and `dispose()` clears it. It is the handle
|
|
2373
|
+
* `incanto-physics-and-input.md` has always assumed you had: the skill teaches
|
|
2374
|
+
* `physics.castRay(...)` but the object lived only where the game BOOTED, so
|
|
2375
|
+
* a `Behavior` — where AI lives, and where line of sight is decided — had no
|
|
2376
|
+
* way to reach it short of casting the private `node._physics`.
|
|
2377
|
+
*
|
|
2378
|
+
* Typed as the query surface rather than the concrete class so core never
|
|
2379
|
+
* learns about Rapier or three. From a behavior, prefer `this.physics`.
|
|
2380
|
+
*/
|
|
2381
|
+
physics = null;
|
|
2368
2382
|
/** Seeded randomness for game logic (deterministic when `seed` is set). */
|
|
2369
2383
|
rng;
|
|
2370
2384
|
/** The engine log channel (debug overlay + headless harness tail this). */
|
|
@@ -2379,6 +2393,33 @@ var Engine = class {
|
|
|
2379
2393
|
* and cleared on dispose; null when nothing renders (headless).
|
|
2380
2394
|
*/
|
|
2381
2395
|
picker = null;
|
|
2396
|
+
/** Frames the engine has stepped — monotonic, and the pick cache's key. */
|
|
2397
|
+
frameNumber = 0;
|
|
2398
|
+
/** @internal frame number + answer, so N Clickables cost ONE raycast. */
|
|
2399
|
+
pickCacheFrame = -1;
|
|
2400
|
+
pickCacheKey = "";
|
|
2401
|
+
pickCacheHit = null;
|
|
2402
|
+
/**
|
|
2403
|
+
* The node under (x, y), answered at most ONCE per frame per cursor position.
|
|
2404
|
+
*
|
|
2405
|
+
* `Clickable` asks every frame, and a board game has one per cell: 42 pads
|
|
2406
|
+
* measured **420 picker calls over ten frames** — one GPU raycast per pad per
|
|
2407
|
+
* frame, all answering the same question about the same pixel. At 60 fps that
|
|
2408
|
+
* is ~2500 raycasts a second to find out what the cursor is on, and a 200-tile
|
|
2409
|
+
* board was unusable.
|
|
2410
|
+
*
|
|
2411
|
+
* Cached on (frame, x, y), so a game that picks at two different points in one
|
|
2412
|
+
* frame still gets two real answers.
|
|
2413
|
+
*/
|
|
2414
|
+
pickAt(x, y) {
|
|
2415
|
+
if (!this.picker) return null;
|
|
2416
|
+
const key = `${x},${y}`;
|
|
2417
|
+
if (this.pickCacheFrame === this.frameNumber && this.pickCacheKey === key) return this.pickCacheHit;
|
|
2418
|
+
this.pickCacheFrame = this.frameNumber;
|
|
2419
|
+
this.pickCacheKey = key;
|
|
2420
|
+
this.pickCacheHit = this.picker(x, y);
|
|
2421
|
+
return this.pickCacheHit;
|
|
2422
|
+
}
|
|
2382
2423
|
/** Global volume buses — `master` × `sfx`/`music` gain + `muted`. AudioPlayer
|
|
2383
2424
|
* routes its volume through this; games set it for global volume/mute. */
|
|
2384
2425
|
audio = new AudioBuses();
|
|
@@ -2714,6 +2755,7 @@ var Engine = class {
|
|
|
2714
2755
|
scene.tree.fixedUpdate(dt);
|
|
2715
2756
|
this.fixedUpdated.emit(dt);
|
|
2716
2757
|
const startedUpdate = performance.now();
|
|
2758
|
+
this.frameNumber += 1;
|
|
2717
2759
|
scene.tree.update(dt);
|
|
2718
2760
|
this.music.tick(dt);
|
|
2719
2761
|
this.updated.emit(dt);
|
|
@@ -2748,6 +2790,7 @@ var Engine = class {
|
|
|
2748
2790
|
}
|
|
2749
2791
|
if (this.accumulator >= this.fixedStep) this.accumulator %= this.fixedStep;
|
|
2750
2792
|
const startedUpdate = performance.now();
|
|
2793
|
+
this.frameNumber += 1;
|
|
2751
2794
|
scene.tree.update(dt);
|
|
2752
2795
|
this.music.tick(dt);
|
|
2753
2796
|
this.updated.emit(dt);
|