incanto 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/3d.d.ts +34 -0
- package/dist/3d.js +3 -3
- package/dist/{create-game-OSntcIiM.js → create-game-B5GWzy1E.js} +2 -109
- package/dist/index.js +1 -1
- package/dist/{physics-3d-D_kUdOjr.js → physics-3d-CDlvC9Z_.js} +1 -1
- package/dist/react.js +1 -1
- package/dist/{register-C9-16x_t.js → register-Lp2qn1Wq.js} +435 -37
- package/dist/test.js +3 -3
- package/editor/assets/{agent8-BDC4LhjC.js → agent8-Cw7igxDG.js} +1 -1
- package/editor/assets/{index-7qOYg7t8.js → index-N3Hnrv0w.js} +217 -118
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +25 -0
- package/skills/incanto-environment.md +14 -2
- package/skills/incanto-node-reference.md +6 -0
- package/templates-app/beacon-isle-3d/PROJECT/Status.md +1 -1
- package/templates-app/beacon-isle-3d/generate-world.ts +23 -18
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/beacon-isle-3d/src/behaviors.ts +70 -4
- package/templates-app/beacon-isle-3d/src/game.scene.json +20 -21
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/PROJECT/Context.md +1 -1
- package/templates-app/village-quest-3d/PROJECT/Requirements.md +1 -1
- package/templates-app/village-quest-3d/PROJECT/Structure.md +6 -1
- package/templates-app/village-quest-3d/generate-dressing.ts +769 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/behaviors.ts +74 -8
- package/templates-app/village-quest-3d/src/grove.scene.json +1 -13
- package/templates-app/village-quest-3d/src/village.scene.json +2989 -162
|
@@ -25,7 +25,7 @@ import type {
|
|
|
25
25
|
} from 'incanto';
|
|
26
26
|
import { Behavior, findPath, gridFromRows } from 'incanto';
|
|
27
27
|
import { mergeSolidRects, parseCells } from 'incanto/2d';
|
|
28
|
-
import type { CharacterController3D, Node3D, Trail3D } from 'incanto/3d';
|
|
28
|
+
import type { Camera3D, CharacterController3D, Node3D, Trail3D } from 'incanto/3d';
|
|
29
29
|
import { MeshInstance3D, Particles3D, StaticBody3D } from 'incanto/3d';
|
|
30
30
|
import { goToScene } from 'incanto/gameplay';
|
|
31
31
|
import groveJsonRaw from './grove.scene.json';
|
|
@@ -79,8 +79,53 @@ function windFor(state: string): { pitch: number; volume: number } {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
/**
|
|
83
|
-
|
|
82
|
+
/** Sprint feel — see sprintFeel(): FOV kick + per-stride dust. */
|
|
83
|
+
const FOV_BASE = 60;
|
|
84
|
+
const FOV_SPRINT = 66.5;
|
|
85
|
+
const STRIDE_SECONDS = 0.22;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* One kicked-up dirt puff, world-anchored at the foot spot (one-shot,
|
|
89
|
+
* self-removing). Non-additive expanding dust — it reads as path dirt
|
|
90
|
+
* leaving the ground, then thins out.
|
|
91
|
+
*/
|
|
92
|
+
function spawnFootDust(root: Node, at: [number, number, number], scale = 1): void {
|
|
93
|
+
const puff = new Particles3D('FootDust');
|
|
94
|
+
puff.position = [at[0], at[1], at[2]];
|
|
95
|
+
puff.rate = 0;
|
|
96
|
+
puff.burst = Math.round(4 * scale);
|
|
97
|
+
puff.blend = 'normal';
|
|
98
|
+
puff.lifetime = [0.3, 0.5];
|
|
99
|
+
puff.speed = [8, 34];
|
|
100
|
+
puff.directionDeg = -90; // up out of the ground…
|
|
101
|
+
puff.spreadDeg = 75;
|
|
102
|
+
puff.gravity = [0, 30]; // …then settle back down
|
|
103
|
+
puff.drag = 2.5;
|
|
104
|
+
puff.sizeStart = 11 * scale;
|
|
105
|
+
puff.sizeEnd = 30 * scale; // dust EXPANDS as it dissipates
|
|
106
|
+
puff.colorStart = '#d3bd97'; // the packed path dirt, sunlit
|
|
107
|
+
puff.colorEnd = '#a08c6e';
|
|
108
|
+
puff.alphaStart = 0.24;
|
|
109
|
+
puff.alphaEnd = 0;
|
|
110
|
+
puff.maxParticles = 24;
|
|
111
|
+
puff.on('finished', () => puff.free());
|
|
112
|
+
root.addChild(puff);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Module-scope sprint-feel state (both directors share ambientUpdate). */
|
|
116
|
+
const sprint = { strideClock: 0, wasAirborne: false, fov: FOV_BASE };
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Wind ambience + sprint FEEL — speed you can see instead of a ribbon glued
|
|
120
|
+
* to the hips: a soft camera FOV kick at full sprint, kicked-up dirt at the
|
|
121
|
+
* feet each stride, and a bigger thump-puff on landing.
|
|
122
|
+
*/
|
|
123
|
+
function ambientUpdate(
|
|
124
|
+
engine: Engine | null | undefined,
|
|
125
|
+
root: Node,
|
|
126
|
+
wind: Voice | null,
|
|
127
|
+
dt: number,
|
|
128
|
+
): void {
|
|
84
129
|
const controller = root.getNode('Player/Controller') as CharacterController3D | null;
|
|
85
130
|
if (!controller) return;
|
|
86
131
|
const state = controller.state;
|
|
@@ -88,8 +133,29 @@ function ambientUpdate(engine: Engine | null | undefined, root: Node, wind: Voic
|
|
|
88
133
|
const w = windFor(state);
|
|
89
134
|
wind.set({ pitch: w.pitch, volume: w.volume });
|
|
90
135
|
}
|
|
91
|
-
const
|
|
92
|
-
if (
|
|
136
|
+
const camera = root.getNodeOrNull('Camera') as Camera3D | null;
|
|
137
|
+
if (camera) {
|
|
138
|
+
sprint.fov +=
|
|
139
|
+
(((state === 'fastRun' ? FOV_SPRINT : FOV_BASE) as number) - sprint.fov) *
|
|
140
|
+
Math.min(1, dt * 6);
|
|
141
|
+
camera.fov = sprint.fov;
|
|
142
|
+
}
|
|
143
|
+
const player = root.getNodeOrNull('Player') as (Node3D & Positioned) | null;
|
|
144
|
+
if (!player) return;
|
|
145
|
+
const [px, py, pz] = player.position;
|
|
146
|
+
const feet: [number, number, number] = [px ?? 0, (py ?? 0) - 0.62, pz ?? 0];
|
|
147
|
+
const airborne = state === 'airborne';
|
|
148
|
+
if (sprint.wasAirborne && !airborne) spawnFootDust(root, feet, 1.7); // landing thump
|
|
149
|
+
sprint.wasAirborne = airborne;
|
|
150
|
+
if (state === 'fastRun') {
|
|
151
|
+
sprint.strideClock -= dt;
|
|
152
|
+
if (sprint.strideClock <= 0) {
|
|
153
|
+
sprint.strideClock = STRIDE_SECONDS;
|
|
154
|
+
spawnFootDust(root, feet);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
sprint.strideClock = 0;
|
|
158
|
+
}
|
|
93
159
|
}
|
|
94
160
|
|
|
95
161
|
// ---- VillageDirector --------------------------------------------------------------
|
|
@@ -123,9 +189,9 @@ export class VillageDirector extends Behavior {
|
|
|
123
189
|
this.wind?.stop();
|
|
124
190
|
}
|
|
125
191
|
|
|
126
|
-
override update(): void {
|
|
192
|
+
override update(dt: number): void {
|
|
127
193
|
const engine = this.node.tree?.engine;
|
|
128
|
-
ambientUpdate(engine, this.node, this.wind);
|
|
194
|
+
ambientUpdate(engine, this.node, this.wind, dt);
|
|
129
195
|
// E advances an open dialogue (same key as "talk" — no extra binding)
|
|
130
196
|
if (engine && this.dialogue.active && engine.input.justPressed('interact')) {
|
|
131
197
|
this.dialogue.advance();
|
|
@@ -275,7 +341,7 @@ export class GroveDirector extends Behavior {
|
|
|
275
341
|
|
|
276
342
|
override update(dt: number): void {
|
|
277
343
|
const engine = this.node.tree?.engine;
|
|
278
|
-
ambientUpdate(engine, this.node, this.wind);
|
|
344
|
+
ambientUpdate(engine, this.node, this.wind, dt);
|
|
279
345
|
this.faceWolvesForward();
|
|
280
346
|
this.huntOrPatrol(dt);
|
|
281
347
|
this.syncHpBar();
|
|
@@ -705,18 +705,6 @@
|
|
|
705
705
|
}
|
|
706
706
|
]
|
|
707
707
|
},
|
|
708
|
-
{
|
|
709
|
-
"name": "DashTrail",
|
|
710
|
-
"type": "Trail3D",
|
|
711
|
-
"props": {
|
|
712
|
-
"width": 0.5,
|
|
713
|
-
"color": "#ffffff",
|
|
714
|
-
"opacity": 0.3,
|
|
715
|
-
"seconds": 0.45,
|
|
716
|
-
"emitting": false,
|
|
717
|
-
"position": [0, -0.4, 0]
|
|
718
|
-
}
|
|
719
|
-
},
|
|
720
708
|
{
|
|
721
709
|
"name": "SwingSfx",
|
|
722
710
|
"type": "AudioPlayer",
|
|
@@ -798,7 +786,7 @@
|
|
|
798
786
|
"type": "UiText",
|
|
799
787
|
"uid": "n_gq_hint",
|
|
800
788
|
"props": {
|
|
801
|
-
"text": "click/F strike
|
|
789
|
+
"text": "click/F strike · Shift sprint · portal returns home",
|
|
802
790
|
"size": 12,
|
|
803
791
|
"color": "#cccccc",
|
|
804
792
|
"anchor": "bottomRight",
|