incanto 0.60.0 → 0.62.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-check.mjs +13 -0
- package/bin/incanto-verify.mjs +134 -55
- package/dist/2d.d.ts +64 -3
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +5 -5
- package/dist/3d.js +5 -4
- package/dist/{pathfinding-BqWBb0kh.d.ts → audio-player-D5GJgb_x.d.ts} +103 -38
- package/dist/{behavior-DWKTUzKI.d.ts → behavior-DsgayMsH.d.ts} +79 -1
- package/dist/{create-game-ClnIb_M5.js → create-game-BpunnGPX.js} +78 -13
- package/dist/{create-game-BCm38FJV.js → create-game-Caut3bqN.js} +21 -294
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/{duplicate-DJQd44CD.js → duplicate-E4FUs5Bn.js} +1 -1
- package/dist/editor.js +41 -19
- package/dist/{environment-presets-8cjF3t6w.js → environment-presets-BAWeOeqf.js} +50 -13
- package/dist/{gameplay-BBEjPFsR.js → gameplay-CaHqDiQD.js} +177 -24
- package/dist/gameplay.d.ts +1 -1
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +97 -6
- package/dist/index.js +7 -7
- package/dist/{loader-D8n7TU8W.js → loader-DEe272nY.js} +900 -2
- package/dist/{loader-TvkRFbyL.d.ts → loader-DolLJWJn.d.ts} +13 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +1 -1
- package/dist/pathfinding-_fGrCFmH.d.ts +28 -0
- package/dist/{physics-2d-DqdVp1bt.js → physics-2d-BXmu2i7W.js} +11 -3
- package/dist/{physics-3d-BP0DZb_1.js → physics-3d-ClxP6Uv7.js} +121 -17
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-BSu2dWGC.js → register-CNh4FlbD.js} +104 -16
- package/dist/{register-Da3hXh2H.js → register-D3yx8D4r.js} +228 -16
- package/dist/{registry-WWcQcfMr.js → registry-CF70EArN.js} +55 -3
- package/dist/{replay-BCMK_VRP.d.ts → replay-C5x2vPF5.d.ts} +2 -2
- package/dist/{replay-BlNuIDdg.js → replay-DlgHItNv.js} +57 -197
- package/dist/{split-screen-CL5Yvxse.js → split-screen-CBM9wcMX.js} +3 -3
- package/dist/{split-screen-BQ3tAsf-.d.ts → split-screen-D7OopelJ.d.ts} +2 -2
- package/dist/{src-DFpXBMJN.js → src-CH00_JsR.js} +1 -1
- package/dist/{teardown-CTTwhWSe.js → teardown-C7qP-dcC.js} +1 -1
- package/dist/{test-BeZ95pqw.js → test-BMkg8zMV.js} +29 -16
- package/dist/test.d.ts +45 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +2 -2
- package/editor/assets/{agent8-DSJries_.js → agent8-m5mtAO_A.js} +1 -1
- package/editor/assets/{debug-D15Wi5TO.js → debug-CPhzCT8f.js} +1 -1
- package/editor/assets/{index-BjC88k97.js → index-D422P4kW.js} +92 -92
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +91 -0
- package/skills/incanto-3d-models.md +1 -1
- package/skills/incanto-assets.md +10 -1
- package/skills/incanto-audio.md +21 -13
- package/skills/incanto-behaviors-and-scripts.md +44 -3
- package/skills/incanto-building-2d-games.md +32 -4
- package/skills/incanto-building-3d-games.md +1 -1
- package/skills/incanto-editor.md +1 -1
- package/skills/incanto-gameplay-behaviors.md +39 -2
- package/skills/incanto-hud.md +5 -3
- package/skills/incanto-localization.md +7 -0
- package/skills/incanto-node-reference.md +12 -0
- package/skills/incanto-physics-and-input.md +23 -2
- package/skills/incanto-scene-json-authoring.md +6 -1
- package/skills/incanto-verifying-your-game.md +31 -1
- 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/dist/particle-sim-C5OfBbmU.d.ts +0 -77
package/dist/editor.js
CHANGED
|
@@ -1111,6 +1111,13 @@ var kt = {
|
|
|
1111
1111
|
en: "Set waitTime (seconds), optionally autostart or oneShot, and connect its timeout signal to any handler. Because it is a node, the whole timing setup lives in the scene file — agents can read and tune it.",
|
|
1112
1112
|
ko: "waitTime(초)을 정하고 autostart·oneShot을 선택한 뒤 timeout 시그널을 핸들러에 연결하세요. 노드이기 때문에 타이밍 설정 전체가 씬 파일에 남아 에이전트가 읽고 조정할 수 있습니다."
|
|
1113
1113
|
}),
|
|
1114
|
+
L("Respawn", {
|
|
1115
|
+
en: "Catches whatever it hangs off when it leaves the world, and puts it back.",
|
|
1116
|
+
ko: "부모가 월드 밖으로 떨어지면 붙잡아 원래 자리로 되돌립니다."
|
|
1117
|
+
}, {
|
|
1118
|
+
en: "Make it a child of the player. With no props it catches its parent 50 m under the spawn (1000 px in 2D — the same line incanto-playtest calls \"fell\"), returns it to where it started and zeroes the velocity the fall built up. below names the line, to names the landing, target picks a different node. It emits respawned, and deliberately does not decide what falling COSTS — wire that to a ScoreKeeper or a Health if it should hurt.",
|
|
1119
|
+
ko: "플레이어의 자식으로 두세요. 프롭 없이도 스폰 50 m 아래(2D는 1000 px — incanto-playtest가 \"fell\"로 부르는 그 선)에서 부모를 붙잡아 처음 위치로 되돌리고, 낙하로 쌓인 속도를 0으로 만듭니다. below는 그 선, to는 착지 지점, target은 다른 노드를 지정합니다. respawned 시그널을 쏘며, 추락의 \"대가\"는 일부러 정하지 않습니다 — 피해를 주려면 ScoreKeeper나 Health에 연결하세요."
|
|
1120
|
+
}),
|
|
1114
1121
|
L("HudLayer", {
|
|
1115
1122
|
en: "Screen-space HUD overlay above the canvas — parent for UiText/UiBar/UiBanner.",
|
|
1116
1123
|
ko: "캔버스 위 화면 고정 HUD 오버레이 — UiText/UiBar/UiBanner의 부모."
|
|
@@ -2372,7 +2379,8 @@ function Bn(e, t, n) {
|
|
|
2372
2379
|
var Vn = [
|
|
2373
2380
|
"connections",
|
|
2374
2381
|
"input",
|
|
2375
|
-
"multiplayer"
|
|
2382
|
+
"multiplayer",
|
|
2383
|
+
"strings"
|
|
2376
2384
|
];
|
|
2377
2385
|
function Hn(e, t, n) {
|
|
2378
2386
|
e.appendChild(Tr("scene")), e.appendChild(Ar("name", String(t.working.name ?? ""), (e) => {
|
|
@@ -9291,8 +9299,15 @@ function yc(e) {
|
|
|
9291
9299
|
let t = e.assets;
|
|
9292
9300
|
if (t) for (let e of Object.values(t)) typeof e?.url == "string" && !e.url.includes("/") && !e.url.includes(".") && (e.url = vc());
|
|
9293
9301
|
}
|
|
9302
|
+
//#endregion
|
|
9303
|
+
//#region src/main.ts
|
|
9304
|
+
var bc = new Set([
|
|
9305
|
+
"Terrain3D",
|
|
9306
|
+
"Water3D",
|
|
9307
|
+
"River3D"
|
|
9308
|
+
]);
|
|
9294
9309
|
m(), b(), k(), ee(), A();
|
|
9295
|
-
async function
|
|
9310
|
+
async function xc(e = {}) {
|
|
9296
9311
|
let t = e.api ?? ze, n = [], r = document.createElement("style");
|
|
9297
9312
|
r.dataset.incantoEditor = "true", r.textContent = vs, document.head.appendChild(r), n.push(() => r.remove());
|
|
9298
9313
|
let i = document.createElement("div");
|
|
@@ -9389,11 +9404,18 @@ async function bc(e = {}) {
|
|
|
9389
9404
|
0,
|
|
9390
9405
|
0
|
|
9391
9406
|
]),
|
|
9392
|
-
onNodeScaled3D: (e, t) =>
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9396
|
-
|
|
9407
|
+
onNodeScaled3D: (e, t) => {
|
|
9408
|
+
let n = u.nodeAt(e);
|
|
9409
|
+
if (n && bc.has(String(n.type))) {
|
|
9410
|
+
O(`${n.type} '${n.name}' cannot be scaled — scale would move only the mesh. Resize it with its "size" prop in the inspector.`);
|
|
9411
|
+
return;
|
|
9412
|
+
}
|
|
9413
|
+
de(e, "scale", t, [
|
|
9414
|
+
1,
|
|
9415
|
+
1,
|
|
9416
|
+
1
|
|
9417
|
+
]);
|
|
9418
|
+
},
|
|
9397
9419
|
onNodeRotated2D: (e, t) => ue(e, "rotation", t, 0),
|
|
9398
9420
|
onNodeRotated3D: (e, t) => de(e, "rotation", t, [
|
|
9399
9421
|
0,
|
|
@@ -9479,15 +9501,15 @@ async function bc(e = {}) {
|
|
|
9479
9501
|
...e.shelf ? { shelf: e.shelf } : {},
|
|
9480
9502
|
...e.assetType ? { assetType: e.assetType } : {},
|
|
9481
9503
|
...e.onProps ? { onProps: e.onProps } : {},
|
|
9482
|
-
...e.asAsset ? { onAsset: (e, t, n) =>
|
|
9504
|
+
...e.asAsset ? { onAsset: (e, t, n) => Tc(u, n, t) } : {}
|
|
9483
9505
|
}) : void 0, le = !1, F = () => {
|
|
9484
9506
|
if (!E) return;
|
|
9485
9507
|
js(d, u), rt(a("#asset-tree"), u), f.textContent = "", it(f, u, Ce, ce) || Bn(f, u, {
|
|
9486
|
-
modelRefs: () =>
|
|
9508
|
+
modelRefs: () => Cc(u, "model"),
|
|
9487
9509
|
animationsForSelection: () => u.selection ? P.modelAnimationsAt(u.selection) : [],
|
|
9488
9510
|
bonesForSelection: (e) => u.selection ? P.boneNamesAt(u.selection, e) : [],
|
|
9489
|
-
assetRefs: (e) =>
|
|
9490
|
-
addAsset: (e, t) =>
|
|
9511
|
+
assetRefs: (e) => wc(u, e),
|
|
9512
|
+
addAsset: (e, t) => Tc(u, e, t),
|
|
9491
9513
|
...ce ? { openLibrary: ce } : {},
|
|
9492
9514
|
confirm: Ce,
|
|
9493
9515
|
paint: {
|
|
@@ -9599,7 +9621,7 @@ async function bc(e = {}) {
|
|
|
9599
9621
|
if (e.length === 0) {
|
|
9600
9622
|
let e = u.working.root;
|
|
9601
9623
|
if (!e) return;
|
|
9602
|
-
let t =
|
|
9624
|
+
let t = Sc(e);
|
|
9603
9625
|
Ce(`This deletes the ROOT '${String(e.name ?? "")}'${t > 0 ? ` AND its ${t} descendant node${t === 1 ? "" : "s"}` : ""} — the scene goes empty, and the next node you add becomes the new root.`, "delete root", () => u.deleteRoot());
|
|
9604
9626
|
return;
|
|
9605
9627
|
}
|
|
@@ -9607,7 +9629,7 @@ async function bc(e = {}) {
|
|
|
9607
9629
|
if (n.length === 0) {
|
|
9608
9630
|
let n = e.reduce((e, t) => {
|
|
9609
9631
|
let n = u.nodeAt(t);
|
|
9610
|
-
return e + (n ?
|
|
9632
|
+
return e + (n ? Sc(n) : 0);
|
|
9611
9633
|
}, 0);
|
|
9612
9634
|
if (n > 0) {
|
|
9613
9635
|
Ce(`This deletes ${e.length > 1 ? `${e.length} nodes` : `'${String(u.nodeAt(e[0] ?? [])?.name ?? "")}'`} AND ${n} descendant node${n === 1 ? "" : "s"}.`, `delete ${e.length + n} nodes`, () => {
|
|
@@ -9783,20 +9805,20 @@ async function bc(e = {}) {
|
|
|
9783
9805
|
}
|
|
9784
9806
|
};
|
|
9785
9807
|
}
|
|
9786
|
-
function
|
|
9808
|
+
function Sc(e) {
|
|
9787
9809
|
let t = 0;
|
|
9788
|
-
for (let n of e.children ?? []) t += 1 +
|
|
9810
|
+
for (let n of e.children ?? []) t += 1 + Sc(n);
|
|
9789
9811
|
return t;
|
|
9790
9812
|
}
|
|
9791
|
-
function
|
|
9813
|
+
function Cc(e, t) {
|
|
9792
9814
|
let n = e.working.assets;
|
|
9793
9815
|
return n ? Object.entries(n).filter(([, e]) => e?.type === t).map(([e]) => `$${e}`) : [];
|
|
9794
9816
|
}
|
|
9795
|
-
function
|
|
9817
|
+
function wc(e, t) {
|
|
9796
9818
|
let n = e.working.assets;
|
|
9797
9819
|
return n ? Object.entries(n).filter(([, e]) => !t || e?.type !== void 0 && t.includes(e.type)).map(([e]) => `$${e}`) : [];
|
|
9798
9820
|
}
|
|
9799
|
-
function
|
|
9821
|
+
function Tc(e, t, n) {
|
|
9800
9822
|
let r = e.working.assets ?? {};
|
|
9801
9823
|
for (let [e, t] of Object.entries(r)) if (t?.url === n.url) return `$${e}`;
|
|
9802
9824
|
let i = t;
|
|
@@ -9806,4 +9828,4 @@ function wc(e, t, n) {
|
|
|
9806
9828
|
}), `$${i}`;
|
|
9807
9829
|
}
|
|
9808
9830
|
//#endregion
|
|
9809
|
-
export { N as formatSceneJson, ze as httpEditorApi,
|
|
9831
|
+
export { N as formatSceneJson, ze as httpEditorApi, xc as mountEditor };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { k as diagnose } from "./loader-DEe272nY.js";
|
|
2
|
+
import { L as translateOn, t as registerCoreNodes } from "./register-D3yx8D4r.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
5
|
-
import { i as getNodeSchema, l as registerNode } from "./registry-
|
|
5
|
+
import { i as getNodeSchema, l as registerNode } from "./registry-CF70EArN.js";
|
|
6
6
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
7
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-CY-mrr1L.js";
|
|
8
|
-
import { B as
|
|
8
|
+
import { B as CharacterBody3D, F as Water3D, H as RigidBody3D, J as colliderFootDrop, L as WaterCutout3D, R as rejectScale, U as StaticBody3D, V as PhysicsBody3D, W as Node3D, w as tolerateUnknownAction, z as Area3D } from "./gameplay-CaHqDiQD.js";
|
|
9
9
|
import { t as checkSheetGrid } from "./sheet-grid-BT6N_Bjs.js";
|
|
10
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
11
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";
|
|
@@ -727,7 +727,8 @@ var Joint3D = class extends Node3D {
|
|
|
727
727
|
},
|
|
728
728
|
target: {
|
|
729
729
|
default: "",
|
|
730
|
-
nodePath: true
|
|
730
|
+
nodePath: true,
|
|
731
|
+
required: true
|
|
731
732
|
},
|
|
732
733
|
anchor: { default: [
|
|
733
734
|
0,
|
|
@@ -1574,6 +1575,7 @@ var Terrain3D = class extends Node3D {
|
|
|
1574
1575
|
}
|
|
1575
1576
|
/** Loader hook: bad themes/layers/grids fail at LOAD, not at render. */
|
|
1576
1577
|
static validateJson(node) {
|
|
1578
|
+
rejectScale(node, "heightAt(), the heightfield collider, drape and terrain-nav all");
|
|
1577
1579
|
const t = node;
|
|
1578
1580
|
if (!TERRAIN_THEMES.includes(t.theme)) throw new IncantoError("BAD_FORMAT", `Terrain3D '${node.name}' theme must be one of [${TERRAIN_THEMES.join(", ")}], got '${t.theme}'.`, {
|
|
1579
1581
|
prop: "theme",
|
|
@@ -2335,7 +2337,8 @@ var BoneAttachment3D = class extends Node3D {
|
|
|
2335
2337
|
/** Node path to the ModelInstance3D whose skeleton to ride. */
|
|
2336
2338
|
target: {
|
|
2337
2339
|
default: "",
|
|
2338
|
-
nodePath: true
|
|
2340
|
+
nodePath: true,
|
|
2341
|
+
required: true
|
|
2339
2342
|
},
|
|
2340
2343
|
/** Bone name ("RightHand", "Head", …). Empty = inert. */
|
|
2341
2344
|
bone: { default: "" }
|
|
@@ -2428,7 +2431,8 @@ var BoneLookAt3D = class extends Node3D {
|
|
|
2428
2431
|
/** Node path to the ModelInstance3D whose bone to steer. */
|
|
2429
2432
|
target: {
|
|
2430
2433
|
default: "",
|
|
2431
|
-
nodePath: true
|
|
2434
|
+
nodePath: true,
|
|
2435
|
+
required: true
|
|
2432
2436
|
},
|
|
2433
2437
|
/** Bone name ("Head", "Neck", "Spine2" — Mixamo spellings matched). */
|
|
2434
2438
|
bone: { default: "Head" },
|
|
@@ -2440,7 +2444,13 @@ var BoneLookAt3D = class extends Node3D {
|
|
|
2440
2444
|
/** Comfort cone half-angle, degrees — beyond it the head returns to the anim. */
|
|
2441
2445
|
maxAngleDeg: { default: 75 },
|
|
2442
2446
|
/** Blend weight 0..1 (how far toward the target the bone turns). */
|
|
2443
|
-
weight: {
|
|
2447
|
+
weight: {
|
|
2448
|
+
default: .85,
|
|
2449
|
+
range: {
|
|
2450
|
+
min: 0,
|
|
2451
|
+
max: 1
|
|
2452
|
+
}
|
|
2453
|
+
},
|
|
2444
2454
|
/** The bone's local facing axis. */
|
|
2445
2455
|
forwardAxis: {
|
|
2446
2456
|
default: "+z",
|
|
@@ -6449,9 +6459,21 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6449
6459
|
static signals = ["animationFinished"];
|
|
6450
6460
|
static props = {
|
|
6451
6461
|
...Node3D.props,
|
|
6452
|
-
model: {
|
|
6453
|
-
|
|
6454
|
-
|
|
6462
|
+
model: {
|
|
6463
|
+
default: "",
|
|
6464
|
+
asset: {
|
|
6465
|
+
kind: "model",
|
|
6466
|
+
refOnly: true
|
|
6467
|
+
}
|
|
6468
|
+
},
|
|
6469
|
+
animation: {
|
|
6470
|
+
default: "",
|
|
6471
|
+
asset: { kind: "animation" }
|
|
6472
|
+
},
|
|
6473
|
+
targetHeight: {
|
|
6474
|
+
default: 0,
|
|
6475
|
+
range: { min: 0 }
|
|
6476
|
+
},
|
|
6455
6477
|
castShadow: { default: false },
|
|
6456
6478
|
animationLoop: { default: true },
|
|
6457
6479
|
/** Playback rate: 1 = authored speed, 0.5 = half, 2 = double. */
|
|
@@ -6466,8 +6488,22 @@ var ModelInstance3D = class extends Node3D {
|
|
|
6466
6488
|
upperBodyRoot: { default: "Spine" },
|
|
6467
6489
|
receiveShadow: { default: false },
|
|
6468
6490
|
tint: { default: "" },
|
|
6469
|
-
metalness: {
|
|
6470
|
-
|
|
6491
|
+
metalness: {
|
|
6492
|
+
default: -1,
|
|
6493
|
+
range: {
|
|
6494
|
+
min: 0,
|
|
6495
|
+
max: 1,
|
|
6496
|
+
allow: [-1]
|
|
6497
|
+
}
|
|
6498
|
+
},
|
|
6499
|
+
roughness: {
|
|
6500
|
+
default: -1,
|
|
6501
|
+
range: {
|
|
6502
|
+
min: 0,
|
|
6503
|
+
max: 1,
|
|
6504
|
+
allow: [-1]
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6471
6507
|
};
|
|
6472
6508
|
model = "";
|
|
6473
6509
|
animation = "";
|
|
@@ -8770,6 +8806,7 @@ var River3D = class River3D extends Node3D {
|
|
|
8770
8806
|
_bodies = [];
|
|
8771
8807
|
/** Loader hook: a malformed river fails at LOAD, not as an invisible ribbon. */
|
|
8772
8808
|
static validateJson(node) {
|
|
8809
|
+
rejectScale(node, "the flow query and its collider both");
|
|
8773
8810
|
const r = node;
|
|
8774
8811
|
if (!Array.isArray(r.path)) throw new IncantoError("BAD_FORMAT", `River3D '${node.name}' path must be an array of [x, z] points, got ${JSON.stringify(r.path)}.`, { prop: "path" });
|
|
8775
8812
|
if (r.path.length > 0 && r.path.length < 2) throw new IncantoError("BAD_FORMAT", `River3D '${node.name}' path needs at least 2 points (source → mouth), got ${r.path.length}.`, { prop: "path" });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { O as Node, P as Behavior, _ as SaveSlots, k as diagnose, n as loadScene, w as effectiveOrder, z as registerBehavior } from "./loader-DEe272nY.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-CwwhxQgb.js";
|
|
4
|
-
import { t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { t as duplicateNode } from "./duplicate-E4FUs5Bn.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();
|
|
@@ -2625,6 +2625,51 @@ var CharacterBody3D = class extends PhysicsBody3D {
|
|
|
2625
2625
|
}
|
|
2626
2626
|
};
|
|
2627
2627
|
//#endregion
|
|
2628
|
+
//#region src/3d/nodes/unscalable.ts
|
|
2629
|
+
/**
|
|
2630
|
+
* Refuse `scale` on a node that keeps a CPU twin of itself.
|
|
2631
|
+
*
|
|
2632
|
+
* `scale` is a plain `Node3D` prop and the 3D skill actively recommends it —
|
|
2633
|
+
* *"resize with `scale`, not `size` — resizing a mesh rebuilds its geometry
|
|
2634
|
+
* every call, scaling is free"*. On a mesh that is true. On `Terrain3D`,
|
|
2635
|
+
* `Water3D` and `River3D` it resizes only the PICTURE: everything the gameplay
|
|
2636
|
+
* layer reads is scale-blind, because it reads `size`.
|
|
2637
|
+
*
|
|
2638
|
+
* - `Terrain3D.heightAt` indexes a heightmap built from `size` and composes
|
|
2639
|
+
* ancestor POSITIONS only
|
|
2640
|
+
* - `buildHeightfieldDesc3D` passes `{x: hm.width, y: 1, z: hm.depth}` with no
|
|
2641
|
+
* scale term
|
|
2642
|
+
* - `Water3D._waterYAt` rejects anything outside `size / 2` of the node
|
|
2643
|
+
*
|
|
2644
|
+
* Measured on `size: [100, 100]` at `scale: [2, 1, 2]`:
|
|
2645
|
+
*
|
|
2646
|
+
* ```
|
|
2647
|
+
* terrain rendered X extent = [-100.0, 100.0] (was [-50, 50])
|
|
2648
|
+
* terrain heightAt(70, 0) = -50.000 (unchanged: the island floor)
|
|
2649
|
+
* water rendered X extent = [-40.0, 40.0]
|
|
2650
|
+
* water _waterYAt(30, 0) = null (unchanged)
|
|
2651
|
+
* ```
|
|
2652
|
+
*
|
|
2653
|
+
* So the player walks off an invisible cliff at ±50 m onto ground that is
|
|
2654
|
+
* visibly there for another 50; drape, spawn placement and terrain-nav all
|
|
2655
|
+
* agree with the collider and disagree with the picture; a scaled water's
|
|
2656
|
+
* underwater fog, splash and `avoidWater` culling stop at half the visible
|
|
2657
|
+
* shoreline. `incanto check` called the scene valid and `auditScene` said
|
|
2658
|
+
* nothing.
|
|
2659
|
+
*
|
|
2660
|
+
* A hard load error rather than a warning, per the engine's own guardrail: the
|
|
2661
|
+
* dial the author wanted exists and is one word away.
|
|
2662
|
+
*/
|
|
2663
|
+
function rejectScale(node, reads) {
|
|
2664
|
+
const scale = node.scale;
|
|
2665
|
+
if (!Array.isArray(scale)) return;
|
|
2666
|
+
if (scale.every((v) => Math.abs((v ?? 1) - 1) < 1e-4)) return;
|
|
2667
|
+
const type = node.constructor.typeName ?? "node";
|
|
2668
|
+
const size = node.size;
|
|
2669
|
+
const suggestion = Array.isArray(size) ? `size: [${size.map((v, i) => (v ?? 0) * (scale[i === 1 ? 2 : i] ?? 1)).join(", ")}]` : "size";
|
|
2670
|
+
throw new IncantoError("BAD_FORMAT", `${type} '${node.name}' has scale ${JSON.stringify(scale)}. On this node scale resizes only the MESH — ${reads} read "size" — so the ground you can see would reach past the ground you can stand on. Resize with "${suggestion}" instead.`, { prop: "scale" });
|
|
2671
|
+
}
|
|
2672
|
+
//#endregion
|
|
2628
2673
|
//#region src/3d/nodes/water-cutout-3d.ts
|
|
2629
2674
|
/**
|
|
2630
2675
|
* A box the water does not enter.
|
|
@@ -3155,6 +3200,7 @@ var Water3D = class Water3D extends Node3D {
|
|
|
3155
3200
|
}
|
|
3156
3201
|
/** Loader hook: degenerate planes and bad enums fail at LOAD, not at render. */
|
|
3157
3202
|
static validateJson(node) {
|
|
3203
|
+
rejectScale(node, "the water surface query, underwater fog, splashes and buoyancy all");
|
|
3158
3204
|
const w = node;
|
|
3159
3205
|
if (!((w.size[0] ?? 0) > 0) || !((w.size[1] ?? 0) > 0)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' size must be positive [width, depth] meters, got ${JSON.stringify(w.size)}.`, { prop: "size" });
|
|
3160
3206
|
if (!WATER_QUALITIES.includes(w.quality)) throw new IncantoError("BAD_FORMAT", `Water3D '${node.name}' quality must be one of [${WATER_QUALITIES.join(", ")}], got '${w.quality}'.`, {
|
|
@@ -4388,6 +4434,56 @@ function smoothingFactor(smoothing, dt) {
|
|
|
4388
4434
|
const s = Math.min(Math.max(smoothing, 0), .99);
|
|
4389
4435
|
return s <= 0 ? 1 : 1 - s ** (dt * 60);
|
|
4390
4436
|
}
|
|
4437
|
+
/**
|
|
4438
|
+
* A node's position with every spatial ancestor's added in.
|
|
4439
|
+
*
|
|
4440
|
+
* The tree composes transforms for DRAWING — three does it for free — and every
|
|
4441
|
+
* piece of engine logic that reads `node.position` gets the LOCAL number
|
|
4442
|
+
* instead. Physics already knew (`worldPosition2D`/`worldPosition3D` in the
|
|
4443
|
+
* adapters); the camera did not, and neither did anything that chases a target.
|
|
4444
|
+
*
|
|
4445
|
+
* A camera parented to the player is the Godot and Phaser idiom, and the
|
|
4446
|
+
* authoring skill explicitly permits it — *"EVERY node type can hold children …
|
|
4447
|
+
* any node works as a grouping container"*. Measured on exactly that scene:
|
|
4448
|
+
*
|
|
4449
|
+
* ```
|
|
4450
|
+
* player world position : [1400, 900]
|
|
4451
|
+
* renderer view centre : {"x":0,"y":0}
|
|
4452
|
+
* framing : camera /Level/Player/Cam centred [1400, 900]
|
|
4453
|
+
* 1 in view, 0 outside it
|
|
4454
|
+
* ```
|
|
4455
|
+
*
|
|
4456
|
+
* The renderer drew empty world 1600 px from the player while `framing` — the
|
|
4457
|
+
* instrument the skills tell you to trust before handing a game back —
|
|
4458
|
+
* certified the player on screen.
|
|
4459
|
+
*
|
|
4460
|
+
* Arity comes from the node itself: a 2D node has two components, a 3D node
|
|
4461
|
+
* three, and an ancestor that is neither contributes nothing.
|
|
4462
|
+
*/
|
|
4463
|
+
function worldPosition(node) {
|
|
4464
|
+
const own = node.position;
|
|
4465
|
+
if (!Array.isArray(own)) return [];
|
|
4466
|
+
const out = own.slice();
|
|
4467
|
+
for (let at = node.parent; at; at = at.parent) {
|
|
4468
|
+
const p = at.position;
|
|
4469
|
+
if (!Array.isArray(p)) continue;
|
|
4470
|
+
for (let i = 0; i < out.length; i++) out[i] = (out[i] ?? 0) + (p[i] ?? 0);
|
|
4471
|
+
}
|
|
4472
|
+
return out;
|
|
4473
|
+
}
|
|
4474
|
+
/**
|
|
4475
|
+
* Turn a world position into the local one `node.position` has to hold for the
|
|
4476
|
+
* node to END UP there — the inverse of `worldPosition` for its parent chain.
|
|
4477
|
+
*/
|
|
4478
|
+
function localFromWorld(node, world) {
|
|
4479
|
+
const out = world.slice();
|
|
4480
|
+
for (let at = node.parent; at; at = at.parent) {
|
|
4481
|
+
const p = at.position;
|
|
4482
|
+
if (!Array.isArray(p)) continue;
|
|
4483
|
+
for (let i = 0; i < out.length; i++) out[i] = (out[i] ?? 0) - (p[i] ?? 0);
|
|
4484
|
+
}
|
|
4485
|
+
return out;
|
|
4486
|
+
}
|
|
4391
4487
|
//#endregion
|
|
4392
4488
|
//#region src/gameplay/chase.ts
|
|
4393
4489
|
/**
|
|
@@ -4975,6 +5071,7 @@ var FloatAway = class extends Behavior {
|
|
|
4975
5071
|
onReady() {
|
|
4976
5072
|
const node = this.node;
|
|
4977
5073
|
this.start = [...node.position ?? []];
|
|
5074
|
+
if (node.opacity === void 0) diagnose(this.node.tree?.engine, "warn", `[incanto] FloatAway on '${this.node.getPath()}' will not fade — ${this.node.constructor.name} has no "opacity" prop, so it pops out at full brightness instead. Use a node that has one (Label, Label3D, Sprite2D, Sprite3D).`);
|
|
4978
5075
|
}
|
|
4979
5076
|
update(dt) {
|
|
4980
5077
|
if (this.done) return;
|
|
@@ -5024,9 +5121,18 @@ var FollowCamera = class extends Behavior {
|
|
|
5024
5121
|
/** Constant offset added to the target's position ([x,y] or [x,y,z]). */
|
|
5025
5122
|
offset: { default: [] },
|
|
5026
5123
|
/** 0..1 retention factor: 0 = snap, higher = smoother chase. */
|
|
5027
|
-
smoothing: {
|
|
5124
|
+
smoothing: {
|
|
5125
|
+
default: 0,
|
|
5126
|
+
range: {
|
|
5127
|
+
min: 0,
|
|
5128
|
+
max: 1
|
|
5129
|
+
}
|
|
5130
|
+
},
|
|
5028
5131
|
/** Don't move until the target is at least this far from the desired point. */
|
|
5029
|
-
deadzone: {
|
|
5132
|
+
deadzone: {
|
|
5133
|
+
default: 0,
|
|
5134
|
+
range: { min: 0 }
|
|
5135
|
+
}
|
|
5030
5136
|
};
|
|
5031
5137
|
static signals = [];
|
|
5032
5138
|
target = "";
|
|
@@ -5052,11 +5158,12 @@ var FollowCamera = class extends Behavior {
|
|
|
5052
5158
|
if (!hasPosition$1(cam)) return;
|
|
5053
5159
|
const target = cam.getNodeOrNull(this.target);
|
|
5054
5160
|
if (!target || !hasPosition$1(target)) return;
|
|
5055
|
-
const
|
|
5056
|
-
|
|
5161
|
+
const here = worldPosition(cam);
|
|
5162
|
+
const desired = add(worldPosition(target), this.offset);
|
|
5163
|
+
if (!(this.deadzone > 0 && distance$1(here, desired) <= this.deadzone)) {
|
|
5057
5164
|
const f = smoothingFactor(this.smoothing, dt);
|
|
5058
|
-
if (f >= 1) cam.position =
|
|
5059
|
-
else cam.position = cam.
|
|
5165
|
+
if (f >= 1) cam.position = localFromWorld(cam, desired);
|
|
5166
|
+
else cam.position = localFromWorld(cam, here.map((c, i) => c + ((desired[i] ?? c) - c) * f));
|
|
5060
5167
|
}
|
|
5061
5168
|
if (this.shakeT > 0) {
|
|
5062
5169
|
this.shakeT -= dt;
|
|
@@ -5109,7 +5216,6 @@ function tolerateUnknownAction(ctx, action, read, fallback) {
|
|
|
5109
5216
|
function restartScene(engine) {
|
|
5110
5217
|
const source = engine.scene?.source;
|
|
5111
5218
|
if (!source) return;
|
|
5112
|
-
engine.timeScale = 1;
|
|
5113
5219
|
engine.setScene(loadScene(jsonClone(source)));
|
|
5114
5220
|
}
|
|
5115
5221
|
/**
|
|
@@ -5119,7 +5225,6 @@ function restartScene(engine) {
|
|
|
5119
5225
|
function goToScene(engine, sceneJson, opts) {
|
|
5120
5226
|
const fade = opts?.fadeSeconds ?? .4;
|
|
5121
5227
|
const swap = () => {
|
|
5122
|
-
engine.timeScale = 1;
|
|
5123
5228
|
engine.setScene(loadScene(jsonClone(sceneJson)));
|
|
5124
5229
|
};
|
|
5125
5230
|
if (typeof document === "undefined" || fade <= 0) {
|
|
@@ -5500,13 +5605,14 @@ function screenFlash(engine, color = "#ffffff", opacity = .35, seconds = .25) {
|
|
|
5500
5605
|
*/
|
|
5501
5606
|
function hitStop(engine, seconds = .08) {
|
|
5502
5607
|
recordEffect(engine, "hitstop", "", "engine", seconds);
|
|
5503
|
-
const state =
|
|
5608
|
+
const state = liveHitStop(engine);
|
|
5504
5609
|
if (state) {
|
|
5505
5610
|
state.until = Math.max(state.until, engine.unscaledTime + seconds);
|
|
5506
5611
|
return;
|
|
5507
5612
|
}
|
|
5508
5613
|
const restore = engine.timeScale;
|
|
5509
5614
|
const entry = {
|
|
5615
|
+
startedAt: engine.unscaledTime,
|
|
5510
5616
|
until: engine.unscaledTime + seconds,
|
|
5511
5617
|
restore,
|
|
5512
5618
|
release: () => {}
|
|
@@ -5514,12 +5620,35 @@ function hitStop(engine, seconds = .08) {
|
|
|
5514
5620
|
hitStops.set(engine, entry);
|
|
5515
5621
|
engine.timeScale = 0;
|
|
5516
5622
|
entry.release = engine.updated.connect(() => {
|
|
5623
|
+
if (!liveHitStop(engine)) return;
|
|
5517
5624
|
if (engine.unscaledTime < entry.until) return;
|
|
5518
5625
|
engine.timeScale = entry.restore;
|
|
5519
5626
|
entry.release();
|
|
5520
5627
|
hitStops.delete(engine);
|
|
5521
5628
|
});
|
|
5522
5629
|
}
|
|
5630
|
+
/**
|
|
5631
|
+
* The engine's pending freeze, if the clock it was measured against still runs.
|
|
5632
|
+
*
|
|
5633
|
+
* `setScene` resets `unscaledTime` to 0, and a freeze deadline is an ABSOLUTE
|
|
5634
|
+
* reading of that clock — so a hit-stop taken on the killing blow, two minutes
|
|
5635
|
+
* into a level, survived the restart as a deadline two minutes in the future.
|
|
5636
|
+
* Measured: `hitStop(engine, 0.08)`, then the restart, then five real seconds
|
|
5637
|
+
* of ticks — 2.08 of them frozen, and a level that long freezes that long. The
|
|
5638
|
+
* quieter half is the next scene's OWN hit-stop: it found the stale entry,
|
|
5639
|
+
* extended a deadline nobody was waiting on, and never froze anything.
|
|
5640
|
+
*
|
|
5641
|
+
* A clock that reads earlier than the freeze began cannot be the clock the
|
|
5642
|
+
* freeze was scheduled on. `setScene` already put `timeScale` back to 1, so
|
|
5643
|
+
* there is nothing to restore — just let go.
|
|
5644
|
+
*/
|
|
5645
|
+
function liveHitStop(engine) {
|
|
5646
|
+
const entry = hitStops.get(engine);
|
|
5647
|
+
if (!entry) return void 0;
|
|
5648
|
+
if (engine.unscaledTime >= entry.startedAt) return entry;
|
|
5649
|
+
entry.release();
|
|
5650
|
+
hitStops.delete(engine);
|
|
5651
|
+
}
|
|
5523
5652
|
const hitStops = /* @__PURE__ */ new Map();
|
|
5524
5653
|
//#endregion
|
|
5525
5654
|
//#region src/gameplay/lifetime.ts
|
|
@@ -5605,7 +5734,10 @@ function ease(curve, t) {
|
|
|
5605
5734
|
var MoveTo = class extends Behavior {
|
|
5606
5735
|
static props = {
|
|
5607
5736
|
/** Destination position ([x,y] or [x,y,z]). */
|
|
5608
|
-
to: {
|
|
5737
|
+
to: {
|
|
5738
|
+
default: [],
|
|
5739
|
+
required: true
|
|
5740
|
+
},
|
|
5609
5741
|
/** Seconds the move takes. */
|
|
5610
5742
|
duration: { default: 1 },
|
|
5611
5743
|
/** Easing curve. */
|
|
@@ -5819,7 +5951,10 @@ function distanceBetween(a, b) {
|
|
|
5819
5951
|
var Patrol = class extends Behavior {
|
|
5820
5952
|
static props = {
|
|
5821
5953
|
/** Waypoints: array of position arrays OR node-path strings to read. */
|
|
5822
|
-
points: {
|
|
5954
|
+
points: {
|
|
5955
|
+
default: [],
|
|
5956
|
+
required: true
|
|
5957
|
+
},
|
|
5823
5958
|
/** Units per second along the path. */
|
|
5824
5959
|
speed: { default: 60 },
|
|
5825
5960
|
/** Wrap to the first point after the last (ignored in pingpong). */
|
|
@@ -6031,12 +6166,12 @@ var Projectile = class extends Behavior {
|
|
|
6031
6166
|
return [Math.cos(rad), Math.sin(rad)];
|
|
6032
6167
|
}
|
|
6033
6168
|
if (Array.isArray(rot)) {
|
|
6034
|
-
const
|
|
6035
|
-
const
|
|
6169
|
+
const ry = (rot[1] ?? 0) * Math.PI / 180;
|
|
6170
|
+
const rx = (rot[0] ?? 0) * Math.PI / 180;
|
|
6036
6171
|
return normalize([
|
|
6037
|
-
|
|
6038
|
-
Math.sin(
|
|
6039
|
-
|
|
6172
|
+
Math.sin(ry),
|
|
6173
|
+
-Math.sin(rx) * Math.cos(ry),
|
|
6174
|
+
Math.cos(rx) * Math.cos(ry)
|
|
6040
6175
|
]);
|
|
6041
6176
|
}
|
|
6042
6177
|
return [1, 0];
|
|
@@ -6322,13 +6457,27 @@ var SpawnSource = class {
|
|
|
6322
6457
|
* spawner's node), and return the clone.
|
|
6323
6458
|
*
|
|
6324
6459
|
* Placement: with no `at`, the clone keeps the template's authored position;
|
|
6325
|
-
* with `at`, it
|
|
6326
|
-
*
|
|
6460
|
+
* with `at`, it ends up at the spawner's position plus `at`.
|
|
6461
|
+
*
|
|
6462
|
+
* `at` is written as the clone's LOCAL position, because the clone is added
|
|
6463
|
+
* as a CHILD of the spawner's node and that parent's transform already
|
|
6464
|
+
* contributes the spawner's own position. This used to add the two, so the
|
|
6465
|
+
* spawner's position was applied twice and the further from the origin you
|
|
6466
|
+
* put the nest, the further away its enemies appeared. Measured on a spawner
|
|
6467
|
+
* at [820, 240] with `"at": [0, -50]`:
|
|
6468
|
+
*
|
|
6469
|
+
* ```
|
|
6470
|
+
* expected world = [820, 190]
|
|
6471
|
+
* clone WORLD position = [1640, 430] error = [820, 240]
|
|
6472
|
+
* ```
|
|
6473
|
+
*
|
|
6474
|
+
* The scene loads, the spawner spawns, the clone is alive and visible — it is
|
|
6475
|
+
* just somewhere else in the level, and nothing has anything to report.
|
|
6327
6476
|
*/
|
|
6328
6477
|
spawn(template, opts) {
|
|
6329
6478
|
const clone = duplicateNode(template);
|
|
6330
6479
|
const at = opts?.at;
|
|
6331
|
-
if (at && at.length > 0 && hasPosition$1(clone)) clone.position = add(hasPosition$1(this.behavior.node) ? this.behavior.node.position
|
|
6480
|
+
if (at && at.length > 0 && hasPosition$1(clone)) clone.position = add((opts?.parent ?? this.behavior.node) === this.behavior.node || !hasPosition$1(this.behavior.node) ? [] : this.behavior.node.position, at);
|
|
6332
6481
|
if (typeof clone.visible === "boolean") clone.visible = true;
|
|
6333
6482
|
(opts?.parent ?? this.behavior.node).addChild(clone);
|
|
6334
6483
|
return clone;
|
|
@@ -6355,7 +6504,8 @@ var Spawner = class extends Behavior {
|
|
|
6355
6504
|
/** Node path of the template to clone. */
|
|
6356
6505
|
prefab: {
|
|
6357
6506
|
default: "",
|
|
6358
|
-
nodePath: true
|
|
6507
|
+
nodePath: true,
|
|
6508
|
+
required: true
|
|
6359
6509
|
},
|
|
6360
6510
|
/** Seconds between spawns. */
|
|
6361
6511
|
interval: { default: 1 },
|
|
@@ -6508,7 +6658,10 @@ var Wander = class extends Behavior {
|
|
|
6508
6658
|
var WaveSpawner = class extends Behavior {
|
|
6509
6659
|
static props = {
|
|
6510
6660
|
/** Array of { prefab, count, interval, delayBefore }. */
|
|
6511
|
-
waves: {
|
|
6661
|
+
waves: {
|
|
6662
|
+
default: [],
|
|
6663
|
+
required: true
|
|
6664
|
+
},
|
|
6512
6665
|
/** Begin the first wave's countdown at ready. */
|
|
6513
6666
|
autoStart: { default: true }
|
|
6514
6667
|
};
|
|
@@ -6825,4 +6978,4 @@ function registerGameplayBehaviors(opts) {
|
|
|
6825
6978
|
for (const [name, ctor] of Object.entries(GAMEPLAY_BEHAVIORS)) registerBehavior(name, ctor, { replace });
|
|
6826
6979
|
}
|
|
6827
6980
|
//#endregion
|
|
6828
|
-
export { Health as A,
|
|
6981
|
+
export { Health as A, CharacterBody3D as B, restartScene as C, DayNight as D, FloatAway as E, Water3D as F, validateCollider3D as G, RigidBody3D as H, WATER_CUTOUT_MAX as I, colliderFootDrop as J, createCausticsQuad as K, WaterCutout3D as L, Chase as M, localFromWorld as N, phaseOf as O, worldPosition as P, rejectScale as R, goToScene as S, FollowCamera as T, StaticBody3D as U, PhysicsBody3D as V, Node3D 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, WATER_MAX_RIPPLES as q, 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, Area3D as z };
|
package/dist/gameplay.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as Engine, d as PropSchema, jt as Node, n as BehaviorCtor, t as Behavior } from "./behavior-DsgayMsH.js";
|
|
2
2
|
import { c as JsonValue, s as JsonObject } from "./schema-CFeioQRE.js";
|
|
3
3
|
|
|
4
4
|
//#region src/gameplay/chase.d.ts
|
package/dist/gameplay.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-CaHqDiQD.js";
|
|
2
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 };
|