incanto 0.55.0 → 0.57.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/bin/incanto-verify.mjs +9 -2
- package/dist/2d.d.ts +59 -7
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +34 -4
- package/dist/3d.js +5 -5
- package/dist/{behavior-CyQoSu4n.d.ts → behavior-l08AEbq9.d.ts} +5 -0
- package/dist/{create-game-CzK9_pzg.js → create-game-C5jQYPah.js} +28 -71
- package/dist/{create-game-BRt6XKmP.js → create-game-DpbUrMOQ.js} +146 -7
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-MNLMAcbz.js → duplicate-BPLZDZpd.js} +1 -1
- package/dist/{environment-presets-DAbEdEwh.js → environment-presets-CvvQr_bJ.js} +118 -24
- package/dist/{frame-report-njybhZon.js → frame-report-BSMny7oe.js} +1 -1
- package/dist/{frame-report-DZ70IY26.d.ts → frame-report-DCnHFmto.d.ts} +1 -1
- package/dist/{gameplay-CZ2yq37J.js → gameplay-BVphcxmE.js} +163 -14
- package/dist/gameplay.d.ts +81 -2
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +45 -5
- package/dist/index.js +8 -9
- package/dist/{loader-DhI1jFW_.d.ts → loader-BbEMTuWg.d.ts} +1 -1
- package/dist/{loader-BTkHYrQn.js → loader-BcrRSjxB.js} +682 -682
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/{pathfinding-CXGCpRQe.d.ts → pathfinding-mEN4V1CU.d.ts} +1 -1
- package/dist/{physics-2d-CfWAggJ1.js → physics-2d-BLcvEFDR.js} +2 -2
- package/dist/{physics-3d-C_ZJ6f_d.js → physics-3d-QBrfIT2Y.js} +3 -3
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-en63AEZO.js → register-C6ZBFRjd.js} +63 -60
- package/dist/{register-p48lHE2o.js → register-Ch70uByv.js} +1615 -1502
- package/dist/{replay-ePMz26jw.d.ts → replay-Dw6gMlYA.d.ts} +1 -1
- package/dist/{replay-t1pP0gQg.js → replay-s7I2GstT.js} +31 -11
- package/dist/sheet-grid-BT6N_Bjs.js +59 -0
- package/dist/{split-screen-BsdOHbzP.d.ts → split-screen-B0baBwxI.d.ts} +5 -1
- package/dist/{split-screen-CSb_uZ6W.js → split-screen-DLsUrleX.js} +14 -3
- package/dist/{sprite-animation-7qvUxF6Z.js → sprite-animation-C0wXLBZJ.js} +8 -4
- package/dist/{src-BVOVHRL0.js → src-CGjmPw65.js} +55 -2
- package/dist/{teardown-C7uVSJvx.js → teardown-Cs113S9F.js} +74 -2
- package/dist/{test-Ca5eqELC.js → test-it1VekWs.js} +28 -19
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/{touch-BnMyy9tr.js → touch-DESwnpOc.js} +173 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +3 -3
- package/editor/assets/{agent8-Cz4oHPtm.js → agent8-CGT7r3Mb.js} +1 -1
- package/editor/assets/{debug-r-Fi9nZh.js → debug-BxWSIHG3.js} +1 -1
- package/editor/assets/{index-BfqmvXYD.js → index-CV1m-aX5.js} +62 -62
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/skills/incanto-assets.md +5 -1
- package/skills/incanto-audio.md +7 -1
- package/skills/incanto-building-3d-games.md +18 -5
- package/skills/incanto-gameplay-behaviors.md +21 -1
- package/skills/incanto-hud.md +6 -0
- package/skills/incanto-performance.md +5 -0
- package/skills/incanto-physics-and-input.md +14 -0
- package/skills/incanto-save-slots.md +2 -1
- package/skills/incanto-verifying-your-game.md +4 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/package.json +1 -1
- package/dist/log-report-CPFm4OXf.js +0 -173
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as diagnose } from "./loader-BcrRSjxB.js";
|
|
2
|
+
import { t as registerCoreNodes } from "./register-Ch70uByv.js";
|
|
2
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
5
|
import { i as getNodeSchema, l as registerNode } from "./registry-C7u42TID.js";
|
|
5
6
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
6
|
-
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-
|
|
7
|
-
import { F as
|
|
7
|
+
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimationAliases, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-C0wXLBZJ.js";
|
|
8
|
+
import { B as StaticBody3D, F as WaterCutout3D, G as colliderFootDrop, I as Area3D, L as CharacterBody3D, N as Water3D, R as PhysicsBody3D, V as Node3D, w as tolerateUnknownAction, z as RigidBody3D } from "./gameplay-BVphcxmE.js";
|
|
9
|
+
import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
|
|
8
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
9
11
|
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
10
12
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
@@ -2175,8 +2177,41 @@ var AnimatedSprite3D = class extends Sprite3D {
|
|
|
2175
2177
|
}
|
|
2176
2178
|
this.currentFrame = this.frameList[this.frameIndex] ?? 0;
|
|
2177
2179
|
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Does the grid fit the image, and does any animation run off the end?
|
|
2182
|
+
*
|
|
2183
|
+
* The same floor-division as the 2D twin, and for a long time the same
|
|
2184
|
+
* division with none of its checking — the checker sat one directory away in
|
|
2185
|
+
* 2d/ where this node could not see it.
|
|
2186
|
+
*/
|
|
2187
|
+
checkGrid(width, height) {
|
|
2188
|
+
if (this.gridChecked === this.sheet) return;
|
|
2189
|
+
this.gridChecked = this.sheet;
|
|
2190
|
+
let highest = 0;
|
|
2191
|
+
for (const [name, entry] of Object.entries(this.animations)) {
|
|
2192
|
+
if (typeof entry === "string") continue;
|
|
2193
|
+
try {
|
|
2194
|
+
for (const frame of resolveFrames(entry.frames, name)) if (frame > highest) highest = frame;
|
|
2195
|
+
} catch {
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
const problem = checkSheetGrid(this.sheet, this.frameWidth, this.frameHeight, width, height, highest);
|
|
2200
|
+
if (problem) diagnose(this.tree?.engine ?? null, "error", problem);
|
|
2201
|
+
}
|
|
2202
|
+
/** Reported once per sheet, so a bad grid says so on the first draw only. */
|
|
2203
|
+
gridChecked = "";
|
|
2204
|
+
/** Reported once, so a sheet with no frame size does not shout every frame. */
|
|
2205
|
+
sizeReported = false;
|
|
2178
2206
|
resolveTexture(assets) {
|
|
2179
|
-
if (!this.sheet
|
|
2207
|
+
if (!this.sheet) return null;
|
|
2208
|
+
if (this.frameWidth <= 0 || this.frameHeight <= 0) {
|
|
2209
|
+
if (!this.sizeReported) {
|
|
2210
|
+
this.sizeReported = true;
|
|
2211
|
+
diagnose(this.tree?.engine ?? null, "error", `[incanto] AnimatedSprite3D '${this.name}' has a sheet ('${this.sheet}') but frameWidth/frameHeight are 0 — it draws nothing. Set both to one frame's pixel size (bunx incanto-assets info <name> prints it for a built-in).`);
|
|
2212
|
+
}
|
|
2213
|
+
return null;
|
|
2214
|
+
}
|
|
2180
2215
|
if (this.loadedSheetRef !== this.sheet) {
|
|
2181
2216
|
this.sheetTexture?.dispose();
|
|
2182
2217
|
this.loadedSheetRef = this.sheet;
|
|
@@ -2186,6 +2221,7 @@ var AnimatedSprite3D = class extends Sprite3D {
|
|
|
2186
2221
|
if (!tex) return null;
|
|
2187
2222
|
const image = tex.image;
|
|
2188
2223
|
if (!image?.width || !image.height) return tex;
|
|
2224
|
+
this.checkGrid(image.width, image.height);
|
|
2189
2225
|
const cols = Math.max(1, Math.floor(image.width / this.frameWidth));
|
|
2190
2226
|
const col = this.currentFrame % cols;
|
|
2191
2227
|
const row = Math.floor(this.currentFrame / cols);
|
|
@@ -2319,10 +2355,14 @@ var BoneAttachment3D = class extends Node3D {
|
|
|
2319
2355
|
this.lookedUpFor = key;
|
|
2320
2356
|
this.boneObj = null;
|
|
2321
2357
|
const source = this.getNodeOrNull(this.target);
|
|
2358
|
+
this.source = source;
|
|
2322
2359
|
if (source && typeof source.findBone === "function") this.boneObj = source.findBone(this.bone);
|
|
2323
2360
|
}
|
|
2324
2361
|
const boneObj = this.boneObj;
|
|
2325
|
-
if (!boneObj)
|
|
2362
|
+
if (!boneObj) {
|
|
2363
|
+
this.reportMissingBone();
|
|
2364
|
+
return;
|
|
2365
|
+
}
|
|
2326
2366
|
const obj = this._ensureObject3D();
|
|
2327
2367
|
const parent = obj.parent;
|
|
2328
2368
|
if (!parent) return;
|
|
@@ -2339,6 +2379,28 @@ var BoneAttachment3D = class extends Node3D {
|
|
|
2339
2379
|
this.boneObj = null;
|
|
2340
2380
|
super.free();
|
|
2341
2381
|
}
|
|
2382
|
+
/** The model this attachment last looked in. */
|
|
2383
|
+
source = null;
|
|
2384
|
+
reportedBone = "";
|
|
2385
|
+
/**
|
|
2386
|
+
* Say when the bone NAME is wrong, without accusing a model that is still
|
|
2387
|
+
* loading.
|
|
2388
|
+
*
|
|
2389
|
+
* The lookup retries every frame on purpose — a GLB mounts async — so the
|
|
2390
|
+
* node can never conclude on its own that the name is bad. But once the model
|
|
2391
|
+
* HAS bones and this one is not among them, it is a typo, and the list that
|
|
2392
|
+
* would fix it is sitting in `boneNames()` right next to `findBone`. Until
|
|
2393
|
+
* now a misspelled bone left the sword at the mount node's authored position
|
|
2394
|
+
* while the character animated away from it, forever, in silence.
|
|
2395
|
+
*/
|
|
2396
|
+
reportMissingBone() {
|
|
2397
|
+
if (this.reportedBone === this.bone) return;
|
|
2398
|
+
const names = this.source?.boneNames?.() ?? [];
|
|
2399
|
+
if (names.length === 0) return;
|
|
2400
|
+
this.reportedBone = this.bone;
|
|
2401
|
+
const shown = names.slice(0, 8).join(", ");
|
|
2402
|
+
diagnose(this.tree?.engine ?? null, "error", `[incanto] ${this.getPath()}: '${this.target}' has no bone '${this.bone}'. It has ${names.length}: [${shown}${names.length > 8 ? ", …" : ""}].`);
|
|
2403
|
+
}
|
|
2342
2404
|
};
|
|
2343
2405
|
const offsetScratch = new Matrix4();
|
|
2344
2406
|
const boneScratch = new Matrix4();
|
|
@@ -2506,6 +2568,11 @@ const DRAG_DAMPING = .15;
|
|
|
2506
2568
|
const SPRING_K = 1.2;
|
|
2507
2569
|
const SPRING_DAMPING = .08;
|
|
2508
2570
|
const FALLING_MAX_VEL = -20;
|
|
2571
|
+
/** The schema's own default for an action prop — never a second copy of it. */
|
|
2572
|
+
function defaultActionOf(prop) {
|
|
2573
|
+
const schema = CharacterController3D.props[prop];
|
|
2574
|
+
return typeof schema?.default === "string" ? schema.default : "";
|
|
2575
|
+
}
|
|
2509
2576
|
const LOOK_SPEED = .002;
|
|
2510
2577
|
const RAD2DEG = 180 / Math.PI;
|
|
2511
2578
|
/** Spring-arm camera collision: keep the camera this far in front of an obstacle. */
|
|
@@ -2706,8 +2773,10 @@ var CharacterController3D = class extends Node3D {
|
|
|
2706
2773
|
const len = Math.hypot(dir[0], dir[2]) || 1;
|
|
2707
2774
|
mx = dir[0] / len;
|
|
2708
2775
|
mz = dir[2] / len;
|
|
2709
|
-
} catch {
|
|
2710
|
-
|
|
2776
|
+
} catch (error) {
|
|
2777
|
+
this.reportMissingAction("moveAction", error, "The character will not move.");
|
|
2778
|
+
}
|
|
2779
|
+
const sprinting = this.readAction("sprintAction", () => input.isPressed(this.sprintAction), false, "Sprint will never engage.");
|
|
2711
2780
|
const intensity = keyboardIntensity(moving, sprinting);
|
|
2712
2781
|
const speedMultiplier = 1 + (this.sprintMultiplier - 1) * intensity;
|
|
2713
2782
|
const targetSpeed = moving ? this.maxSpeed * speedMultiplier : 0;
|
|
@@ -2741,7 +2810,7 @@ var CharacterController3D = class extends Node3D {
|
|
|
2741
2810
|
this.coyoteLeft = Math.max(0, this.coyoteLeft - dt);
|
|
2742
2811
|
if (!this.grounded && this.coyoteLeft <= 0 && this.jumpsUsed === 0) this.jumpsUsed = 1;
|
|
2743
2812
|
}
|
|
2744
|
-
const pressedJump =
|
|
2813
|
+
const pressedJump = this.readAction("jumpAction", () => input.justPressed(this.jumpAction), false, "The character will never jump.");
|
|
2745
2814
|
if (pressedJump) this.bufferLeft = Math.max(this.jumpBufferSeconds, 0);
|
|
2746
2815
|
else this.bufferLeft = Math.max(0, this.bufferLeft - dt);
|
|
2747
2816
|
if ((this.bufferLeft > 0 || pressedJump) && (footed || this.coyoteLeft > 0 || this.jumpsUsed < this.maxJumps)) {
|
|
@@ -2761,7 +2830,7 @@ var CharacterController3D = class extends Node3D {
|
|
|
2761
2830
|
}
|
|
2762
2831
|
if (this.rising) {
|
|
2763
2832
|
if ((vel[1] ?? 0) <= 0) this.rising = false;
|
|
2764
|
-
else if (this.jumpCutMultiplier < 1 && !
|
|
2833
|
+
else if (this.jumpCutMultiplier < 1 && !this.readAction("jumpAction", () => input.isPressed(this.jumpAction), false, "The character will never jump.")) {
|
|
2765
2834
|
const cut = (vel[1] ?? 0) * this.jumpCutMultiplier;
|
|
2766
2835
|
body.linearVelocity = [
|
|
2767
2836
|
vel[0],
|
|
@@ -2806,6 +2875,31 @@ var CharacterController3D = class extends Node3D {
|
|
|
2806
2875
|
}
|
|
2807
2876
|
}
|
|
2808
2877
|
}
|
|
2878
|
+
/** Actions already reported missing, so a per-frame read says it once. */
|
|
2879
|
+
reportedActions = /* @__PURE__ */ new Set();
|
|
2880
|
+
/**
|
|
2881
|
+
* Read an input action this controller is allowed to be missing.
|
|
2882
|
+
*
|
|
2883
|
+
* Tolerated because a game may declare no sprint key and no jump; reported
|
|
2884
|
+
* because otherwise a TYPO looks exactly like a deliberate omission, and the
|
|
2885
|
+
* engine has already thrown the sentence that fixes it.
|
|
2886
|
+
*/
|
|
2887
|
+
readAction(prop, read, fallback, consequence) {
|
|
2888
|
+
const action = this[prop];
|
|
2889
|
+
return tolerateUnknownAction({
|
|
2890
|
+
engine: this.tree?.engine,
|
|
2891
|
+
who: this.getPath(),
|
|
2892
|
+
reported: this.reportedActions,
|
|
2893
|
+
consequence,
|
|
2894
|
+
authored: action !== defaultActionOf(prop)
|
|
2895
|
+
}, action, read, fallback);
|
|
2896
|
+
}
|
|
2897
|
+
/** Report a throw the caller already caught (the move read has its own try). */
|
|
2898
|
+
reportMissingAction(prop, error, consequence) {
|
|
2899
|
+
this.readAction(prop, () => {
|
|
2900
|
+
throw error;
|
|
2901
|
+
}, void 0, consequence);
|
|
2902
|
+
}
|
|
2809
2903
|
update(dt) {
|
|
2810
2904
|
const input = this.tree?.engine?.input;
|
|
2811
2905
|
if (!input) return;
|
|
@@ -2921,28 +3015,14 @@ function worldOf(node) {
|
|
|
2921
3015
|
z
|
|
2922
3016
|
];
|
|
2923
3017
|
}
|
|
2924
|
-
function safePressed(input, action) {
|
|
2925
|
-
try {
|
|
2926
|
-
return input.isPressed(action);
|
|
2927
|
-
} catch {
|
|
2928
|
-
return false;
|
|
2929
|
-
}
|
|
2930
|
-
}
|
|
2931
3018
|
/**
|
|
2932
3019
|
* The EDGE, not the level.
|
|
2933
3020
|
*
|
|
2934
3021
|
* Jump used to read `isPressed`, so holding the button re-jumped on every frame
|
|
2935
3022
|
* the raycast found ground — an auto-hop nobody asked for, and one that makes
|
|
2936
3023
|
* coyote time incoherent (a held button would re-fire through the whole
|
|
2937
|
-
* window).
|
|
3024
|
+
* window). Undeclared actions are tolerated, and reported once.
|
|
2938
3025
|
*/
|
|
2939
|
-
function safeJustPressed(input, action) {
|
|
2940
|
-
try {
|
|
2941
|
-
return input.justPressed(action);
|
|
2942
|
-
} catch {
|
|
2943
|
-
return false;
|
|
2944
|
-
}
|
|
2945
|
-
}
|
|
2946
3026
|
//#endregion
|
|
2947
3027
|
//#region src/3d/vegetation/grass-placement.ts
|
|
2948
3028
|
const NOISE_SCALE = .15;
|
|
@@ -3668,6 +3748,7 @@ var Flowers3D = class extends Node3D {
|
|
|
3668
3748
|
this.height,
|
|
3669
3749
|
this.clustering,
|
|
3670
3750
|
this.drape,
|
|
3751
|
+
this.avoidWater,
|
|
3671
3752
|
this.terrain
|
|
3672
3753
|
]);
|
|
3673
3754
|
if (key === this.fieldKey) return;
|
|
@@ -5222,6 +5303,7 @@ var Foliage3D = class Foliage3D extends Node3D {
|
|
|
5222
5303
|
this.colorA,
|
|
5223
5304
|
this.colorB,
|
|
5224
5305
|
this.coverage,
|
|
5306
|
+
this.avoidWater,
|
|
5225
5307
|
this.flowers,
|
|
5226
5308
|
this.seed,
|
|
5227
5309
|
this.drape,
|
|
@@ -5737,6 +5819,18 @@ var Label3D = class extends Sprite3D {
|
|
|
5737
5819
|
font = "sans-serif";
|
|
5738
5820
|
outline = "#000000";
|
|
5739
5821
|
billboard = "full";
|
|
5822
|
+
/**
|
|
5823
|
+
* A `texture` on a label is a mistake, and a loud one.
|
|
5824
|
+
*
|
|
5825
|
+
* The prop is inherited from `Sprite3D` and cannot be un-inherited (schemas
|
|
5826
|
+
* merge up the chain), so a URL set here would be silently ignored — this
|
|
5827
|
+
* node draws its own text. Silent is the failure mode these rounds keep
|
|
5828
|
+
* finding; naming it costs one check at load.
|
|
5829
|
+
*/
|
|
5830
|
+
static validateJson(node) {
|
|
5831
|
+
const label = node;
|
|
5832
|
+
if (label.texture) throw new IncantoError("BAD_FORMAT", `Label3D '${label.name}' has a "texture" — a label draws its own text, so the image would never be used. Set "text" instead, or use a Sprite3D.`, { prop: "texture" });
|
|
5833
|
+
}
|
|
5740
5834
|
canvas = null;
|
|
5741
5835
|
/** The rasterised text. Named apart from Sprite3D's `texture` URL prop, which
|
|
5742
5836
|
* this node ignores — the text IS the picture. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as registerBehavior,
|
|
1
|
+
import { A as registerBehavior, C as diagnose, S as Node, T as Behavior, f as SaveSlots, n as loadScene, y as effectiveOrder } from "./loader-BcrRSjxB.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
4
|
-
import { t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { t as duplicateNode } from "./duplicate-BPLZDZpd.js";
|
|
5
5
|
import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
6
6
|
//#region src/3d/frustum.ts
|
|
7
7
|
const scratchFrustum = new Frustum();
|
|
@@ -4172,12 +4172,20 @@ var Buoyancy = class extends Behavior {
|
|
|
4172
4172
|
size = [1, 1];
|
|
4173
4173
|
surface = null;
|
|
4174
4174
|
wet = false;
|
|
4175
|
+
/** Said once: a body that cannot be pushed will never start being able to. */
|
|
4176
|
+
reportedNoImpulse = false;
|
|
4175
4177
|
update(dt) {
|
|
4176
4178
|
if (dt <= 0) return;
|
|
4177
4179
|
const water = this.resolveWater();
|
|
4178
4180
|
if (!water) return;
|
|
4179
4181
|
const node = this.node;
|
|
4180
|
-
if (!node.applyImpulse)
|
|
4182
|
+
if (!node.applyImpulse) {
|
|
4183
|
+
if (!this.reportedNoImpulse) {
|
|
4184
|
+
this.reportedNoImpulse = true;
|
|
4185
|
+
diagnose(this.node.tree?.engine ?? null, "error", `[incanto] ${this.node.getPath()}: Buoyancy needs a body it can push — this node has no applyImpulse, so it will never float. Put it on a RigidBody3D.`);
|
|
4186
|
+
}
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4181
4189
|
const [x, y, z] = [
|
|
4182
4190
|
node.position[0] ?? 0,
|
|
4183
4191
|
node.position[1] ?? 0,
|
|
@@ -4891,6 +4899,78 @@ function phaseOf(hour) {
|
|
|
4891
4899
|
return "dusk";
|
|
4892
4900
|
}
|
|
4893
4901
|
//#endregion
|
|
4902
|
+
//#region src/gameplay/float-away.ts
|
|
4903
|
+
/**
|
|
4904
|
+
* Rise, fade, and be gone — the second half of a damage number.
|
|
4905
|
+
*
|
|
4906
|
+
* `Label3D` gave a game text standing in the world; every game then writes the
|
|
4907
|
+
* same eight lines to move it up and fade it out, and the interesting part is
|
|
4908
|
+
* not the eight lines, it is the three things they all get wrong: the node is
|
|
4909
|
+
* freed on the frame it becomes invisible rather than a second later, the fade
|
|
4910
|
+
* fights whatever else writes `opacity`, and a hundred numbers a fight each
|
|
4911
|
+
* leave a node behind because nothing ever frees them.
|
|
4912
|
+
*
|
|
4913
|
+
* ```json
|
|
4914
|
+
* { "name": "Hit", "type": "Label3D",
|
|
4915
|
+
* "props": { "text": "12", "height": 0.35, "color": "#ff5a5a" },
|
|
4916
|
+
* "script": { "name": "FloatAway", "props": { "rise": 1.2, "seconds": 0.7 } } }
|
|
4917
|
+
* ```
|
|
4918
|
+
*
|
|
4919
|
+
* Spawning one is then `duplicateNode` + set `text` + `position` — no per-frame
|
|
4920
|
+
* code of your own, and no cleanup to forget.
|
|
4921
|
+
*
|
|
4922
|
+
* It writes `opacity` and the node's own `position`, so it composes with
|
|
4923
|
+
* anything that does not. Works on any node with those props: a `Label3D`, a
|
|
4924
|
+
* `Sprite3D` pickup puff, a 2D `Label`.
|
|
4925
|
+
*/
|
|
4926
|
+
var FloatAway = class extends Behavior {
|
|
4927
|
+
static props = {
|
|
4928
|
+
/** World units travelled over the whole life (negative sinks). */
|
|
4929
|
+
rise: { default: 1 },
|
|
4930
|
+
/** How long the whole thing takes. */
|
|
4931
|
+
seconds: { default: .7 },
|
|
4932
|
+
/** Fraction of the life spent at full opacity before the fade starts. */
|
|
4933
|
+
hold: { default: .3 },
|
|
4934
|
+
/** Sideways drift, so ten numbers at once do not stack into one. */
|
|
4935
|
+
drift: { default: 0 },
|
|
4936
|
+
/** Free the node when it finishes. Off for something you re-use. */
|
|
4937
|
+
freeOnEnd: { default: true }
|
|
4938
|
+
};
|
|
4939
|
+
rise = 1;
|
|
4940
|
+
seconds = .7;
|
|
4941
|
+
hold = .3;
|
|
4942
|
+
drift = 0;
|
|
4943
|
+
freeOnEnd = true;
|
|
4944
|
+
elapsed = 0;
|
|
4945
|
+
start = [];
|
|
4946
|
+
done = false;
|
|
4947
|
+
onReady() {
|
|
4948
|
+
const node = this.node;
|
|
4949
|
+
this.start = [...node.position ?? []];
|
|
4950
|
+
}
|
|
4951
|
+
update(dt) {
|
|
4952
|
+
if (this.done) return;
|
|
4953
|
+
const node = this.node;
|
|
4954
|
+
if (!node.position) return;
|
|
4955
|
+
this.elapsed += dt;
|
|
4956
|
+
const life = Math.max(.001, this.seconds);
|
|
4957
|
+
const t = Math.min(1, this.elapsed / life);
|
|
4958
|
+
const next = [...this.start];
|
|
4959
|
+
const eased = 1 - (1 - t) * (1 - t);
|
|
4960
|
+
next[1] = (this.start[1] ?? 0) + this.rise * eased;
|
|
4961
|
+
if (this.drift !== 0) next[0] = (this.start[0] ?? 0) + this.drift * eased;
|
|
4962
|
+
node.position = next;
|
|
4963
|
+
if (node.opacity !== void 0) {
|
|
4964
|
+
const holdFor = Math.min(.99, Math.max(0, this.hold));
|
|
4965
|
+
node.opacity = t <= holdFor ? 1 : 1 - (t - holdFor) / (1 - holdFor);
|
|
4966
|
+
}
|
|
4967
|
+
if (t >= 1) {
|
|
4968
|
+
this.done = true;
|
|
4969
|
+
if (this.freeOnEnd) this.node.queueFree();
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
};
|
|
4973
|
+
//#endregion
|
|
4894
4974
|
//#region src/gameplay/follow-camera.ts
|
|
4895
4975
|
/**
|
|
4896
4976
|
* Make the node it sits on chase a target's position — THE camera-follow
|
|
@@ -4964,6 +5044,35 @@ var FollowCamera = class extends Behavior {
|
|
|
4964
5044
|
}
|
|
4965
5045
|
};
|
|
4966
5046
|
//#endregion
|
|
5047
|
+
//#region src/core/optional-action.ts
|
|
5048
|
+
/**
|
|
5049
|
+
* Read an input action that a game is ALLOWED not to declare — and say so once
|
|
5050
|
+
* when it is missing.
|
|
5051
|
+
*
|
|
5052
|
+
* `CharacterController3D` and `GameFlow` wrap every input read in a bare
|
|
5053
|
+
* `catch {}`. The tolerance is right: a game with no sprint key should not
|
|
5054
|
+
* crash, and `pause()` stays an API even with no pause action. What was wrong is
|
|
5055
|
+
* that the tolerance is indistinguishable from a TYPO. Write
|
|
5056
|
+
* `"moveAction": "movement"` and the character stands still, forever, while
|
|
5057
|
+
* `InputMap` has already thrown the exact sentence that would fix it —
|
|
5058
|
+
* `Unknown input action 'movement'. Declared actions: [move, jump].` — and the
|
|
5059
|
+
* catch discards it.
|
|
5060
|
+
*
|
|
5061
|
+
* Reported once per node and action, so a per-frame read does not shout.
|
|
5062
|
+
*/
|
|
5063
|
+
function tolerateUnknownAction(ctx, action, read, fallback) {
|
|
5064
|
+
try {
|
|
5065
|
+
return read();
|
|
5066
|
+
} catch (error) {
|
|
5067
|
+
if (ctx.authored && !ctx.reported.has(action)) {
|
|
5068
|
+
ctx.reported.add(action);
|
|
5069
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
5070
|
+
diagnose(ctx.engine ?? null, "error", `[incanto] ${ctx.who}: ${detail} ${ctx.consequence}`);
|
|
5071
|
+
}
|
|
5072
|
+
return fallback;
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
//#endregion
|
|
4967
5076
|
//#region src/gameplay/game-flow.ts
|
|
4968
5077
|
/**
|
|
4969
5078
|
* Reload the CURRENT scene from its source JSON — fresh nodes, reset physics,
|
|
@@ -5023,7 +5132,7 @@ function goToScene(engine, sceneJson, opts) {
|
|
|
5023
5132
|
* through a `%Banner` UiBanner when one exists; otherwise states are silent
|
|
5024
5133
|
* (drive your own UI off the `flowChanged` signal).
|
|
5025
5134
|
*/
|
|
5026
|
-
var GameFlow = class extends Behavior {
|
|
5135
|
+
var GameFlow = class GameFlow extends Behavior {
|
|
5027
5136
|
static signals = ["flowChanged"];
|
|
5028
5137
|
static props = {
|
|
5029
5138
|
restartAction: { default: "restart" },
|
|
@@ -5049,6 +5158,28 @@ var GameFlow = class extends Behavior {
|
|
|
5049
5158
|
* fine and means pause is API-only).
|
|
5050
5159
|
*/
|
|
5051
5160
|
pauseAction = "pause";
|
|
5161
|
+
/** Actions already reported missing, so a per-frame poll says it once. */
|
|
5162
|
+
reportedActions = /* @__PURE__ */ new Set();
|
|
5163
|
+
/**
|
|
5164
|
+
* Poll an action this flow is allowed to be missing, and say so once when the
|
|
5165
|
+
* author named one that does not exist.
|
|
5166
|
+
*
|
|
5167
|
+
* Tolerated because `pause()` and `restart()` stay API-only in a game with no
|
|
5168
|
+
* such key. Reported because a typed-out `"restartAction": "retry"` that is
|
|
5169
|
+
* never declared leaves a frozen game-over screen that answers nothing, and
|
|
5170
|
+
* the engine has already thrown the sentence that fixes it.
|
|
5171
|
+
*/
|
|
5172
|
+
readAction(prop, consequence) {
|
|
5173
|
+
const action = this[prop];
|
|
5174
|
+
const schema = GameFlow.props[prop];
|
|
5175
|
+
return tolerateUnknownAction({
|
|
5176
|
+
engine: this.engine,
|
|
5177
|
+
who: this.node.getPath(),
|
|
5178
|
+
reported: this.reportedActions,
|
|
5179
|
+
consequence,
|
|
5180
|
+
authored: action !== (typeof schema?.default === "string" ? schema.default : "")
|
|
5181
|
+
}, action, () => this.engine.input.justPressed(action), false);
|
|
5182
|
+
}
|
|
5052
5183
|
/**
|
|
5053
5184
|
* A node shown while paused and hidden otherwise — a `UiPanel` of buttons in
|
|
5054
5185
|
* practice. '' turns the whole thing off.
|
|
@@ -5120,16 +5251,12 @@ var GameFlow = class extends Behavior {
|
|
|
5120
5251
|
}
|
|
5121
5252
|
update() {
|
|
5122
5253
|
if (this.state === "playing" || this.state === "paused") {
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
else this.resume();
|
|
5126
|
-
} catch {}
|
|
5254
|
+
if (this.readAction("pauseAction", "The pause key will do nothing.")) if (this.state === "playing") this.pause();
|
|
5255
|
+
else this.resume();
|
|
5127
5256
|
return;
|
|
5128
5257
|
}
|
|
5129
5258
|
if (this.state !== "gameover" && this.state !== "won") return;
|
|
5130
|
-
|
|
5131
|
-
if (this.engine.input.justPressed(this.restartAction)) this.restart();
|
|
5132
|
-
} catch {}
|
|
5259
|
+
if (this.readAction("restartAction", "The restart key will do nothing.")) this.restart();
|
|
5133
5260
|
}
|
|
5134
5261
|
};
|
|
5135
5262
|
//#endregion
|
|
@@ -5698,7 +5825,10 @@ var Patrol = class extends Behavior {
|
|
|
5698
5825
|
}
|
|
5699
5826
|
const node = this.node;
|
|
5700
5827
|
const target = this.pointAt(this.index);
|
|
5701
|
-
if (!target)
|
|
5828
|
+
if (!target) {
|
|
5829
|
+
this.reportDeadWaypoint(this.index);
|
|
5830
|
+
return;
|
|
5831
|
+
}
|
|
5702
5832
|
const { position, reached } = moveToward(node.position, target, this.speed * dt);
|
|
5703
5833
|
moveBody(node, position, dt);
|
|
5704
5834
|
if (reached) {
|
|
@@ -5707,6 +5837,24 @@ var Patrol = class extends Behavior {
|
|
|
5707
5837
|
if (this.pauseAt > 0) this.pauseTimer = this.pauseAt;
|
|
5708
5838
|
}
|
|
5709
5839
|
}
|
|
5840
|
+
/** Waypoints already reported dead, so a per-frame stall says it once. */
|
|
5841
|
+
reportedDead = /* @__PURE__ */ new Set();
|
|
5842
|
+
/**
|
|
5843
|
+
* Say which waypoint the route died on.
|
|
5844
|
+
*
|
|
5845
|
+
* A `points` entry can be a node path, and a misspelled one stops the
|
|
5846
|
+
* patroller the moment the index reaches it — `advance()` is never called, so
|
|
5847
|
+
* it never moves again — with nothing printed. `points` is an ARRAY, so it
|
|
5848
|
+
* cannot carry `nodePath: true`, and `nodeRefWarnings` only inspects string
|
|
5849
|
+
* props: every other node-path prop in the engine is covered by that lint and
|
|
5850
|
+
* this one is invisible to it.
|
|
5851
|
+
*/
|
|
5852
|
+
reportDeadWaypoint(i) {
|
|
5853
|
+
if (this.reportedDead.has(i)) return;
|
|
5854
|
+
this.reportedDead.add(i);
|
|
5855
|
+
const raw = this.points[i];
|
|
5856
|
+
diagnose(this.node.tree?.engine ?? null, "error", `[incanto] ${this.node.getPath()}: waypoint ${i} (${JSON.stringify(raw)}) resolves to nothing — the patrol stops here and never moves again.`);
|
|
5857
|
+
}
|
|
5710
5858
|
/** Resolve waypoint `i` to a position, reading node paths live. */
|
|
5711
5859
|
pointAt(i) {
|
|
5712
5860
|
const raw = this.points[i];
|
|
@@ -6636,7 +6784,8 @@ const GAMEPLAY_BEHAVIORS = {
|
|
|
6636
6784
|
Spawner,
|
|
6637
6785
|
WaveSpawner,
|
|
6638
6786
|
Projectile,
|
|
6639
|
-
Buoyancy
|
|
6787
|
+
Buoyancy,
|
|
6788
|
+
FloatAway
|
|
6640
6789
|
};
|
|
6641
6790
|
/**
|
|
6642
6791
|
* Register all built-in gameplay behaviors. Idempotent and hot-reload tolerant
|
|
@@ -6648,4 +6797,4 @@ function registerGameplayBehaviors(opts) {
|
|
|
6648
6797
|
for (const [name, ctor] of Object.entries(GAMEPLAY_BEHAVIORS)) registerBehavior(name, ctor, { replace });
|
|
6649
6798
|
}
|
|
6650
6799
|
//#endregion
|
|
6651
|
-
export {
|
|
6800
|
+
export { Health as A, StaticBody3D as B, restartScene as C, DayNight as D, FloatAway as E, WaterCutout3D as F, colliderFootDrop as G, validateCollider3D as H, Area3D as I, CharacterBody3D as L, Chase as M, Water3D as N, phaseOf as O, WATER_CUTOUT_MAX as P, PhysicsBody3D as R, goToScene as S, FollowCamera as T, createCausticsQuad as U, Node3D as V, WATER_MAX_RIPPLES as W, Cooldown as _, Wander as a, Interactable as b, SavePoint as c, Patrol as d, PathFollow as f, CameraShake as g, Lifetime as h, WaveSpawner as i, Collector as j, DamageOnContact as k, Projectile as l, MoveTo as m, registerGameplayBehaviors as n, Spawner as o, Oscillate as p, ZombieAI as r, ScoreKeeper as s, GAMEPLAY_BEHAVIORS as t, Pickup as u, hitStop as v, tolerateUnknownAction as w, GameFlow as x, screenFlash as y, RigidBody3D as z };
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-
|
|
1
|
+
import { At as Node, b as Engine, d as PropSchema, n as BehaviorCtor, t as Behavior } from "./behavior-l08AEbq9.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
|
@@ -318,6 +318,19 @@ declare class Patrol extends Behavior {
|
|
|
318
318
|
private pauseTimer;
|
|
319
319
|
override onReady(): void;
|
|
320
320
|
override update(dt: number): void;
|
|
321
|
+
/** Waypoints already reported dead, so a per-frame stall says it once. */
|
|
322
|
+
private readonly reportedDead;
|
|
323
|
+
/**
|
|
324
|
+
* Say which waypoint the route died on.
|
|
325
|
+
*
|
|
326
|
+
* A `points` entry can be a node path, and a misspelled one stops the
|
|
327
|
+
* patroller the moment the index reaches it — `advance()` is never called, so
|
|
328
|
+
* it never moves again — with nothing printed. `points` is an ARRAY, so it
|
|
329
|
+
* cannot carry `nodePath: true`, and `nodeRefWarnings` only inspects string
|
|
330
|
+
* props: every other node-path prop in the engine is covered by that lint and
|
|
331
|
+
* this one is invisible to it.
|
|
332
|
+
*/
|
|
333
|
+
private reportDeadWaypoint;
|
|
321
334
|
/** Resolve waypoint `i` to a position, reading node paths live. */
|
|
322
335
|
private pointAt;
|
|
323
336
|
private advance;
|
|
@@ -678,6 +691,60 @@ declare class DayNight extends Behavior {
|
|
|
678
691
|
}
|
|
679
692
|
declare function phaseOf(hour: number): DayPhase;
|
|
680
693
|
//#endregion
|
|
694
|
+
//#region src/gameplay/float-away.d.ts
|
|
695
|
+
/**
|
|
696
|
+
* Rise, fade, and be gone — the second half of a damage number.
|
|
697
|
+
*
|
|
698
|
+
* `Label3D` gave a game text standing in the world; every game then writes the
|
|
699
|
+
* same eight lines to move it up and fade it out, and the interesting part is
|
|
700
|
+
* not the eight lines, it is the three things they all get wrong: the node is
|
|
701
|
+
* freed on the frame it becomes invisible rather than a second later, the fade
|
|
702
|
+
* fights whatever else writes `opacity`, and a hundred numbers a fight each
|
|
703
|
+
* leave a node behind because nothing ever frees them.
|
|
704
|
+
*
|
|
705
|
+
* ```json
|
|
706
|
+
* { "name": "Hit", "type": "Label3D",
|
|
707
|
+
* "props": { "text": "12", "height": 0.35, "color": "#ff5a5a" },
|
|
708
|
+
* "script": { "name": "FloatAway", "props": { "rise": 1.2, "seconds": 0.7 } } }
|
|
709
|
+
* ```
|
|
710
|
+
*
|
|
711
|
+
* Spawning one is then `duplicateNode` + set `text` + `position` — no per-frame
|
|
712
|
+
* code of your own, and no cleanup to forget.
|
|
713
|
+
*
|
|
714
|
+
* It writes `opacity` and the node's own `position`, so it composes with
|
|
715
|
+
* anything that does not. Works on any node with those props: a `Label3D`, a
|
|
716
|
+
* `Sprite3D` pickup puff, a 2D `Label`.
|
|
717
|
+
*/
|
|
718
|
+
declare class FloatAway extends Behavior {
|
|
719
|
+
static override readonly props: {
|
|
720
|
+
/** World units travelled over the whole life (negative sinks). */rise: {
|
|
721
|
+
default: number;
|
|
722
|
+
}; /** How long the whole thing takes. */
|
|
723
|
+
seconds: {
|
|
724
|
+
default: number;
|
|
725
|
+
}; /** Fraction of the life spent at full opacity before the fade starts. */
|
|
726
|
+
hold: {
|
|
727
|
+
default: number;
|
|
728
|
+
}; /** Sideways drift, so ten numbers at once do not stack into one. */
|
|
729
|
+
drift: {
|
|
730
|
+
default: number;
|
|
731
|
+
}; /** Free the node when it finishes. Off for something you re-use. */
|
|
732
|
+
freeOnEnd: {
|
|
733
|
+
default: boolean;
|
|
734
|
+
};
|
|
735
|
+
};
|
|
736
|
+
rise: number;
|
|
737
|
+
seconds: number;
|
|
738
|
+
hold: number;
|
|
739
|
+
drift: number;
|
|
740
|
+
freeOnEnd: boolean;
|
|
741
|
+
private elapsed;
|
|
742
|
+
private start;
|
|
743
|
+
private done;
|
|
744
|
+
override onReady(): void;
|
|
745
|
+
override update(dt: number): void;
|
|
746
|
+
}
|
|
747
|
+
//#endregion
|
|
681
748
|
//#region src/gameplay/game-flow.d.ts
|
|
682
749
|
/**
|
|
683
750
|
* Reload the CURRENT scene from its source JSON — fresh nodes, reset physics,
|
|
@@ -721,6 +788,18 @@ declare class GameFlow extends Behavior {
|
|
|
721
788
|
* fine and means pause is API-only).
|
|
722
789
|
*/
|
|
723
790
|
pauseAction: string;
|
|
791
|
+
/** Actions already reported missing, so a per-frame poll says it once. */
|
|
792
|
+
private readonly reportedActions;
|
|
793
|
+
/**
|
|
794
|
+
* Poll an action this flow is allowed to be missing, and say so once when the
|
|
795
|
+
* author named one that does not exist.
|
|
796
|
+
*
|
|
797
|
+
* Tolerated because `pause()` and `restart()` stay API-only in a game with no
|
|
798
|
+
* such key. Reported because a typed-out `"restartAction": "retry"` that is
|
|
799
|
+
* never declared leaves a frozen game-over screen that answers nothing, and
|
|
800
|
+
* the engine has already thrown the sentence that fixes it.
|
|
801
|
+
*/
|
|
802
|
+
private readAction;
|
|
724
803
|
/**
|
|
725
804
|
* A node shown while paused and hidden otherwise — a `UiPanel` of buttons in
|
|
726
805
|
* practice. '' turns the whole thing off.
|
|
@@ -869,4 +948,4 @@ declare function registerGameplayBehaviors(opts?: {
|
|
|
869
948
|
replace?: boolean;
|
|
870
949
|
}): void;
|
|
871
950
|
//#endregion
|
|
872
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, type DayPhase, 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 };
|
|
951
|
+
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 };
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { CameraShake, Chase, Collector, Cooldown, DamageOnContact, DayNight, 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 Health, C as restartScene, D as DayNight, E as FloatAway, M as Chase, O as phaseOf, 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 Collector, k as DamageOnContact, 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-BVphcxmE.js";
|
|
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 };
|