incanto 0.72.0 → 0.74.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 +114 -42
- package/bin/incanto-verify.mjs +9 -2
- package/dist/2d.d.ts +29 -4
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +137 -15
- package/dist/3d.js +6 -6
- package/dist/{agent8-BqZ0_O1u.js → agent8-CHTT4unP.js} +1 -1
- package/dist/{audio-player-ioZ7VKC6.d.ts → audio-player-BOrk4eQx.d.ts} +1 -1
- package/dist/{behavior-Bf9P9oB2.d.ts → behavior-J1cmVah0.d.ts} +8 -0
- package/dist/{create-game-CmFAtLZp.js → create-game-BAiA-FjP.js} +7 -7
- package/dist/{create-game-C9rWqqAC.js → create-game-ssvGvP7W.js} +7 -7
- package/dist/debug.d.ts +1 -1
- package/dist/debug.js +1 -1
- package/dist/editor.js +965 -893
- package/dist/{environment-presets-BeHoaGhy.js → environment-presets-BkqlWewf.js} +277 -60
- package/dist/{gameplay-BlQe-M07.js → gameplay-Bxe1sMVT.js} +611 -39
- package/dist/gameplay.d.ts +141 -7
- package/dist/gameplay.js +2 -2
- package/dist/index.d.ts +6 -4
- package/dist/index.js +6 -6
- package/dist/{loader-CBfQzB6S.d.ts → loader-BAeWMYfF.d.ts} +1 -1
- package/dist/net.d.ts +2 -2
- package/dist/net.js +2 -2
- package/dist/{physics-2d-DrIgTlLk.js → physics-2d-C-SfvjzH.js} +94 -11
- package/dist/{physics-3d-BzOCw1VS.js → physics-3d-rOzeg890.js} +202 -15
- package/dist/{picking-C9McVJrO.js → picking-BMV34Pjl.js} +2 -2
- package/dist/react.d.ts +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-5IYfooAN.js → register-CjociOtt.js} +19 -4
- package/dist/{register-C8HuRkOf.js → register-DRQyZKGU.js} +45 -9
- package/dist/{replay-datiAE-b.js → replay-B6BbgGM_.js} +42 -6
- package/dist/{replay-CBEChqXq.d.ts → replay-wZK5Ok5c.d.ts} +1 -1
- package/dist/{save-slots-CEuJPUle.js → save-slots-CEUGeLuB.js} +11 -2
- package/dist/{split-screen-Bm5DTElG.js → split-screen-BxZ5rBe7.js} +4 -4
- package/dist/{split-screen-DkqLng6q.d.ts → split-screen-D6sx8z3Z.d.ts} +2 -2
- package/dist/{sprite-animation-CqR2o3SA.js → sprite-animation-Bz3DHD_4.js} +1 -1
- package/dist/{src-DRSsRleD.js → src-CqtvYtSN.js} +1 -1
- package/dist/{test-Djuq3Vhq.js → test-CEl0y2Sw.js} +162 -30
- package/dist/test.d.ts +56 -5
- package/dist/test.js +2 -2
- package/dist/{touch-BnCyPA0G.js → touch-CioTZB-y.js} +1 -1
- package/dist/vite.js +3 -3
- package/editor/assets/{agent8-CMKz2cax.js → agent8-BlzturGi.js} +1 -1
- package/editor/assets/{debug-DLrQm-az.js → debug-BMUi8usj.js} +1 -1
- package/editor/assets/{index-BEKuxYcE.js → index-CrUCQoaB.js} +53 -53
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +634 -10
- package/skills/incanto-3d-character.md +113 -5
- package/skills/incanto-assets.md +9 -3
- package/skills/incanto-behaviors-and-scripts.md +26 -2
- package/skills/incanto-building-2d-games.md +9 -0
- package/skills/incanto-building-3d-games.md +45 -0
- package/skills/incanto-editor.md +6 -1
- package/skills/incanto-environment.md +7 -2
- package/skills/incanto-game-feel.md +16 -11
- package/skills/incanto-gameplay-behaviors.md +179 -16
- package/skills/incanto-node-reference.md +124 -45
- package/skills/incanto-physics-and-input.md +67 -5
- package/skills/incanto-scene-json-authoring.md +9 -3
- package/skills/incanto-verifying-your-game.md +19 -2
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +8 -0
- package/templates-app/beacon-isle-3d/PROJECT/Structure.md +3 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/game.scene.json +136 -0
- package/templates-app/beacon-isle-3d/verify.ts +144 -0
- package/templates-app/molehill-2d/package.json +1 -1
- package/templates-app/platformer-2d/PROJECT/Status.md +7 -0
- package/templates-app/platformer-2d/PROJECT/Structure.md +3 -0
- package/templates-app/platformer-2d/package.json +1 -1
- package/templates-app/platformer-2d/src/game.scene.json +126 -0
- package/templates-app/platformer-2d/verify.ts +54 -0
- package/templates-app/star-survivor/package.json +1 -1
- package/templates-app/tps-3d/PROJECT/Context.md +1 -1
- package/templates-app/tps-3d/PROJECT/Status.md +40 -1
- package/templates-app/tps-3d/PROJECT/Structure.md +19 -0
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/tps-3d/src/behaviors.ts +9 -0
- package/templates-app/tps-3d/src/cover.scene.json +26 -0
- package/templates-app/tps-3d/src/game.scene.json +331 -75
- package/templates-app/tps-3d/src/main.ts +14 -0
- package/templates-app/tps-3d/src/pillar.scene.json +25 -0
- package/templates-app/tps-3d/verify.ts +582 -3
- package/templates-app/village-quest-3d/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Y as diagnose } from "./save-slots-
|
|
2
|
-
import { M as translateOn, t as registerCoreNodes } from "./register-
|
|
1
|
+
import { Y as diagnose } from "./save-slots-CEUGeLuB.js";
|
|
2
|
+
import { M as translateOn, t as registerCoreNodes } from "./register-CjociOtt.js";
|
|
3
3
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
4
4
|
import { t as Rng } from "./rng-CDOMybym.js";
|
|
5
|
-
import { c as getNodeSchema, h as didYouMean, p as registerNode } from "./touch-
|
|
5
|
+
import { c as getNodeSchema, h as didYouMean, p as registerNode } from "./touch-CioTZB-y.js";
|
|
6
6
|
import { t as createNoise2D } from "./noise-D3nPpmFg.js";
|
|
7
|
-
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimations, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-
|
|
8
|
-
import {
|
|
7
|
+
import { i as ParticleSim, n as resolveFrames, o as PARTICLE_PRESET_NAMES, r as validateAnimations, s as applyParticlePreset, t as resolveAnimation } from "./sprite-animation-Bz3DHD_4.js";
|
|
8
|
+
import { E as tolerateUnknownAction, G as PhysicsBody3D, H as rejectScale, J as Node3D, K as RigidBody3D, O as effectRng, Q as colliderFootDrop, U as Area3D, V as WaterCutout3D, W as CharacterBody3D, et as worldPosition, q as StaticBody3D, z as Water3D } from "./gameplay-Bxe1sMVT.js";
|
|
9
9
|
import { t as checkSheetGrid } from "./sheet-grid-Cea343VO.js";
|
|
10
10
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-BYgD5Edk.js";
|
|
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";
|
|
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, MathUtils, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, SpotLight, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
12
12
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
13
13
|
//#region src/3d/textures.ts
|
|
14
14
|
/**
|
|
@@ -641,7 +641,10 @@ var InstancedMesh3D = class extends Node3D {
|
|
|
641
641
|
transforms: { default: [] },
|
|
642
642
|
castShadow: { default: false },
|
|
643
643
|
receiveShadow: { default: false },
|
|
644
|
-
collider: {
|
|
644
|
+
collider: {
|
|
645
|
+
default: null,
|
|
646
|
+
kinds: ["null", "object"]
|
|
647
|
+
}
|
|
645
648
|
};
|
|
646
649
|
mesh = "box";
|
|
647
650
|
size = [
|
|
@@ -783,7 +786,10 @@ var Joint3D = class extends Node3D {
|
|
|
783
786
|
length: { default: 0 },
|
|
784
787
|
stiffness: { default: 50 },
|
|
785
788
|
damping: { default: 5 },
|
|
786
|
-
collide: {
|
|
789
|
+
collide: {
|
|
790
|
+
default: null,
|
|
791
|
+
kinds: ["null", "boolean"]
|
|
792
|
+
}
|
|
787
793
|
};
|
|
788
794
|
type = "spherical";
|
|
789
795
|
target = "";
|
|
@@ -1583,12 +1589,18 @@ var Terrain3D = class extends Node3D {
|
|
|
1583
1589
|
default: .95,
|
|
1584
1590
|
range: { min: 0 }
|
|
1585
1591
|
},
|
|
1586
|
-
islandEdge: {
|
|
1592
|
+
islandEdge: {
|
|
1593
|
+
default: null,
|
|
1594
|
+
kinds: ["null", "boolean"]
|
|
1595
|
+
},
|
|
1587
1596
|
layers: { default: [] },
|
|
1588
1597
|
textureBase: { default: DEFAULT_TERRAIN_TEXTURE_BASE },
|
|
1589
1598
|
basins: { default: [] },
|
|
1590
1599
|
channels: { default: [] },
|
|
1591
|
-
wetline: {
|
|
1600
|
+
wetline: {
|
|
1601
|
+
default: null,
|
|
1602
|
+
kinds: ["null", "object"]
|
|
1603
|
+
}
|
|
1592
1604
|
};
|
|
1593
1605
|
/** [width, depth] extent in meters, centered on the node. */
|
|
1594
1606
|
size = [200, 200];
|
|
@@ -2666,7 +2678,7 @@ const correctionScratch = new Quaternion();
|
|
|
2666
2678
|
const parentScratch = new Quaternion();
|
|
2667
2679
|
const quatScratch$1 = new Quaternion();
|
|
2668
2680
|
//#endregion
|
|
2669
|
-
//#region src/3d/nodes/
|
|
2681
|
+
//#region src/3d/nodes/look-at.ts
|
|
2670
2682
|
const RAD2DEG$1 = 180 / Math.PI;
|
|
2671
2683
|
/** World up. The whole fix is that this argument exists. */
|
|
2672
2684
|
const UP = new Vector3(0, 1, 0);
|
|
@@ -2675,6 +2687,50 @@ const targetScratch = new Vector3();
|
|
|
2675
2687
|
const lookScratch = new Matrix4();
|
|
2676
2688
|
const eulerScratch$1 = new Euler(0, 0, 0, "XYZ");
|
|
2677
2689
|
/**
|
|
2690
|
+
* Aim a node's `rotation` at whatever its `lookAt` path names — the camera's
|
|
2691
|
+
* rule, shared with the spot light so that "point the searchlight at the
|
|
2692
|
+
* player" is one prop and not Euler arithmetic.
|
|
2693
|
+
*
|
|
2694
|
+
* Runs in `update` and not `_syncObject3D`: the second is the renderer's copy
|
|
2695
|
+
* pass and a static node is pruned from it, which silently freezes anything
|
|
2696
|
+
* driven there. `rotation` is written as an ordinary prop, so the editor, the
|
|
2697
|
+
* serializer and `describeFraming` all see what the node is actually doing.
|
|
2698
|
+
*
|
|
2699
|
+
* A path that resolves to nothing is an AUDIT finding, not a throw: every
|
|
2700
|
+
* other `nodePath` prop in the engine is reported by `auditScene` /
|
|
2701
|
+
* `incanto-check`, and throwing here would QUARANTINE the node. A target with
|
|
2702
|
+
* no world position (a light, a HudLayer, a plain `Node`) is warned about
|
|
2703
|
+
* once per path and the node keeps its authored rotation. Returns the path
|
|
2704
|
+
* that has been warned about, for the caller to remember.
|
|
2705
|
+
*/
|
|
2706
|
+
function aimAt(node, warned, what) {
|
|
2707
|
+
if (node.lookAt === "") return warned;
|
|
2708
|
+
const target = node.getNodeOrNull(node.lookAt);
|
|
2709
|
+
if (!target) return warned;
|
|
2710
|
+
const to = worldPosition(target);
|
|
2711
|
+
if (to.length < 3) {
|
|
2712
|
+
if (warned !== node.lookAt) {
|
|
2713
|
+
diagnose(node.tree?.engine ?? null, "warn", `[incanto] ${node.getPath()}: lookAt '${node.lookAt}' resolves to a ${target.constructor.typeName ?? "Node"}, which has no world position — the ${what} keeps its authored rotation. Point it at a Node3D.`);
|
|
2714
|
+
return node.lookAt;
|
|
2715
|
+
}
|
|
2716
|
+
return warned;
|
|
2717
|
+
}
|
|
2718
|
+
const from = worldPosition(node);
|
|
2719
|
+
eyeScratch.set(from[0] ?? 0, from[1] ?? 0, from[2] ?? 0);
|
|
2720
|
+
targetScratch.set(to[0] ?? 0, to[1] ?? 0, to[2] ?? 0);
|
|
2721
|
+
if (eyeScratch.distanceToSquared(targetScratch) < 1e-12) return warned;
|
|
2722
|
+
lookScratch.lookAt(eyeScratch, targetScratch, UP);
|
|
2723
|
+
eulerScratch$1.setFromRotationMatrix(lookScratch, "XYZ");
|
|
2724
|
+
node.rotation = [
|
|
2725
|
+
eulerScratch$1.x * RAD2DEG$1,
|
|
2726
|
+
eulerScratch$1.y * RAD2DEG$1,
|
|
2727
|
+
eulerScratch$1.z * RAD2DEG$1
|
|
2728
|
+
];
|
|
2729
|
+
return warned;
|
|
2730
|
+
}
|
|
2731
|
+
//#endregion
|
|
2732
|
+
//#region src/3d/nodes/camera-3d.ts
|
|
2733
|
+
/**
|
|
2678
2734
|
* A perspective camera. Mark exactly one camera `current: true`; with none
|
|
2679
2735
|
* marked, the renderer falls back to the first camera in tree order.
|
|
2680
2736
|
* Aspect ratio is managed by the renderer on resize.
|
|
@@ -2722,38 +2778,13 @@ var Camera3D = class extends Node3D {
|
|
|
2722
2778
|
current = false;
|
|
2723
2779
|
lookAt = "";
|
|
2724
2780
|
/**
|
|
2725
|
-
* Aim, every frame, whenever `lookAt` names something
|
|
2726
|
-
*
|
|
2727
|
-
* In `update` and not `_syncObject3D`: the second is the renderer's copy pass
|
|
2728
|
-
* and a static node is pruned from it, which silently freezes anything driven
|
|
2729
|
-
* there. `rotation` is written as an ordinary prop, so the editor, the
|
|
2730
|
-
* serializer and `describeFraming` all see what the camera is actually doing.
|
|
2781
|
+
* Aim, every frame, whenever `lookAt` names something — see `aimAt`, which
|
|
2782
|
+
* the spot light shares.
|
|
2731
2783
|
*/
|
|
2732
2784
|
/** The `lookAt` path already reported as unlookable — cleared by a new one. */
|
|
2733
2785
|
warnedLookAt = "";
|
|
2734
2786
|
update(_dt) {
|
|
2735
|
-
|
|
2736
|
-
const target = this.getNodeOrNull(this.lookAt);
|
|
2737
|
-
if (!target) return;
|
|
2738
|
-
const to = worldPosition(target);
|
|
2739
|
-
if (to.length < 3) {
|
|
2740
|
-
if (this.warnedLookAt !== this.lookAt) {
|
|
2741
|
-
this.warnedLookAt = this.lookAt;
|
|
2742
|
-
diagnose(this.tree?.engine ?? null, "warn", `[incanto] ${this.getPath()}: lookAt '${this.lookAt}' resolves to a ${target.constructor.typeName ?? "Node"}, which has no world position — the camera keeps its authored rotation. Point it at a Node3D.`);
|
|
2743
|
-
}
|
|
2744
|
-
return;
|
|
2745
|
-
}
|
|
2746
|
-
const from = worldPosition(this);
|
|
2747
|
-
eyeScratch.set(from[0] ?? 0, from[1] ?? 0, from[2] ?? 0);
|
|
2748
|
-
targetScratch.set(to[0] ?? 0, to[1] ?? 0, to[2] ?? 0);
|
|
2749
|
-
if (eyeScratch.distanceToSquared(targetScratch) < 1e-12) return;
|
|
2750
|
-
lookScratch.lookAt(eyeScratch, targetScratch, UP);
|
|
2751
|
-
eulerScratch$1.setFromRotationMatrix(lookScratch, "XYZ");
|
|
2752
|
-
this.rotation = [
|
|
2753
|
-
eulerScratch$1.x * RAD2DEG$1,
|
|
2754
|
-
eulerScratch$1.y * RAD2DEG$1,
|
|
2755
|
-
eulerScratch$1.z * RAD2DEG$1
|
|
2756
|
-
];
|
|
2787
|
+
this.warnedLookAt = aimAt(this, this.warnedLookAt, "camera");
|
|
2757
2788
|
}
|
|
2758
2789
|
_createObject3D() {
|
|
2759
2790
|
return new PerspectiveCamera(this.fov, 1, this.near, this.far);
|
|
@@ -2782,6 +2813,8 @@ const MOVEMENT_STATES = [
|
|
|
2782
2813
|
"fastRun",
|
|
2783
2814
|
"airborne"
|
|
2784
2815
|
];
|
|
2816
|
+
/** Air control stands down this long after a wall kick, so the kick lands. */
|
|
2817
|
+
const WALL_LOCKOUT_SECONDS = .18;
|
|
2785
2818
|
const ACC_DELTA_TIME = 8;
|
|
2786
2819
|
const DRAG_DAMPING = .15;
|
|
2787
2820
|
const SPRING_K = 1.2;
|
|
@@ -2820,7 +2853,7 @@ const UP_VEC = new Vector3(0, 1, 0);
|
|
|
2820
2853
|
*/
|
|
2821
2854
|
var CharacterController3D = class extends Node3D {
|
|
2822
2855
|
static typeName = "CharacterController3D";
|
|
2823
|
-
static signals = ["movementStateChanged"];
|
|
2856
|
+
static signals = ["movementStateChanged", "wallJumped"];
|
|
2824
2857
|
static props = {
|
|
2825
2858
|
view: {
|
|
2826
2859
|
default: "free",
|
|
@@ -2847,6 +2880,11 @@ var CharacterController3D = class extends Node3D {
|
|
|
2847
2880
|
maxJumps: { default: 1 },
|
|
2848
2881
|
/** How much of your ground control you keep in the air (0 = none, 1 = full). */
|
|
2849
2882
|
airControl: { default: .2 },
|
|
2883
|
+
wallJumpImpulse: { default: [0, 0] },
|
|
2884
|
+
wallSlideSpeed: {
|
|
2885
|
+
default: 0,
|
|
2886
|
+
range: { min: 0 }
|
|
2887
|
+
},
|
|
2850
2888
|
/** Gravity multiplier while falling — >1 is the "snappy" arc. */
|
|
2851
2889
|
fallGravity: { default: 2.5 },
|
|
2852
2890
|
floatHeight: { default: .01 },
|
|
@@ -2888,6 +2926,17 @@ var CharacterController3D = class extends Node3D {
|
|
|
2888
2926
|
jumpCutMultiplier = 1;
|
|
2889
2927
|
maxJumps = 1;
|
|
2890
2928
|
airControl = .2;
|
|
2929
|
+
/**
|
|
2930
|
+
* `[away, up]` m/s: airborne and pressing into a wall, `jump` kicks off it —
|
|
2931
|
+
* away along the wall's normal, up. `[0, 0]` (default) = no wall-jumps.
|
|
2932
|
+
* The controller owns this because a kick written from outside lasted three
|
|
2933
|
+
* frames: the jump cut halved its rise on release and air control steered
|
|
2934
|
+
* the horizontal straight back into the wall. After a kick, air control
|
|
2935
|
+
* stands down for `WALL_LOCKOUT` so the kick lands.
|
|
2936
|
+
*/
|
|
2937
|
+
wallJumpImpulse = [0, 0];
|
|
2938
|
+
/** Max fall speed (m/s) while pressing into a wall; 0 = no wall slide. */
|
|
2939
|
+
wallSlideSpeed = 0;
|
|
2891
2940
|
fallGravity = 2.5;
|
|
2892
2941
|
floatHeight = .01;
|
|
2893
2942
|
/**
|
|
@@ -3008,6 +3057,10 @@ var CharacterController3D = class extends Node3D {
|
|
|
3008
3057
|
rising = false;
|
|
3009
3058
|
/** Between the jump impulse and the landing — the animation's clock. */
|
|
3010
3059
|
jumping = false;
|
|
3060
|
+
/** Seconds of air control still suppressed after a wall kick. */
|
|
3061
|
+
wallLockout = 0;
|
|
3062
|
+
/** The outward normal of the wall being pressed into this step, if any. */
|
|
3063
|
+
wallNormal = null;
|
|
3011
3064
|
get body() {
|
|
3012
3065
|
const parent = this.parent;
|
|
3013
3066
|
if (!(parent instanceof RigidBody3D)) throw new IncantoError("TREE_VIOLATION", `CharacterController3D '${this.name}' must be a child of a RigidBody3D (parent is '${parent?.name ?? "none"}').`);
|
|
@@ -3090,7 +3143,29 @@ var CharacterController3D = class extends Node3D {
|
|
|
3090
3143
|
const intensity = keyboardIntensity(moving, sprinting);
|
|
3091
3144
|
const speedMultiplier = 1 + (this.sprintMultiplier - 1) * intensity;
|
|
3092
3145
|
const targetSpeed = moving ? this.maxSpeed * speedMultiplier : 0;
|
|
3093
|
-
|
|
3146
|
+
this.wallNormal = null;
|
|
3147
|
+
if ((this.wallSlideSpeed > 0 || this.wallJumpImpulse.some((v) => v !== 0)) && !this.grounded && moving) {
|
|
3148
|
+
const r = body.collider.radius ?? .32;
|
|
3149
|
+
const n = (this.tree?.engine?.physics?.castRay([
|
|
3150
|
+
pos[0] ?? 0,
|
|
3151
|
+
pos[1] ?? 0,
|
|
3152
|
+
pos[2] ?? 0
|
|
3153
|
+
], [
|
|
3154
|
+
mx,
|
|
3155
|
+
0,
|
|
3156
|
+
mz
|
|
3157
|
+
], r + .25, body, { staticOnly: true }))?.normal;
|
|
3158
|
+
if (n && Math.hypot(n[0] ?? 0, n[2] ?? 0) > .5) {
|
|
3159
|
+
const len = Math.hypot(n[0] ?? 0, n[2] ?? 0);
|
|
3160
|
+
this.wallNormal = [
|
|
3161
|
+
(n[0] ?? 0) / len,
|
|
3162
|
+
0,
|
|
3163
|
+
(n[2] ?? 0) / len
|
|
3164
|
+
];
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
this.wallLockout = Math.max(0, this.wallLockout - dt);
|
|
3168
|
+
const control = this.wallLockout > 0 ? 0 : this.grounded ? 1 : this.airControl;
|
|
3094
3169
|
const ax = (mx * targetSpeed + carry[0] - vel[0]) / ACC_DELTA_TIME * control;
|
|
3095
3170
|
const az = (mz * targetSpeed + carry[1] - vel[2]) / ACC_DELTA_TIME * control;
|
|
3096
3171
|
body.applyImpulse([
|
|
@@ -3121,7 +3196,7 @@ var CharacterController3D = class extends Node3D {
|
|
|
3121
3196
|
if (rise > .02 && rise <= this.stepHeight + .02) springToi = toi - rise;
|
|
3122
3197
|
}
|
|
3123
3198
|
}
|
|
3124
|
-
if (springToi !== null && springToi < floatingDis * 2 && !this.jumping) {
|
|
3199
|
+
if (springToi !== null && springToi < floatingDis * 2 && !this.jumping && (vel[1] ?? 0) < 2) {
|
|
3125
3200
|
const spring = SPRING_K * (floatingDis - springToi) - vel[1] * SPRING_DAMPING;
|
|
3126
3201
|
body.applyImpulse([
|
|
3127
3202
|
0,
|
|
@@ -3141,7 +3216,27 @@ var CharacterController3D = class extends Node3D {
|
|
|
3141
3216
|
const pressedJump = this.readAction("jumpAction", () => input.justPressed(this.jumpAction), false, "The character will never jump.");
|
|
3142
3217
|
if (pressedJump) this.bufferLeft = Math.max(this.jumpBufferSeconds, 0);
|
|
3143
3218
|
else this.bufferLeft = Math.max(0, this.bufferLeft - dt);
|
|
3144
|
-
|
|
3219
|
+
const wantsJump = this.bufferLeft > 0 || pressedJump;
|
|
3220
|
+
const wall = this.wallNormal;
|
|
3221
|
+
if (wantsJump && !this.grounded && wall && this.wallJumpImpulse.some((v) => v !== 0)) {
|
|
3222
|
+
const away = this.wallJumpImpulse[0] ?? 0;
|
|
3223
|
+
const up = this.wallJumpImpulse[1] ?? 0;
|
|
3224
|
+
body.linearVelocity = [
|
|
3225
|
+
wall[0] * away,
|
|
3226
|
+
up,
|
|
3227
|
+
wall[2] * away
|
|
3228
|
+
];
|
|
3229
|
+
vel[0] = wall[0] * away;
|
|
3230
|
+
vel[1] = up;
|
|
3231
|
+
vel[2] = wall[2] * away;
|
|
3232
|
+
this.grounded = false;
|
|
3233
|
+
this.bufferLeft = 0;
|
|
3234
|
+
this.coyoteLeft = 0;
|
|
3235
|
+
this.rising = false;
|
|
3236
|
+
this.jumping = true;
|
|
3237
|
+
this.wallLockout = WALL_LOCKOUT_SECONDS;
|
|
3238
|
+
this.emit("wallJumped", wall);
|
|
3239
|
+
} else if (wantsJump && (footed || this.coyoteLeft > 0 || this.jumpsUsed < this.maxJumps)) {
|
|
3145
3240
|
const jumpVel = this.jumpVelocity * (1 + (this.sprintJumpMultiplier - 1) * intensity);
|
|
3146
3241
|
body.linearVelocity = [
|
|
3147
3242
|
vel[0],
|
|
@@ -3169,8 +3264,17 @@ var CharacterController3D = class extends Node3D {
|
|
|
3169
3264
|
this.rising = false;
|
|
3170
3265
|
}
|
|
3171
3266
|
}
|
|
3267
|
+
const sliding = this.wallSlideSpeed > 0 && !footed && this.wallNormal !== null && (vel[1] ?? 0) < 0;
|
|
3268
|
+
if (sliding && (vel[1] ?? 0) < -this.wallSlideSpeed) {
|
|
3269
|
+
body.linearVelocity = [
|
|
3270
|
+
vel[0],
|
|
3271
|
+
-this.wallSlideSpeed,
|
|
3272
|
+
vel[2]
|
|
3273
|
+
];
|
|
3274
|
+
vel[1] = -this.wallSlideSpeed;
|
|
3275
|
+
}
|
|
3172
3276
|
if ((vel[1] ?? 0) < FALLING_MAX_VEL) body.gravityScale = 0;
|
|
3173
|
-
else if ((vel[1] ?? 0) < 0 && !footed) body.gravityScale = this.fallGravity;
|
|
3277
|
+
else if ((vel[1] ?? 0) < 0 && !footed) body.gravityScale = sliding ? 1 : this.fallGravity;
|
|
3174
3278
|
else body.gravityScale = 1;
|
|
3175
3279
|
if (this.view === "side" && Math.abs(pos[2]) > .01) body.position = [
|
|
3176
3280
|
body.position[0] ?? 0,
|
|
@@ -3973,7 +4077,10 @@ var Flowers3D = class extends Node3D {
|
|
|
3973
4077
|
height: { default: .45 },
|
|
3974
4078
|
clustering: { default: .6 },
|
|
3975
4079
|
sway: { default: .5 },
|
|
3976
|
-
drape: {
|
|
4080
|
+
drape: {
|
|
4081
|
+
default: null,
|
|
4082
|
+
kinds: ["null", "boolean"]
|
|
4083
|
+
},
|
|
3977
4084
|
avoidWater: { default: true },
|
|
3978
4085
|
terrain: {
|
|
3979
4086
|
default: "",
|
|
@@ -5387,7 +5494,10 @@ var Foliage3D = class Foliage3D extends Node3D {
|
|
|
5387
5494
|
},
|
|
5388
5495
|
flowers: { default: 0 },
|
|
5389
5496
|
seed: { default: 1 },
|
|
5390
|
-
drape: {
|
|
5497
|
+
drape: {
|
|
5498
|
+
default: null,
|
|
5499
|
+
kinds: ["null", "boolean"]
|
|
5500
|
+
},
|
|
5391
5501
|
avoidWater: { default: true },
|
|
5392
5502
|
terrain: {
|
|
5393
5503
|
default: "",
|
|
@@ -6308,6 +6418,98 @@ var OmniLight3D = class extends Node3D {
|
|
|
6308
6418
|
light.distance = this.range;
|
|
6309
6419
|
}
|
|
6310
6420
|
};
|
|
6421
|
+
/**
|
|
6422
|
+
* A cone of light — a flashlight, a searchlight, a car's headlights, a stage
|
|
6423
|
+
* spot, a guard's torch.
|
|
6424
|
+
*
|
|
6425
|
+
* It AIMS down the node's local −Z, exactly like a camera: at rest it points
|
|
6426
|
+
* along −Z, `rotation: [-90, 0, 0]` points it at the floor, and a headlamp
|
|
6427
|
+
* mounted on a +Z-forward skin wants `rotation: [0, 180, 0]`. `coneDeg` is the
|
|
6428
|
+
* FULL angle of the cone (a "30° beam" is 30), converted to three's half-angle
|
|
6429
|
+
* here so nobody has to halve it by hand. `intensity` is in the same physical
|
|
6430
|
+
* units as `OmniLight3D` — tens, not ones. Shadows are a perspective map from
|
|
6431
|
+
* the cone's apex, so `castShadow` costs one extra render per frame per light.
|
|
6432
|
+
*/
|
|
6433
|
+
var SpotLight3D = class extends Node3D {
|
|
6434
|
+
static typeName = "SpotLight3D";
|
|
6435
|
+
static props = {
|
|
6436
|
+
color: { default: "#ffffff" },
|
|
6437
|
+
intensity: {
|
|
6438
|
+
default: 1,
|
|
6439
|
+
range: { min: 0 }
|
|
6440
|
+
},
|
|
6441
|
+
range: { default: 0 },
|
|
6442
|
+
coneDeg: {
|
|
6443
|
+
default: 60,
|
|
6444
|
+
range: {
|
|
6445
|
+
min: 0,
|
|
6446
|
+
max: 180,
|
|
6447
|
+
exclusiveMin: true,
|
|
6448
|
+
exclusiveMax: true
|
|
6449
|
+
}
|
|
6450
|
+
},
|
|
6451
|
+
penumbra: {
|
|
6452
|
+
default: .3,
|
|
6453
|
+
range: {
|
|
6454
|
+
min: 0,
|
|
6455
|
+
max: 1
|
|
6456
|
+
}
|
|
6457
|
+
},
|
|
6458
|
+
castShadow: { default: false },
|
|
6459
|
+
shadowMapSize: { default: 1024 },
|
|
6460
|
+
lookAt: {
|
|
6461
|
+
default: "",
|
|
6462
|
+
nodePath: true
|
|
6463
|
+
}
|
|
6464
|
+
};
|
|
6465
|
+
color = "#ffffff";
|
|
6466
|
+
intensity = 1;
|
|
6467
|
+
/** 0 = unlimited (three `distance` semantics). */
|
|
6468
|
+
range = 0;
|
|
6469
|
+
/** Full cone angle in degrees, exclusive of 0 and 180. */
|
|
6470
|
+
coneDeg = 60;
|
|
6471
|
+
/** 0 = hard edge, 1 = the whole cone is falloff. */
|
|
6472
|
+
penumbra = .3;
|
|
6473
|
+
castShadow = false;
|
|
6474
|
+
shadowMapSize = 1024;
|
|
6475
|
+
/**
|
|
6476
|
+
* A node path to AIM at, every frame — the camera's prop, for the same
|
|
6477
|
+
* reason: a searchlight that tracks the player, a stage spot on the boss.
|
|
6478
|
+
* Aiming by hand is Euler arithmetic in XYZ order, where a yaw on the same
|
|
6479
|
+
* node as a pitch swings the cone sideways (at yaw 180 a −55° pitch points
|
|
6480
|
+
* UP). Empty = the authored `rotation` is the aim.
|
|
6481
|
+
*/
|
|
6482
|
+
lookAt = "";
|
|
6483
|
+
warnedLookAt = "";
|
|
6484
|
+
update(_dt) {
|
|
6485
|
+
this.warnedLookAt = aimAt(this, this.warnedLookAt, "light");
|
|
6486
|
+
}
|
|
6487
|
+
_createObject3D() {
|
|
6488
|
+
const light = new SpotLight();
|
|
6489
|
+
light.add(light.target);
|
|
6490
|
+
light.target.position.set(0, 0, -1);
|
|
6491
|
+
return light;
|
|
6492
|
+
}
|
|
6493
|
+
_syncObject3D() {
|
|
6494
|
+
super._syncObject3D();
|
|
6495
|
+
const light = this._ensureObject3D();
|
|
6496
|
+
light.color.set(this.color);
|
|
6497
|
+
light.intensity = this.intensity;
|
|
6498
|
+
light.distance = this.range;
|
|
6499
|
+
light.angle = MathUtils.degToRad(this.coneDeg / 2);
|
|
6500
|
+
light.penumbra = this.penumbra;
|
|
6501
|
+
light.castShadow = this.castShadow;
|
|
6502
|
+
if (this.castShadow) {
|
|
6503
|
+
if (light.shadow.mapSize.x !== this.shadowMapSize) {
|
|
6504
|
+
light.shadow.mapSize.set(this.shadowMapSize, this.shadowMapSize);
|
|
6505
|
+
light.shadow.map?.dispose();
|
|
6506
|
+
light.shadow.map = null;
|
|
6507
|
+
}
|
|
6508
|
+
light.shadow.bias = -2e-4;
|
|
6509
|
+
light.shadow.normalBias = .002;
|
|
6510
|
+
}
|
|
6511
|
+
}
|
|
6512
|
+
};
|
|
6311
6513
|
//#endregion
|
|
6312
6514
|
//#region src/3d/nodes/loft-mesh-3d.ts
|
|
6313
6515
|
/**
|
|
@@ -11564,7 +11766,10 @@ var Tree3D = class Tree3D extends Node3D {
|
|
|
11564
11766
|
leafFadeStart: { default: 0 },
|
|
11565
11767
|
leafFadeEnd: { default: 0 },
|
|
11566
11768
|
leafShadows: { default: true },
|
|
11567
|
-
drape: {
|
|
11769
|
+
drape: {
|
|
11770
|
+
default: null,
|
|
11771
|
+
kinds: ["null", "boolean"]
|
|
11772
|
+
},
|
|
11568
11773
|
terrain: {
|
|
11569
11774
|
default: "",
|
|
11570
11775
|
nodePath: true
|
|
@@ -12908,9 +13113,29 @@ var VoxelGrid3D = class extends Node3D {
|
|
|
12908
13113
|
for (const [i, row] of self.voxels.entries()) if (!Array.isArray(row) || row.length < 3 || row.some((v) => typeof v !== "number")) throw new IncantoError("BAD_FORMAT", `VoxelGrid3D '${node.name}': voxels[${i}] must be [x, y, z, tile?] (numbers), got ${JSON.stringify(row)}.`);
|
|
12909
13114
|
if (self.voxels.length > MAX_INSTANCES) throw new IncantoError("BAD_FORMAT", `VoxelGrid3D '${node.name}': ${self.voxels.length} voxels exceeds the ${MAX_INSTANCES} this node can draw. Everything past the cap would still be SOLID and still be reported by tileAt(), and simply not appear. Split the world into several VoxelGrid3D nodes (one per chunk) and show the ones near the player.`);
|
|
12910
13115
|
}
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
13116
|
+
_voxels = [];
|
|
13117
|
+
/**
|
|
13118
|
+
* JSON-authored blocks as [x, y, z, tile] tuples (generated terrains bake
|
|
13119
|
+
* these). The seed lands WHEN THE PROP DOES — at load, before the tree
|
|
13120
|
+
* readies — not on the first `update()` as it used to: a sibling that
|
|
13121
|
+
* builds chunk colliders from `blocks()` at ready (the minecraft template's
|
|
13122
|
+
* Builder) saw an empty map and a baked hut was walked through, and the
|
|
13123
|
+
* late `setBlocks` then WIPED whatever a generator had built at ready.
|
|
13124
|
+
* Now a generator calling `setBlocks` after load is the author replacing
|
|
13125
|
+
* the seed, never the seed replacing the author.
|
|
13126
|
+
*/
|
|
13127
|
+
get voxels() {
|
|
13128
|
+
return this._voxels;
|
|
13129
|
+
}
|
|
13130
|
+
set voxels(rows) {
|
|
13131
|
+
this._voxels = rows;
|
|
13132
|
+
if (rows.length > 0) this.setBlocks(rows.map((t) => ({
|
|
13133
|
+
x: t[0] ?? 0,
|
|
13134
|
+
y: t[1] ?? 0,
|
|
13135
|
+
z: t[2] ?? 0,
|
|
13136
|
+
tile: t[3] ?? 0
|
|
13137
|
+
})));
|
|
13138
|
+
}
|
|
12914
13139
|
/** Said once per node: a runtime overflow must not spam a frame loop. */
|
|
12915
13140
|
reportedOverflow = false;
|
|
12916
13141
|
map = /* @__PURE__ */ new Map();
|
|
@@ -12969,15 +13194,6 @@ var VoxelGrid3D = class extends Node3D {
|
|
|
12969
13194
|
return this.mesh;
|
|
12970
13195
|
}
|
|
12971
13196
|
update() {
|
|
12972
|
-
if (this.voxels.length > 0 && this.voxels !== this.appliedVoxels) {
|
|
12973
|
-
this.appliedVoxels = this.voxels;
|
|
12974
|
-
this.setBlocks(this.voxels.map((t) => ({
|
|
12975
|
-
x: t[0] ?? 0,
|
|
12976
|
-
y: t[1] ?? 0,
|
|
12977
|
-
z: t[2] ?? 0,
|
|
12978
|
-
tile: t[3] ?? 0
|
|
12979
|
-
})));
|
|
12980
|
-
}
|
|
12981
13197
|
if (this.map.size > MAX_INSTANCES && !this.reportedOverflow) {
|
|
12982
13198
|
this.reportedOverflow = true;
|
|
12983
13199
|
diagnose(this.tree?.engine ?? null, "error", `[incanto] VoxelGrid3D '${this.getPath()}' holds ${this.map.size} blocks and can draw ${MAX_INSTANCES}. The rest are still solid and still reported by tileAt(), and do not appear. Split the world across several VoxelGrid3D nodes.`);
|
|
@@ -13099,6 +13315,7 @@ function registerNodes3D() {
|
|
|
13099
13315
|
registerNode(Camera3D);
|
|
13100
13316
|
registerNode(DirectionalLight3D);
|
|
13101
13317
|
registerNode(OmniLight3D);
|
|
13318
|
+
registerNode(SpotLight3D);
|
|
13102
13319
|
registerNode(StaticBody3D);
|
|
13103
13320
|
registerNode(RigidBody3D);
|
|
13104
13321
|
registerNode(Area3D);
|
|
@@ -13136,4 +13353,4 @@ function resolveEnvironmentHdri(env) {
|
|
|
13136
13353
|
return null;
|
|
13137
13354
|
}
|
|
13138
13355
|
//#endregion
|
|
13139
|
-
export {
|
|
13356
|
+
export { Billboard3D as A, cameraRelative as B, Flowers3D as C, Camera3D as D, CharacterController3D as E, Joint3D as F, acquireOwnTexture as G, movementState as H, InstancedMesh3D as I, acquireTexture as K, MeshInstance3D as L, DEFAULT_TERRAIN_TEXTURE_BASE as M, TERRAIN_THEMES as N, BoneLookAt3D as O, terrainThemeLayers as P, buildMeshGeometry as R, DENSITY_PRESETS as S, FLOWER_VARIETIES as T, rigPose as U, keyboardIntensity as V, TextureCache3D as W, LoftMesh3D as _, Tree3D as a, SpotLight3D as b, buildRiverRings as c, riverCarveChannels as d, riverStepFor as f, ModelInstance3D as g, Particles3D as h, VoxelGrid3D as i, Terrain3D as j, BoneAttachment3D as k, findRiverCoverageGaps as l, traceDownhillPath as m, registerNodes3D as n, Trail3D as o, smoothCourse as p, VOXEL_PALETTE as r, River3D as s, resolveEnvironmentHdri as t, projectToRiver as u, DirectionalLight3D as v, resolveFlowerDensity as w, Foliage3D as x, OmniLight3D as y, QUARTER_PITCH as z };
|