dcl-npc-toolkit 1.0.9 → 1.0.10-20230523140244.commit-fbf44ee
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/README.md +950 -6
- package/dist/bubble.d.ts +1 -1
- package/dist/bubble.js +14 -4
- package/dist/components.d.ts +5 -0
- package/dist/components.js +10 -5
- package/dist/dialog.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/npc.d.ts +2 -2
- package/dist/npc.js +29 -15
- package/dist/systems.d.ts +1 -0
- package/dist/systems.js +19 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,1087 +1,1950 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
|
|
5
|
+
|
|
4
6
|
# NPC-library
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
|
|
10
|
+
|
|
11
|
+
|
|
8
12
|
A collection of tools for creating Non-Player-Characters (NPCs). These are capable of having conversations with the player, and play different animations.
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
|
|
16
|
+
|
|
17
|
+
|
|
12
18
|
Capabilities of the NPCs in this library:
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
|
|
22
|
+
|
|
23
|
+
|
|
16
24
|
- Start a conversation when clicked or when walking near
|
|
17
25
|
|
|
26
|
+
|
|
27
|
+
|
|
18
28
|
- Trigger any action when clicked or when walking near
|
|
19
29
|
|
|
30
|
+
|
|
31
|
+
|
|
20
32
|
- Trigger any action when the player walks away
|
|
21
33
|
|
|
34
|
+
|
|
35
|
+
|
|
22
36
|
- Turn around slowly to always face the player
|
|
23
37
|
|
|
38
|
+
|
|
39
|
+
|
|
24
40
|
- Play an animation in the NPC 3d model, optionally returning to loop the idle animation afterwards
|
|
25
41
|
|
|
26
42
|
|
|
27
43
|
|
|
44
|
+
|
|
45
|
+
|
|
28
46
|
The dialog messages can also require that the player chooses options, and any action can be triggered when the player picks an option or advances past a message.
|
|
29
47
|
|
|
30
48
|
|
|
31
49
|
|
|
50
|
+
|
|
51
|
+
|
|
32
52
|
To use NPCs in your scene:
|
|
33
53
|
|
|
34
54
|
|
|
35
55
|
|
|
56
|
+
|
|
57
|
+
|
|
36
58
|
1. Install the library as an npm bundle. Run this command in your scene's project folder:
|
|
37
59
|
|
|
38
60
|
|
|
39
61
|
|
|
62
|
+
|
|
63
|
+
|
|
40
64
|
```
|
|
41
65
|
|
|
66
|
+
|
|
67
|
+
|
|
42
68
|
npm i dcl-npc-toolkit -B
|
|
43
69
|
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
2. Install the dependent sdk utils library as an npm bundle. Run this command in your scene's project folder:
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
npm i @dcl-sdk/utils -B
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
|
|
44
90
|
```
|
|
45
91
|
|
|
46
92
|
|
|
47
93
|
|
|
48
|
-
|
|
94
|
+
3. Run `dcl start` or `dcl build` so the dependencies are correctly installed.
|
|
95
|
+
|
|
96
|
+
|
|
49
97
|
|
|
50
98
|
|
|
51
99
|
|
|
52
|
-
|
|
100
|
+
4. Import the library into the scene's script. Add this line at the start of your `game.ts` file, or any other TypeScript files that require it:
|
|
101
|
+
|
|
102
|
+
|
|
53
103
|
|
|
54
104
|
|
|
55
105
|
|
|
56
106
|
```ts
|
|
57
107
|
|
|
108
|
+
|
|
109
|
+
|
|
58
110
|
import * as npc from 'dcl-npc-toolkit'
|
|
59
111
|
|
|
112
|
+
|
|
113
|
+
|
|
60
114
|
```
|
|
61
115
|
|
|
62
116
|
|
|
63
117
|
|
|
64
|
-
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
5. In your TypeScript file, call the `create` function passing it a `TransformType` and a `NPCData` object. The `NPCData` object requires a minimum of a `NPCType` and a function to trigger when the NPC is activated:
|
|
121
|
+
|
|
122
|
+
|
|
65
123
|
|
|
66
124
|
|
|
67
125
|
|
|
68
126
|
```ts
|
|
69
127
|
|
|
128
|
+
|
|
129
|
+
|
|
70
130
|
export let myNPC = npc.create({position: Vector3.create(8,0,8),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
71
131
|
|
|
132
|
+
|
|
133
|
+
|
|
72
134
|
//NPC Data Object
|
|
73
135
|
|
|
136
|
+
|
|
137
|
+
|
|
74
138
|
{
|
|
75
139
|
|
|
140
|
+
|
|
141
|
+
|
|
76
142
|
type: npc.NPCType.CUSTOM,
|
|
77
143
|
|
|
144
|
+
|
|
145
|
+
|
|
78
146
|
model: 'models/npc.glb',
|
|
79
147
|
|
|
148
|
+
|
|
149
|
+
|
|
80
150
|
onActivate:()=>{console.log('npc activated');}
|
|
81
151
|
|
|
152
|
+
|
|
153
|
+
|
|
82
154
|
}
|
|
83
155
|
|
|
156
|
+
|
|
157
|
+
|
|
84
158
|
)
|
|
85
159
|
|
|
160
|
+
|
|
161
|
+
|
|
86
162
|
```
|
|
87
163
|
|
|
88
164
|
|
|
89
165
|
|
|
166
|
+
|
|
167
|
+
|
|
90
168
|
5. Write a dialog script for your character, preferably on a separate file, making it of type `Dialog[]`.
|
|
91
169
|
|
|
92
170
|
|
|
93
171
|
|
|
172
|
+
|
|
173
|
+
|
|
94
174
|
```ts
|
|
95
175
|
|
|
176
|
+
|
|
177
|
+
|
|
96
178
|
import { Dialog } from 'dcl-npc-toolkit'
|
|
97
179
|
|
|
98
180
|
|
|
99
181
|
|
|
182
|
+
|
|
183
|
+
|
|
100
184
|
export let ILoveCats: Dialog[] = [
|
|
101
185
|
|
|
186
|
+
|
|
187
|
+
|
|
102
188
|
{
|
|
103
189
|
|
|
190
|
+
|
|
191
|
+
|
|
104
192
|
text: `I really lo-ove cats`,
|
|
105
193
|
|
|
194
|
+
|
|
195
|
+
|
|
106
196
|
isEndOfDialog: true
|
|
107
197
|
|
|
198
|
+
|
|
199
|
+
|
|
108
200
|
}
|
|
109
201
|
|
|
202
|
+
|
|
203
|
+
|
|
110
204
|
]
|
|
111
205
|
|
|
206
|
+
|
|
207
|
+
|
|
112
208
|
```
|
|
113
209
|
|
|
114
210
|
|
|
115
211
|
|
|
212
|
+
|
|
213
|
+
|
|
116
214
|
## NPC Default Behavior
|
|
117
215
|
|
|
118
216
|
|
|
119
217
|
|
|
218
|
+
|
|
219
|
+
|
|
120
220
|
NPCs at the very least must have:
|
|
121
221
|
|
|
122
222
|
|
|
123
223
|
|
|
224
|
+
|
|
225
|
+
|
|
124
226
|
- `position`: (_TransformType_) Must include position, rotation and scale.
|
|
125
227
|
|
|
228
|
+
|
|
229
|
+
|
|
126
230
|
- `NPCData`: (_Data Object_) with a minimum of two variables
|
|
127
231
|
|
|
232
|
+
|
|
233
|
+
|
|
128
234
|
- `type`: (_NPCType_) you have the choice to use a custom GLB object or an `AvatarShape` for your npc
|
|
129
235
|
|
|
236
|
+
|
|
237
|
+
|
|
130
238
|
- `NPCType.CUSTOM`
|
|
131
239
|
|
|
240
|
+
|
|
241
|
+
|
|
132
242
|
- `NPCType.AVATAR`
|
|
133
243
|
|
|
244
|
+
|
|
245
|
+
|
|
134
246
|
- `onActivate()`: (_()=> void_) A function to call when the NPC is activated.
|
|
135
247
|
|
|
136
248
|
|
|
137
249
|
|
|
250
|
+
|
|
251
|
+
|
|
138
252
|
*if you decide to use a `NPCType.CUSTOM` GLB model for your avatar, you must pass in a model object inside the `NPCData`*
|
|
139
253
|
|
|
254
|
+
|
|
255
|
+
|
|
140
256
|
- `model`: (_string_) The path to a 3D model
|
|
141
257
|
|
|
142
258
|
|
|
143
259
|
|
|
260
|
+
|
|
261
|
+
|
|
144
262
|
```ts
|
|
145
263
|
|
|
264
|
+
|
|
265
|
+
|
|
146
266
|
export let myNPC = npc.create({position: Vector3.create(8,0,8),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
147
267
|
|
|
268
|
+
|
|
269
|
+
|
|
148
270
|
//NPC Data Object
|
|
149
271
|
|
|
272
|
+
|
|
273
|
+
|
|
150
274
|
{
|
|
151
275
|
|
|
276
|
+
|
|
277
|
+
|
|
152
278
|
type: npc.NPCType.CUSTOM,
|
|
153
279
|
|
|
280
|
+
|
|
281
|
+
|
|
154
282
|
model: 'models/npc.glb',
|
|
155
283
|
|
|
284
|
+
|
|
285
|
+
|
|
156
286
|
onActivate:()=>{console.log('npc activated');}
|
|
157
287
|
|
|
288
|
+
|
|
289
|
+
|
|
158
290
|
}
|
|
159
291
|
|
|
292
|
+
|
|
293
|
+
|
|
160
294
|
)
|
|
161
295
|
|
|
296
|
+
|
|
297
|
+
|
|
162
298
|
```
|
|
163
299
|
|
|
164
300
|
|
|
165
301
|
|
|
302
|
+
|
|
303
|
+
|
|
166
304
|
With this default configuration, the NPC behaves in the following way:
|
|
167
305
|
|
|
168
306
|
|
|
169
307
|
|
|
308
|
+
|
|
309
|
+
|
|
170
310
|
- The `onActivate()` function is called when pressing E on the NPC, and when the player walks near at a distance of 6 meters.
|
|
171
311
|
|
|
312
|
+
|
|
313
|
+
|
|
172
314
|
- Once activated, there's a cooldown period of 5 seconds, that prevents the NPC to be activated again.
|
|
173
315
|
|
|
316
|
+
|
|
317
|
+
|
|
174
318
|
- After walking away from the NPC, if its dialog window was open it will be closed, and if the NPC was rotating to follow the player it will stop.
|
|
175
319
|
|
|
320
|
+
|
|
321
|
+
|
|
176
322
|
- If the NPC already has an open dialog window, clicking on the NPC won't do anything, to prevent accidentally clicking on it while flipping through the conversation.
|
|
177
323
|
|
|
324
|
+
|
|
325
|
+
|
|
178
326
|
- If the NPC has an animation named 'Idle', it will play it in a loop. If other non-looping animations are played, it will return to looping the 'Idle' animation after the indicated duration.
|
|
179
327
|
|
|
180
328
|
|
|
181
329
|
|
|
330
|
+
|
|
331
|
+
|
|
182
332
|
Many of these behaviors can be overridden or tweaked with the exposed properties.
|
|
183
333
|
|
|
184
334
|
|
|
335
|
+
## SDK7 UI
|
|
336
|
+
With sdk7, there are new ways to implement similar features from sdk6, one of them being the way 2D UI objects get created. To add the NPC dialogs to your sdk7 2D UI:
|
|
337
|
+
|
|
338
|
+
- create a variable to hold *all* of your 2D UI objects
|
|
339
|
+
- import the NPC UI from the library and add the React object to your scene UI tree
|
|
340
|
+
- create a function to be called once to render all of your 2D UI objects
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import ReactEcs, { Label, ReactEcsRenderer, UiEntity } from '@dcl/sdk/react-ecs'
|
|
344
|
+
import { NpcUtilsUi } from 'dcl-npc-toolkit'
|
|
345
|
+
|
|
346
|
+
const SceneOwnedUi = () =>
|
|
347
|
+
<UiEntity>
|
|
348
|
+
<NpcUtilsUi />
|
|
349
|
+
{ /* rest of user defined UI */ }
|
|
350
|
+
</UiEntity>
|
|
351
|
+
|
|
352
|
+
export function setupUi() {
|
|
353
|
+
ReactEcsRenderer.setUiRenderer(SceneOwnedUi)
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
|
|
185
358
|
|
|
186
359
|
## NPC Additional Properties
|
|
187
360
|
|
|
188
361
|
|
|
189
362
|
|
|
363
|
+
|
|
364
|
+
|
|
190
365
|
To configure other properties of an NPC, add a fourth argument as an `NPCData` object. This object can have the following optional properties:
|
|
191
366
|
|
|
192
367
|
|
|
193
368
|
|
|
369
|
+
|
|
370
|
+
|
|
194
371
|
- `idleAnim`: _(string)_ Name of the idle animation in the model. This animation is always looped. After playing a non-looping animation it returns to looping this one.
|
|
195
372
|
|
|
373
|
+
|
|
374
|
+
|
|
196
375
|
- `faceUser`: _(boolean)_ Set if the NPC rotates to face the user while active.
|
|
197
376
|
|
|
377
|
+
|
|
378
|
+
|
|
198
379
|
- `dialogSound`: _(string)_ Path to sound file to play once for every entry shown on the UI. If the dialog entry being shown has an `audio` field, the NPC will play the file referenced by the `audio` field instead.
|
|
199
380
|
|
|
381
|
+
|
|
382
|
+
|
|
200
383
|
- `coolDownDuration`: _(number)_ Change the cooldown period for activating the NPC again. The number is in seconds.
|
|
201
384
|
|
|
385
|
+
|
|
386
|
+
|
|
202
387
|
- `hoverText`: _(string)_ Set the UI hover feedback when pointing the cursor at the NPC. _TALK_ by default.
|
|
203
388
|
|
|
389
|
+
|
|
390
|
+
|
|
204
391
|
- `onlyClickTrigger`: _(boolean)_ If true, the NPC can't be activated by walking near. Just by clicking on it or calling its `activate()` function.
|
|
205
392
|
|
|
393
|
+
|
|
394
|
+
|
|
206
395
|
- `onlyETrigger`: _(boolean)_ If true, the NPC can't be activated by walking near. Just by pressing the E key on it or calling its `activate()` function.
|
|
207
396
|
|
|
397
|
+
|
|
398
|
+
|
|
208
399
|
- `onlyExternalTrigger`: _(boolean)_ If true, the NPC can't be activated by clicking, pressing E, or walking near. Just by calling its `activate()` function.
|
|
209
400
|
|
|
401
|
+
|
|
402
|
+
|
|
210
403
|
- `reactDistance`: _(number)_ Radius in meters for the player to activate the NPC or trigger the `onWalkAway()` function when leaving the radius.
|
|
211
404
|
|
|
405
|
+
|
|
406
|
+
|
|
212
407
|
- `continueOnWalkAway`: _(boolean)_ If true,when the player walks out of the `reactDistance` radius, the dialog window stays open and the NPC keeps turning to face the player (if applicable). It doesn't affect the triggering of the `onWalkAway()` function.
|
|
213
408
|
|
|
409
|
+
|
|
410
|
+
|
|
214
411
|
- `onWalkAway`: (_()=> void_) Function to call every time the player walks out of the `reactDistance` radius.
|
|
215
412
|
|
|
413
|
+
|
|
414
|
+
|
|
216
415
|
- `walkingAnim`: _(string)_ Name of the walking animation on the model. This animation is looped when calling the `followPath()` function.
|
|
217
416
|
|
|
417
|
+
|
|
418
|
+
|
|
218
419
|
- `walkingSpeed`: _(number)_ Speed of the NPC when walking. By default _2_.
|
|
219
420
|
|
|
421
|
+
|
|
422
|
+
|
|
220
423
|
- `path`: _(Vector3)_ Default path to walk. If a value is provided for this field on NPC initialization, the NPC will walk over this path in loop from the start.
|
|
221
424
|
|
|
425
|
+
- `bubbleHeight`: _(number)_ The height at which to display the speech bubble above the head of the NPC.
|
|
426
|
+
|
|
427
|
+
- `textBubble`: _(boolean)_ If true, NPC starts with a speech bubble object ready to be accessed from the start. Otherwise, they text bubble is only built on the first call to `talkBubble()` on the NPC.
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
222
431
|
- `noUI`: _(boolean)_ If true, no UI object is built for UI dialogs for this NPC. This may help optimize the scene if this feature is not used.
|
|
223
432
|
|
|
224
433
|
|
|
225
434
|
|
|
435
|
+
|
|
436
|
+
|
|
226
437
|
```ts
|
|
227
438
|
|
|
439
|
+
|
|
440
|
+
|
|
228
441
|
export let myNPC = npc.create({position: Vector3.create(8,0,8),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
229
442
|
|
|
443
|
+
|
|
444
|
+
|
|
230
445
|
//NPC Data Object
|
|
231
446
|
|
|
447
|
+
|
|
448
|
+
|
|
232
449
|
{
|
|
233
450
|
|
|
451
|
+
|
|
452
|
+
|
|
234
453
|
type: npc.NPCType.CUSTOM,
|
|
235
454
|
|
|
455
|
+
|
|
456
|
+
|
|
236
457
|
model: 'models/npc.glb',
|
|
237
458
|
|
|
459
|
+
|
|
460
|
+
|
|
238
461
|
onActivate: ()=>{console.log('npc activated');},
|
|
239
462
|
|
|
463
|
+
|
|
464
|
+
|
|
240
465
|
onWalkAway: ()=>{console.log('test on walk away function')},
|
|
241
466
|
|
|
467
|
+
|
|
468
|
+
|
|
242
469
|
faceUser: true,
|
|
243
470
|
|
|
471
|
+
|
|
472
|
+
|
|
244
473
|
reactDistance: 3,
|
|
245
474
|
|
|
475
|
+
|
|
476
|
+
|
|
246
477
|
idleAnim: 'idle1',
|
|
247
478
|
|
|
479
|
+
|
|
480
|
+
|
|
248
481
|
walkingAnim: 'walk1',
|
|
249
482
|
|
|
483
|
+
|
|
484
|
+
|
|
250
485
|
hoverText: 'Activate',
|
|
251
486
|
|
|
487
|
+
|
|
488
|
+
|
|
252
489
|
continueOnWalkAway: true,
|
|
253
490
|
|
|
491
|
+
|
|
492
|
+
|
|
254
493
|
onlyClickTrigger: false,
|
|
255
494
|
|
|
495
|
+
|
|
496
|
+
|
|
256
497
|
onlyExternalTrigger: false
|
|
257
498
|
|
|
499
|
+
|
|
500
|
+
|
|
258
501
|
}
|
|
259
502
|
|
|
503
|
+
|
|
504
|
+
|
|
260
505
|
)
|
|
261
506
|
|
|
507
|
+
|
|
508
|
+
|
|
262
509
|
```
|
|
263
510
|
|
|
264
511
|
|
|
265
512
|
|
|
513
|
+
|
|
514
|
+
|
|
266
515
|
## Get NPC Data
|
|
267
516
|
|
|
268
517
|
|
|
269
518
|
|
|
519
|
+
|
|
520
|
+
|
|
270
521
|
```ts
|
|
271
522
|
|
|
523
|
+
|
|
524
|
+
|
|
272
525
|
npc.getData(myNPC)
|
|
273
526
|
|
|
527
|
+
|
|
528
|
+
|
|
274
529
|
```
|
|
275
530
|
|
|
276
531
|
|
|
277
532
|
|
|
533
|
+
|
|
534
|
+
|
|
278
535
|
There are several properties you can check on an NPC to know what its current state is:
|
|
279
536
|
|
|
280
537
|
|
|
281
538
|
|
|
539
|
+
|
|
540
|
+
|
|
282
541
|
- `.state`: An enum value of type `NPCState`. Supported values are `NPCState.STANDING` (default), `NPCState.TALKING`, and `NPCState.FOLLOWPATH`. `TALKING` is applied when the dialog window is opened, and set back to `STANDING` when the window is closed. `FOLLOWPATH` is applied when the NPC starts walking, and set back to `STANDING` when the NPC finishes its path or is stopped.
|
|
283
542
|
|
|
543
|
+
|
|
544
|
+
|
|
284
545
|
- `.introduced`: Boolean, false by default. Set to true if the NPC has spoken to the player at least once in this session.
|
|
285
546
|
|
|
547
|
+
|
|
548
|
+
|
|
286
549
|
- `.visible`: Returns a Boolean, false by default. True if the dialog window for this NPC is currently open.
|
|
287
550
|
|
|
551
|
+
|
|
552
|
+
|
|
288
553
|
- `.inCooldown`: Boolean, false by default. True if the NPC was recently activated and it's now in cooldown. The NPC won't respond to being activated till `inCooldown` is false.
|
|
289
554
|
|
|
290
555
|
|
|
291
556
|
|
|
557
|
+
|
|
558
|
+
|
|
292
559
|
> TIP: If you want to force an activation of the NPC in spite of the `inCooldown` value, you can force this value to true before activating.
|
|
293
560
|
|
|
294
561
|
|
|
295
562
|
|
|
563
|
+
|
|
564
|
+
|
|
296
565
|
## NPC Callable Actions
|
|
297
566
|
|
|
298
567
|
|
|
299
568
|
|
|
569
|
+
|
|
570
|
+
|
|
300
571
|
An NPC object has several callable functions that come with the class:
|
|
301
572
|
|
|
302
573
|
|
|
303
574
|
|
|
575
|
+
|
|
576
|
+
|
|
304
577
|
### Talk
|
|
305
578
|
|
|
306
579
|
|
|
307
580
|
|
|
581
|
+
|
|
582
|
+
|
|
308
583
|
To start a conversation with the NPC using the dialog UI, call the `talk()` function. The function takes the following **required** parameter:
|
|
309
584
|
|
|
310
585
|
|
|
311
586
|
|
|
587
|
+
|
|
588
|
+
|
|
312
589
|
- `script`: _(Dialog[])_ This array contains the information to manage the conversation, including events that may be triggered, options to choose, etc.
|
|
313
590
|
|
|
314
591
|
|
|
315
592
|
|
|
593
|
+
|
|
594
|
+
|
|
316
595
|
It can also take the following optional parameters:
|
|
317
596
|
|
|
318
597
|
|
|
319
598
|
|
|
599
|
+
|
|
600
|
+
|
|
320
601
|
- `startIndex`: _(number | string)_ The _Dialog_ object from the `script` array to open first. By default this is _0_, the first element of the array. Pass a number to open the entry on a given array position, or pass a string to open the entry with a `name` property matching that string.
|
|
321
602
|
|
|
603
|
+
|
|
604
|
+
|
|
322
605
|
- `duration`: _(number)_ Number of seconds to wait before closing the dialog window. If no value is set, the window is kept open till the player reaches the end of the conversation or something else closes it.
|
|
323
606
|
|
|
324
607
|
|
|
325
608
|
|
|
609
|
+
|
|
610
|
+
|
|
326
611
|
```ts
|
|
327
612
|
|
|
613
|
+
|
|
614
|
+
|
|
328
615
|
npc.talk(myNPC,myScript, 0)
|
|
329
616
|
|
|
617
|
+
|
|
618
|
+
|
|
330
619
|
```
|
|
331
620
|
|
|
332
621
|
|
|
333
622
|
|
|
623
|
+
|
|
624
|
+
|
|
334
625
|
Learn how to build a script object for NPCs in a section below.
|
|
335
626
|
|
|
336
627
|
|
|
337
628
|
|
|
629
|
+
|
|
630
|
+
|
|
338
631
|
### Play Animations
|
|
339
632
|
|
|
340
633
|
|
|
341
634
|
|
|
635
|
+
|
|
636
|
+
|
|
342
637
|
By default, the NPC will loop an animation named 'Idle', or with a name passed in the `idleAnim` parameter.
|
|
343
638
|
|
|
344
639
|
|
|
345
640
|
|
|
641
|
+
|
|
642
|
+
|
|
346
643
|
Make the NPC play another animation by calling the `playAnimation()` function. The function takes the following **required** parameter:
|
|
347
644
|
|
|
348
645
|
|
|
349
646
|
|
|
647
|
+
|
|
648
|
+
|
|
350
649
|
- `animationName`: _(string)_ The name of the animation to play.
|
|
351
650
|
|
|
352
651
|
|
|
353
652
|
|
|
653
|
+
|
|
654
|
+
|
|
354
655
|
It can also take the following optional parameters:
|
|
355
656
|
|
|
356
657
|
|
|
357
658
|
|
|
659
|
+
|
|
660
|
+
|
|
358
661
|
- `noLoop`: _(boolean)_ If true, plays the animation just once. Otherwise, the animation is looped.
|
|
359
662
|
|
|
663
|
+
|
|
664
|
+
|
|
360
665
|
- `duration`: _(number)_ Specifies the duration in seconds of the animation. When finished, it returns to playing the idle animation.
|
|
361
666
|
|
|
362
667
|
|
|
363
668
|
|
|
669
|
+
|
|
670
|
+
|
|
364
671
|
> Note: If `noLoop` is true but no `duration` is set, the model will stay still after playing the animation instead of returning to the idle animation.
|
|
365
672
|
|
|
366
673
|
|
|
367
674
|
|
|
675
|
+
|
|
676
|
+
|
|
368
677
|
```ts
|
|
369
678
|
|
|
679
|
+
|
|
680
|
+
|
|
370
681
|
npc.playAnimation(myNPC, `Head_Yes`, true, 2.63)
|
|
371
682
|
|
|
683
|
+
|
|
684
|
+
|
|
372
685
|
```
|
|
373
686
|
|
|
374
687
|
|
|
375
688
|
|
|
689
|
+
|
|
690
|
+
|
|
376
691
|
### Change idle animation
|
|
377
692
|
|
|
378
693
|
|
|
379
694
|
|
|
695
|
+
|
|
696
|
+
|
|
380
697
|
The NPC's idle animation is looped by default whenever the NPC is not playing any other animations. In some cases you may want to have different idle animations depending on the circumstances, like while in a conversation, or if the NPC changes its general attitude after some event.
|
|
381
698
|
|
|
382
699
|
|
|
383
700
|
|
|
701
|
+
|
|
702
|
+
|
|
384
703
|
You set the NPC's idle animation when creating the NPC, using the `idleAnim` field. To change this animation at some later time, use `changeIdleAnim()`.
|
|
385
704
|
|
|
386
705
|
|
|
387
706
|
|
|
707
|
+
|
|
708
|
+
|
|
388
709
|
The `changeIdleAnim()` function takes two arguments:
|
|
389
710
|
|
|
390
711
|
|
|
391
712
|
|
|
713
|
+
|
|
714
|
+
|
|
392
715
|
- `animation`: The name of the new animation to set as the idle animation
|
|
393
716
|
|
|
717
|
+
|
|
718
|
+
|
|
394
719
|
- `play`: Optionally pass this value as _true_ if you want this new animation to start playing right away.
|
|
395
720
|
|
|
396
721
|
|
|
397
722
|
|
|
723
|
+
|
|
724
|
+
|
|
398
725
|
```ts
|
|
399
726
|
|
|
727
|
+
|
|
728
|
+
|
|
400
729
|
npc.changeIdleAnim(myNPC,`AngryIdle`, true)
|
|
401
730
|
|
|
731
|
+
|
|
732
|
+
|
|
402
733
|
```
|
|
403
734
|
|
|
404
735
|
|
|
405
736
|
|
|
737
|
+
|
|
738
|
+
|
|
406
739
|
### Activate
|
|
407
740
|
|
|
408
741
|
|
|
409
742
|
|
|
743
|
+
|
|
744
|
+
|
|
410
745
|
The `activate()` function can be used to trigger the `onActivate()` function, as an alternative to pressing E or walking near.
|
|
411
746
|
|
|
412
747
|
|
|
413
748
|
|
|
749
|
+
|
|
750
|
+
|
|
414
751
|
```ts
|
|
415
752
|
|
|
753
|
+
|
|
754
|
+
|
|
416
755
|
npc.activate(myNPC)
|
|
417
756
|
|
|
757
|
+
|
|
758
|
+
|
|
418
759
|
```
|
|
419
760
|
|
|
420
761
|
|
|
421
762
|
|
|
763
|
+
|
|
764
|
+
|
|
422
765
|
The `activate()` function is callable even when in cool down period, and it doesn't start a new cool down period.
|
|
423
766
|
|
|
424
767
|
|
|
425
768
|
|
|
769
|
+
|
|
770
|
+
|
|
426
771
|
### Stop Walking
|
|
427
772
|
|
|
428
773
|
|
|
429
774
|
|
|
775
|
+
|
|
776
|
+
|
|
430
777
|
If the NPC is currently walking, call `stopWalking()` to stop it moving and return to playing its idle animation.
|
|
431
778
|
|
|
432
779
|
|
|
433
780
|
|
|
781
|
+
|
|
782
|
+
|
|
434
783
|
```ts
|
|
435
784
|
|
|
785
|
+
|
|
786
|
+
|
|
436
787
|
npc.stopWalking(myNPC)
|
|
437
788
|
|
|
789
|
+
|
|
790
|
+
|
|
438
791
|
```
|
|
439
792
|
|
|
440
793
|
|
|
441
794
|
|
|
795
|
+
|
|
796
|
+
|
|
442
797
|
`stopWalking()` can be called with no parameters, or it can also be called with:
|
|
443
798
|
|
|
444
799
|
|
|
445
800
|
|
|
801
|
+
|
|
802
|
+
|
|
446
803
|
- `duration`: Seconds to wait before starting to walk again. If not provided, the NPC will stop walking indefinitely.
|
|
447
804
|
|
|
448
805
|
|
|
449
806
|
|
|
807
|
+
|
|
808
|
+
|
|
450
809
|
> Note: If the NPC is has its dialog window open when the timer for the `duration` ends, the NPC will not return to walking.
|
|
451
810
|
|
|
452
811
|
|
|
453
812
|
|
|
813
|
+
|
|
814
|
+
|
|
454
815
|
To make the NPC play a different animation from idle when paused, call `playAnimation()` after `stopWalking()`.
|
|
455
816
|
|
|
456
817
|
|
|
457
818
|
|
|
819
|
+
|
|
820
|
+
|
|
458
821
|
### Follow Path
|
|
459
822
|
|
|
460
823
|
|
|
461
824
|
|
|
825
|
+
|
|
826
|
+
|
|
462
827
|
Make an NPC walk following a path of `Vector3` points by calling `followPath()`. While walking, the NPC will play the `walkingAnim` if one was set when defining the NPC. The path can be taken once or on a loop.
|
|
463
828
|
|
|
464
829
|
|
|
465
830
|
|
|
831
|
+
|
|
832
|
+
|
|
466
833
|
`followPath()` can be called with no parameters if a `path` was already provided in the NPC's initialization or in a previous calling of `followPath()`. If the NPC was previously in the middle of walking a path and was interrupted, calling `followPath()` again with no arguments will return the NPC to that path.
|
|
467
834
|
|
|
468
835
|
|
|
469
836
|
|
|
837
|
+
|
|
838
|
+
|
|
470
839
|
```ts
|
|
471
840
|
|
|
841
|
+
|
|
842
|
+
|
|
472
843
|
npc.followPath(myNPC)
|
|
473
844
|
|
|
845
|
+
|
|
846
|
+
|
|
474
847
|
```
|
|
475
848
|
|
|
476
849
|
|
|
477
850
|
|
|
851
|
+
|
|
852
|
+
|
|
478
853
|
> Note: If the NPC is initialized with a `path` value, it will start out walking that path in a loop, no need to run `followPath()`.
|
|
479
854
|
|
|
480
855
|
|
|
481
856
|
|
|
857
|
+
|
|
858
|
+
|
|
482
859
|
`followPath()` has a single optional parameter of type `FollowPathData`. This object may have the following optional fields:
|
|
483
860
|
|
|
484
861
|
|
|
485
862
|
|
|
863
|
+
|
|
864
|
+
|
|
486
865
|
- path: Array of `Vector3` positions to walk over.
|
|
487
866
|
|
|
867
|
+
|
|
868
|
+
|
|
488
869
|
- speed: Speed to move at while walking this path. If no `speed` or `totalDuration` is provided, it uses the NPC's `walkingSpeed`, which is _2_ by default.
|
|
489
870
|
|
|
871
|
+
|
|
872
|
+
|
|
490
873
|
- totalDuration: The duration in _seconds_ that the whole path should take. The NPC will move at the constant speed required to finish in that time. This value overrides that of the _speed_.
|
|
491
874
|
|
|
875
|
+
|
|
876
|
+
|
|
492
877
|
- loop: _boolean_ If true, the NPC walks in circles over the provided set of points in the path. _false_ by default, unless the NPC is initiated with a `path`, in which case it starts as _true_.
|
|
493
878
|
|
|
879
|
+
|
|
880
|
+
|
|
494
881
|
- curve: _boolean_ If true, the path is traced a single smooth curve that passes over each of the indicated points. The curve is made out of straight-line segments, the path is stored with 4 times as many points as originally defined. _false_ by default.
|
|
495
882
|
|
|
883
|
+
|
|
884
|
+
|
|
496
885
|
- startingPoint: Index position for what point to start from on the path. _0_ by default.
|
|
497
886
|
|
|
887
|
+
|
|
888
|
+
|
|
498
889
|
- onFinishCallback: Function to call when the NPC finished walking over all the points on the path. This is only called when `loop` is _false_.
|
|
499
890
|
|
|
891
|
+
|
|
892
|
+
|
|
500
893
|
- onReachedPointCallback: Function to call once every time the NPC reaches a point in the path.
|
|
501
894
|
|
|
502
895
|
|
|
503
896
|
|
|
897
|
+
|
|
898
|
+
|
|
504
899
|
```ts
|
|
505
900
|
|
|
901
|
+
|
|
902
|
+
|
|
506
903
|
export let myNPC = npc.create({position: Vector3.create(8,0,8),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
507
904
|
|
|
905
|
+
|
|
906
|
+
|
|
508
907
|
//NPC Data Object
|
|
509
908
|
|
|
909
|
+
|
|
910
|
+
|
|
510
911
|
{
|
|
511
912
|
|
|
913
|
+
|
|
914
|
+
|
|
512
915
|
type: npc.NPCType.CUSTOM,
|
|
513
916
|
|
|
917
|
+
|
|
918
|
+
|
|
514
919
|
model: 'models/npc.glb',
|
|
515
920
|
|
|
921
|
+
|
|
922
|
+
|
|
516
923
|
onActivate: ()=>{console.log('npc activated');},
|
|
517
924
|
|
|
925
|
+
|
|
926
|
+
|
|
518
927
|
onWalkAway: ()=>{console.log('test on walk away function')},
|
|
519
928
|
|
|
929
|
+
|
|
930
|
+
|
|
520
931
|
faceUser: true,
|
|
521
932
|
|
|
933
|
+
|
|
934
|
+
|
|
522
935
|
reactDistance: 3,
|
|
523
936
|
|
|
937
|
+
|
|
938
|
+
|
|
524
939
|
idleAnim: 'idle1',
|
|
525
940
|
|
|
941
|
+
|
|
942
|
+
|
|
526
943
|
walkingAnim: 'walk1',
|
|
527
944
|
|
|
945
|
+
|
|
946
|
+
|
|
528
947
|
hoverText: "Activate"
|
|
529
948
|
|
|
949
|
+
|
|
950
|
+
|
|
530
951
|
}
|
|
531
952
|
|
|
953
|
+
|
|
954
|
+
|
|
532
955
|
)
|
|
533
956
|
|
|
534
957
|
|
|
535
958
|
|
|
959
|
+
|
|
960
|
+
|
|
536
961
|
npc.followPath(myNPC,
|
|
537
962
|
|
|
963
|
+
|
|
964
|
+
|
|
538
965
|
{
|
|
539
966
|
|
|
967
|
+
|
|
968
|
+
|
|
540
969
|
path:path,
|
|
541
970
|
|
|
971
|
+
|
|
972
|
+
|
|
542
973
|
loop:true,
|
|
543
974
|
|
|
975
|
+
|
|
976
|
+
|
|
544
977
|
pathType: npc.NPCPathType.RIGID_PATH,
|
|
545
978
|
|
|
979
|
+
|
|
980
|
+
|
|
546
981
|
onFinishCallback:()=>{console.log('path is done')},
|
|
547
982
|
|
|
983
|
+
|
|
984
|
+
|
|
548
985
|
onReachedPointCallback:()=>{console.log('ending oint')},
|
|
549
986
|
|
|
987
|
+
|
|
988
|
+
|
|
550
989
|
totalDuration: 20
|
|
551
990
|
|
|
991
|
+
|
|
992
|
+
|
|
552
993
|
}
|
|
553
994
|
|
|
995
|
+
|
|
996
|
+
|
|
554
997
|
)
|
|
555
998
|
|
|
556
999
|
|
|
557
1000
|
|
|
1001
|
+
|
|
1002
|
+
|
|
558
1003
|
```
|
|
559
1004
|
|
|
560
1005
|
|
|
561
1006
|
|
|
1007
|
+
|
|
1008
|
+
|
|
562
1009
|
#### NPC Walking Speed
|
|
563
1010
|
|
|
564
1011
|
|
|
565
1012
|
|
|
1013
|
+
|
|
1014
|
+
|
|
566
1015
|
The following list of factors are used to determine speed in hierarchical order:
|
|
567
1016
|
|
|
568
1017
|
|
|
569
1018
|
|
|
1019
|
+
|
|
1020
|
+
|
|
570
1021
|
- `totalDuration` parameter set when calling `followPath()` is used over the total distance travelled over the path.
|
|
571
1022
|
|
|
1023
|
+
|
|
1024
|
+
|
|
572
1025
|
- `speed` parameter set when calling `followPath()`
|
|
573
1026
|
|
|
1027
|
+
|
|
1028
|
+
|
|
574
1029
|
- `walkingSpeed` parameter set when initializing NPC
|
|
575
1030
|
|
|
1031
|
+
|
|
1032
|
+
|
|
576
1033
|
- Default value _2_.
|
|
577
1034
|
|
|
578
1035
|
|
|
579
1036
|
|
|
1037
|
+
|
|
1038
|
+
|
|
580
1039
|
#### Joining the path
|
|
581
1040
|
|
|
582
1041
|
|
|
583
1042
|
|
|
1043
|
+
|
|
1044
|
+
|
|
584
1045
|
If the NPC's current position when calling `followPath()` doesn't match the first position in the `path` array (or the one that matches the `startingPoint` value), the current position is added to the `path` array. The NPC will start by walking from its current position to the first point provided in the path.
|
|
585
1046
|
|
|
586
1047
|
|
|
587
1048
|
|
|
1049
|
+
|
|
1050
|
+
|
|
588
1051
|
The `path` can be a single point, and the NPC will then walk a from its current position to that point.
|
|
589
1052
|
|
|
590
1053
|
|
|
591
1054
|
|
|
1055
|
+
|
|
1056
|
+
|
|
592
1057
|
> Note: If the speed of the NPC is determined by a `totalDuration` value, the segment that the NPC walks to join into the path is counted as part of the full path. If this segment is long, it will increase the NPC walking speed so that the full path lasts as what's indicated by the `totalDuration`.
|
|
593
1058
|
|
|
594
1059
|
|
|
595
1060
|
|
|
1061
|
+
|
|
1062
|
+
|
|
596
1063
|
In this example the NPC is far away from the start of the path. It will first walk from _10, 0, 10_ to _2, 0, 2_ and then continue the path.
|
|
597
1064
|
|
|
598
1065
|
|
|
599
1066
|
|
|
1067
|
+
|
|
1068
|
+
|
|
600
1069
|
```ts
|
|
601
1070
|
|
|
1071
|
+
|
|
1072
|
+
|
|
602
1073
|
export let myNPC = npc.create({position: Vector3.create(10,0,10),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
603
1074
|
|
|
1075
|
+
|
|
1076
|
+
|
|
604
1077
|
//NPC Data Object
|
|
605
1078
|
|
|
1079
|
+
|
|
1080
|
+
|
|
606
1081
|
{
|
|
607
1082
|
|
|
1083
|
+
|
|
1084
|
+
|
|
608
1085
|
type: npc.NPCType.CUSTOM,
|
|
609
1086
|
|
|
1087
|
+
|
|
1088
|
+
|
|
610
1089
|
model: 'models/npc.glb',
|
|
611
1090
|
|
|
1091
|
+
|
|
1092
|
+
|
|
612
1093
|
onActivate: ()=>{console.log('npc activated');},
|
|
613
1094
|
|
|
1095
|
+
|
|
1096
|
+
|
|
614
1097
|
}
|
|
615
1098
|
|
|
1099
|
+
|
|
1100
|
+
|
|
616
1101
|
)
|
|
617
1102
|
|
|
1103
|
+
|
|
1104
|
+
|
|
618
1105
|
npc.followPath(myNPC,
|
|
619
1106
|
|
|
1107
|
+
|
|
1108
|
+
|
|
620
1109
|
{
|
|
621
1110
|
|
|
1111
|
+
|
|
1112
|
+
|
|
622
1113
|
path: [new Vector3(2, 0, 2), new Vector3(4, 0, 4), new Vector3(6, 0, 6)]
|
|
623
1114
|
|
|
1115
|
+
|
|
1116
|
+
|
|
624
1117
|
})
|
|
625
1118
|
|
|
1119
|
+
|
|
1120
|
+
|
|
626
1121
|
```
|
|
627
1122
|
|
|
628
1123
|
|
|
629
1124
|
|
|
1125
|
+
|
|
1126
|
+
|
|
630
1127
|
#### Example Interrupting the NPC
|
|
631
1128
|
|
|
632
1129
|
|
|
633
1130
|
|
|
1131
|
+
|
|
1132
|
+
|
|
634
1133
|
In the following example, an NPC starts roaming walking over a path, pausing on every point to call out for its lost kitten. If the player activates the NPC (by pressing E on it or walking near it) the NPC stops, and turns to face the player and talk. When the conversation is over, the NPC returns to walking its path from where it left off.
|
|
635
1134
|
|
|
636
1135
|
|
|
637
1136
|
|
|
1137
|
+
|
|
1138
|
+
|
|
638
1139
|
```ts
|
|
639
1140
|
|
|
1141
|
+
|
|
1142
|
+
|
|
640
1143
|
export let myNPC = npc.create({position: Vector3.create(10,0,10),rotation:Quaternion.Zero(), scale: Vector3.create(1,1,1)},
|
|
641
1144
|
|
|
1145
|
+
|
|
1146
|
+
|
|
642
1147
|
//NPC Data Object
|
|
643
1148
|
|
|
1149
|
+
|
|
1150
|
+
|
|
644
1151
|
{
|
|
645
1152
|
|
|
1153
|
+
|
|
1154
|
+
|
|
646
1155
|
type: npc.NPCType.CUSTOM,
|
|
647
1156
|
|
|
1157
|
+
|
|
1158
|
+
|
|
648
1159
|
model: 'models/npc.glb',
|
|
649
1160
|
|
|
1161
|
+
|
|
1162
|
+
|
|
650
1163
|
onActivate: ()=>{
|
|
651
1164
|
|
|
1165
|
+
|
|
1166
|
+
|
|
652
1167
|
npc.stopWalking(myNPC);
|
|
653
1168
|
|
|
1169
|
+
|
|
1170
|
+
|
|
654
1171
|
npc.talk(myNPC, lostCat, 0)
|
|
655
1172
|
|
|
1173
|
+
|
|
1174
|
+
|
|
656
1175
|
console.log('npc activated');
|
|
657
1176
|
|
|
1177
|
+
|
|
1178
|
+
|
|
658
1179
|
},
|
|
659
1180
|
|
|
1181
|
+
|
|
1182
|
+
|
|
660
1183
|
walkingAnim: 'walk1',
|
|
661
1184
|
|
|
1185
|
+
|
|
1186
|
+
|
|
662
1187
|
faceUser:true
|
|
663
1188
|
|
|
1189
|
+
|
|
1190
|
+
|
|
664
1191
|
}
|
|
665
1192
|
|
|
1193
|
+
|
|
1194
|
+
|
|
666
1195
|
)
|
|
667
1196
|
|
|
668
1197
|
|
|
669
1198
|
|
|
1199
|
+
|
|
1200
|
+
|
|
670
1201
|
npc.followPath(myNPC,
|
|
671
1202
|
|
|
1203
|
+
|
|
1204
|
+
|
|
672
1205
|
{
|
|
673
1206
|
|
|
1207
|
+
|
|
1208
|
+
|
|
674
1209
|
path: [new Vector3(4, 0, 30), new Vector3(6, 0, 29), new Vector3(15, 0, 25)],
|
|
675
1210
|
|
|
1211
|
+
|
|
1212
|
+
|
|
676
1213
|
loop: true,
|
|
677
1214
|
|
|
1215
|
+
|
|
1216
|
+
|
|
678
1217
|
onReachedPointCallback: () => {
|
|
679
1218
|
|
|
1219
|
+
|
|
1220
|
+
|
|
680
1221
|
npc.stopWalking(myNPC, 3)
|
|
681
1222
|
|
|
1223
|
+
|
|
1224
|
+
|
|
682
1225
|
npc.playAnimation(myNPC, `Cocky`, true, 2.93)
|
|
683
1226
|
|
|
1227
|
+
|
|
1228
|
+
|
|
684
1229
|
}
|
|
685
1230
|
|
|
1231
|
+
|
|
1232
|
+
|
|
686
1233
|
})
|
|
687
1234
|
|
|
688
1235
|
|
|
689
1236
|
|
|
1237
|
+
|
|
1238
|
+
|
|
690
1239
|
export let lostCat: Dialog[] = [
|
|
691
1240
|
|
|
1241
|
+
|
|
1242
|
+
|
|
692
1243
|
{
|
|
693
1244
|
|
|
1245
|
+
|
|
1246
|
+
|
|
694
1247
|
text: `I lost my cat, I'm going crazy here`
|
|
695
1248
|
|
|
1249
|
+
|
|
1250
|
+
|
|
696
1251
|
},
|
|
697
1252
|
|
|
1253
|
+
|
|
1254
|
+
|
|
698
1255
|
{
|
|
699
1256
|
|
|
1257
|
+
|
|
1258
|
+
|
|
700
1259
|
text: `Have you seen it anywhere?`
|
|
701
1260
|
|
|
1261
|
+
|
|
1262
|
+
|
|
702
1263
|
},
|
|
703
1264
|
|
|
1265
|
+
|
|
1266
|
+
|
|
704
1267
|
{
|
|
705
1268
|
|
|
1269
|
+
|
|
1270
|
+
|
|
706
1271
|
text: `Ok, I'm gonna go back to looking for it`,
|
|
707
1272
|
|
|
1273
|
+
|
|
1274
|
+
|
|
708
1275
|
triggeredByNext: () => {
|
|
709
1276
|
|
|
1277
|
+
|
|
1278
|
+
|
|
710
1279
|
npc.followPath(myNPC)
|
|
711
1280
|
|
|
1281
|
+
|
|
1282
|
+
|
|
712
1283
|
},
|
|
713
1284
|
|
|
1285
|
+
|
|
1286
|
+
|
|
714
1287
|
isEndOfDialog: true
|
|
715
1288
|
|
|
1289
|
+
|
|
1290
|
+
|
|
716
1291
|
}
|
|
717
1292
|
|
|
1293
|
+
|
|
1294
|
+
|
|
718
1295
|
]
|
|
719
1296
|
|
|
1297
|
+
|
|
1298
|
+
|
|
720
1299
|
```
|
|
721
1300
|
|
|
722
1301
|
|
|
723
1302
|
|
|
1303
|
+
|
|
1304
|
+
|
|
724
1305
|
### End interaction
|
|
725
1306
|
|
|
726
1307
|
|
|
727
1308
|
|
|
1309
|
+
|
|
1310
|
+
|
|
728
1311
|
The `endInteraction()` function can be used to abruptly end interactions with the NPC.
|
|
729
1312
|
|
|
730
1313
|
|
|
731
1314
|
|
|
1315
|
+
|
|
1316
|
+
|
|
732
1317
|
If applicable, it closes the dialog UI, hides speech bubbles, and makes the NPC stop rotating to face the player.
|
|
733
1318
|
|
|
734
1319
|
|
|
735
1320
|
|
|
1321
|
+
|
|
1322
|
+
|
|
736
1323
|
```ts
|
|
737
1324
|
|
|
1325
|
+
|
|
1326
|
+
|
|
738
1327
|
npc.endInteraction(myNPC)
|
|
739
1328
|
|
|
1329
|
+
|
|
1330
|
+
|
|
740
1331
|
```
|
|
741
1332
|
|
|
742
1333
|
|
|
743
1334
|
|
|
1335
|
+
|
|
1336
|
+
|
|
744
1337
|
As an alternative, you can call the `handleWalkAway()` function, which has the same effects (as long as `continueOnWalkAway` isn't set to true), but also triggers the `onWalkAway()` function.
|
|
745
1338
|
|
|
746
1339
|
|
|
747
1340
|
|
|
1341
|
+
|
|
1342
|
+
|
|
748
1343
|
## NPC Dialog Window
|
|
749
1344
|
|
|
750
1345
|
|
|
751
1346
|
|
|
1347
|
+
|
|
1348
|
+
|
|
752
1349
|
You can display an interactive dialog window to simulate a conversation with a non-player character (NPC).
|
|
753
1350
|
|
|
754
1351
|
|
|
755
1352
|
|
|
1353
|
+
|
|
1354
|
+
|
|
756
1355
|
The conversation is based on a script in JSON format. The script can include questions that can take you forward or backward, or end the conversation.
|
|
757
1356
|
|
|
758
1357
|
|
|
759
1358
|
|
|
1359
|
+
|
|
1360
|
+
|
|
760
1361
|
<img src="screenshots/NPC1.png" width="500">
|
|
761
1362
|
|
|
762
1363
|
|
|
763
1364
|
|
|
1365
|
+
|
|
1366
|
+
|
|
764
1367
|
### The NPC script
|
|
765
1368
|
|
|
766
1369
|
|
|
767
1370
|
|
|
1371
|
+
|
|
1372
|
+
|
|
768
1373
|
Each entry on the script must include at least a `text` field, but can include several more fields to further customize it.
|
|
769
1374
|
|
|
770
1375
|
|
|
771
1376
|
|
|
1377
|
+
|
|
1378
|
+
|
|
772
1379
|
Below is a minimal dialog.
|
|
773
1380
|
|
|
774
1381
|
|
|
775
1382
|
|
|
1383
|
+
|
|
1384
|
+
|
|
776
1385
|
```ts
|
|
777
1386
|
|
|
1387
|
+
|
|
1388
|
+
|
|
778
1389
|
export let NPCTalk: Dialog[] = [
|
|
779
1390
|
|
|
1391
|
+
|
|
1392
|
+
|
|
780
1393
|
{
|
|
781
1394
|
|
|
1395
|
+
|
|
1396
|
+
|
|
782
1397
|
text: 'Hi there'
|
|
783
1398
|
|
|
1399
|
+
|
|
1400
|
+
|
|
784
1401
|
},
|
|
785
1402
|
|
|
1403
|
+
|
|
1404
|
+
|
|
786
1405
|
{
|
|
787
1406
|
|
|
1407
|
+
|
|
1408
|
+
|
|
788
1409
|
text: 'It sure is nice talking to you'
|
|
789
1410
|
|
|
1411
|
+
|
|
1412
|
+
|
|
790
1413
|
},
|
|
791
1414
|
|
|
1415
|
+
|
|
1416
|
+
|
|
792
1417
|
{
|
|
793
1418
|
|
|
1419
|
+
|
|
1420
|
+
|
|
794
1421
|
text: 'I must go, my planet needs me',
|
|
795
1422
|
|
|
1423
|
+
|
|
1424
|
+
|
|
796
1425
|
isEndOfDialog: true
|
|
797
1426
|
|
|
1427
|
+
|
|
1428
|
+
|
|
798
1429
|
}
|
|
799
1430
|
|
|
1431
|
+
|
|
1432
|
+
|
|
800
1433
|
]
|
|
801
1434
|
|
|
1435
|
+
|
|
1436
|
+
|
|
802
1437
|
```
|
|
803
1438
|
|
|
804
1439
|
|
|
805
1440
|
|
|
1441
|
+
|
|
1442
|
+
|
|
806
1443
|
The player advances through each entry by clicking the mouse button. Once the last is reached, clicking again closes the window, as it's marked as `isEndOfDialog`.
|
|
807
1444
|
|
|
808
1445
|
|
|
809
1446
|
|
|
1447
|
+
|
|
1448
|
+
|
|
810
1449
|
The script must adhere to the following schema:
|
|
811
1450
|
|
|
812
1451
|
|
|
813
1452
|
|
|
1453
|
+
|
|
1454
|
+
|
|
814
1455
|
```ts
|
|
815
1456
|
|
|
1457
|
+
|
|
1458
|
+
|
|
816
1459
|
class Dialog {
|
|
817
1460
|
|
|
1461
|
+
|
|
1462
|
+
|
|
818
1463
|
text: string
|
|
819
1464
|
|
|
1465
|
+
|
|
1466
|
+
|
|
820
1467
|
fontSize?: number
|
|
821
1468
|
|
|
1469
|
+
|
|
1470
|
+
|
|
822
1471
|
typeSpeed?: number
|
|
823
1472
|
|
|
1473
|
+
|
|
1474
|
+
|
|
824
1475
|
isEndOfDialog?: boolean
|
|
825
1476
|
|
|
1477
|
+
|
|
1478
|
+
|
|
826
1479
|
isQuestion?:boolean
|
|
827
1480
|
|
|
1481
|
+
|
|
1482
|
+
|
|
828
1483
|
buttons?: ButtonData[]
|
|
829
1484
|
|
|
1485
|
+
|
|
1486
|
+
|
|
830
1487
|
audio?: string
|
|
831
1488
|
|
|
1489
|
+
|
|
1490
|
+
|
|
832
1491
|
triggeredByNext?: () => void
|
|
833
1492
|
|
|
1493
|
+
|
|
1494
|
+
|
|
834
1495
|
}
|
|
835
1496
|
|
|
1497
|
+
|
|
1498
|
+
|
|
836
1499
|
```
|
|
837
1500
|
|
|
838
1501
|
|
|
839
1502
|
|
|
1503
|
+
|
|
1504
|
+
|
|
840
1505
|
> Note: A `Dialog` object can be used as an input both for the `talk()` function (that is displayed in the UI), and the `talkBubble()` function (that is displayed in a floating bubble over the NPC). Properties marked with `*` are only applicable to UI dialogs.
|
|
841
1506
|
|
|
842
1507
|
|
|
1508
|
+
|
|
843
1509
|
|
|
844
1510
|
|
|
845
1511
|
You can set the following fields to change the appearance of a dialog:
|
|
846
1512
|
|
|
847
1513
|
|
|
848
1514
|
|
|
1515
|
+
|
|
1516
|
+
|
|
849
1517
|
- `text`: The dialog text
|
|
850
1518
|
|
|
1519
|
+
|
|
1520
|
+
|
|
851
1521
|
- `fontSize`: Size of the text
|
|
852
1522
|
|
|
853
1523
|
|
|
854
1524
|
|
|
1525
|
+
|
|
1526
|
+
|
|
855
1527
|
Other fields:
|
|
856
1528
|
|
|
1529
|
+
|
|
1530
|
+
|
|
857
1531
|
- `buttons *`: An array of buttons to use in a question entry, covered in the next section.
|
|
858
1532
|
|
|
1533
|
+
|
|
1534
|
+
|
|
859
1535
|
- `audio`: String with the path to an audio file to play once when this dialog is shown on the UI.
|
|
860
1536
|
|
|
1537
|
+
|
|
1538
|
+
|
|
861
1539
|
- `typeSpeed`: The text appears one character at a time, simulating typing. Players can click to skip the animation. Tune the speed of this typing (30 by default) to go slower or faster. Set to _-1_ to skip the animation.
|
|
862
1540
|
|
|
863
1541
|
|
|
864
1542
|
|
|
1543
|
+
|
|
1544
|
+
|
|
865
1545
|
#### Questions and conversation trees
|
|
866
1546
|
|
|
867
1547
|
|
|
868
1548
|
|
|
1549
|
+
|
|
1550
|
+
|
|
869
1551
|
The script can include questions that prompt the player to pick between two or up to four options. These questions can branch the conversation out and trigger other actions in the scene.
|
|
870
1552
|
|
|
871
1553
|
|
|
872
1554
|
|
|
1555
|
+
|
|
1556
|
+
|
|
873
1557
|
<img src="screenshots/NPC2.png" width="500">
|
|
874
1558
|
|
|
875
1559
|
|
|
876
1560
|
|
|
1561
|
+
|
|
1562
|
+
|
|
877
1563
|
> Note: Questions are only used by UI dialogs. If used in a speech bubble, questions will be displayed as regular entries with no buttons or options.
|
|
878
1564
|
|
|
879
1565
|
|
|
880
1566
|
|
|
1567
|
+
|
|
1568
|
+
|
|
881
1569
|
To make an entry a question, set the `isQuestion` field to _true_. This displays a set of buttons rather than the click icon. It also disables the click to advance to the next entry.
|
|
882
1570
|
|
|
883
1571
|
|
|
884
1572
|
|
|
1573
|
+
|
|
1574
|
+
|
|
885
1575
|
The `buttons` property of an entry contains an array of `ButtonData` objects, each one of these defines one button.
|
|
886
1576
|
|
|
887
1577
|
|
|
888
1578
|
|
|
1579
|
+
|
|
1580
|
+
|
|
889
1581
|
When on a question entry, you must provide at least the following for each button:
|
|
890
1582
|
|
|
891
1583
|
|
|
892
1584
|
|
|
1585
|
+
|
|
1586
|
+
|
|
893
1587
|
- `label`: _(string)_ The label to show on the button.
|
|
894
1588
|
|
|
1589
|
+
|
|
1590
|
+
|
|
895
1591
|
- `goToDialog`: _(number | string)_ The index or name of the next dialog entry to display when activated.
|
|
896
1592
|
|
|
897
1593
|
|
|
898
1594
|
|
|
1595
|
+
|
|
1596
|
+
|
|
899
1597
|
> TIP: It's always better to refer to an entry by name, since the array index might shift if you add more entries and it can get hard to keep track of these references.
|
|
900
1598
|
|
|
901
1599
|
|
|
902
1600
|
|
|
1601
|
+
|
|
1602
|
+
|
|
903
1603
|
You can also set the following:
|
|
904
1604
|
|
|
905
1605
|
|
|
906
1606
|
|
|
1607
|
+
|
|
1608
|
+
|
|
907
1609
|
- `triggeredActions`: _( () => void )_ An additional function to run whenever the button is activated
|
|
908
1610
|
|
|
1611
|
+
|
|
1612
|
+
|
|
909
1613
|
- `fontSize`: _(number)_ Font size of the text
|
|
910
1614
|
|
|
1615
|
+
|
|
1616
|
+
|
|
911
1617
|
- `offsetX`: _(number)_ Offset of the label on the X axis, relative to its normal position.
|
|
912
1618
|
|
|
1619
|
+
|
|
1620
|
+
|
|
913
1621
|
- `offsetY`: _(number)_ Offset of the label on the Y axis, relative to its normal position.
|
|
914
1622
|
|
|
915
1623
|
|
|
916
1624
|
|
|
1625
|
+
|
|
1626
|
+
|
|
917
1627
|
All buttons can be clicked to activate them. Additionally, the first button in the array can be activated by pressing the _E_ key. The second button in the array can be activated by pressing the _F_ key,
|
|
918
1628
|
|
|
919
1629
|
|
|
920
1630
|
|
|
1631
|
+
|
|
1632
|
+
|
|
921
1633
|
<img src="screenshots/NPC3.png" width="500">
|
|
922
1634
|
|
|
923
1635
|
|
|
924
1636
|
|
|
1637
|
+
|
|
1638
|
+
|
|
925
1639
|
```ts
|
|
926
1640
|
|
|
1641
|
+
|
|
1642
|
+
|
|
927
1643
|
export let GemsMission: Dialog[] = [
|
|
928
1644
|
|
|
1645
|
+
|
|
1646
|
+
|
|
929
1647
|
{
|
|
930
1648
|
|
|
1649
|
+
|
|
1650
|
+
|
|
931
1651
|
text: `Hello stranger`
|
|
932
1652
|
|
|
1653
|
+
|
|
1654
|
+
|
|
933
1655
|
},
|
|
934
1656
|
|
|
1657
|
+
|
|
1658
|
+
|
|
935
1659
|
{
|
|
936
1660
|
|
|
1661
|
+
|
|
1662
|
+
|
|
937
1663
|
text: `Can you help me finding my missing gems?`,
|
|
938
1664
|
|
|
1665
|
+
|
|
1666
|
+
|
|
939
1667
|
isQuestion: true,
|
|
940
1668
|
|
|
1669
|
+
|
|
1670
|
+
|
|
941
1671
|
buttons: [
|
|
942
1672
|
|
|
1673
|
+
|
|
1674
|
+
|
|
943
1675
|
{ label: `Yes!`, goToDialog: 2 },
|
|
944
1676
|
|
|
1677
|
+
|
|
1678
|
+
|
|
945
1679
|
{ label: `I'm busy`, goToDialog: 4 }
|
|
946
1680
|
|
|
1681
|
+
|
|
1682
|
+
|
|
947
1683
|
]
|
|
948
1684
|
|
|
1685
|
+
|
|
1686
|
+
|
|
949
1687
|
},
|
|
950
1688
|
|
|
1689
|
+
|
|
1690
|
+
|
|
951
1691
|
{
|
|
952
1692
|
|
|
1693
|
+
|
|
1694
|
+
|
|
953
1695
|
text: `Ok, awesome, thanks!`
|
|
954
1696
|
|
|
1697
|
+
|
|
1698
|
+
|
|
955
1699
|
},
|
|
956
1700
|
|
|
1701
|
+
|
|
1702
|
+
|
|
957
1703
|
{
|
|
958
1704
|
|
|
1705
|
+
|
|
1706
|
+
|
|
959
1707
|
text: `I need you to find 10 gems scattered around this scene, go find them!`,
|
|
960
1708
|
|
|
1709
|
+
|
|
1710
|
+
|
|
961
1711
|
isEndOfDialog: true
|
|
962
1712
|
|
|
1713
|
+
|
|
1714
|
+
|
|
963
1715
|
},
|
|
964
1716
|
|
|
1717
|
+
|
|
1718
|
+
|
|
965
1719
|
{
|
|
966
1720
|
|
|
1721
|
+
|
|
1722
|
+
|
|
967
1723
|
text: `Ok, come back soon`,
|
|
968
1724
|
|
|
1725
|
+
|
|
1726
|
+
|
|
969
1727
|
isEndOfDialog: true
|
|
970
1728
|
|
|
1729
|
+
|
|
1730
|
+
|
|
971
1731
|
}
|
|
972
1732
|
|
|
1733
|
+
|
|
1734
|
+
|
|
973
1735
|
]
|
|
974
1736
|
|
|
1737
|
+
|
|
1738
|
+
|
|
975
1739
|
```
|
|
976
1740
|
|
|
977
1741
|
|
|
978
1742
|
|
|
1743
|
+
|
|
1744
|
+
|
|
979
1745
|
#### Triggering functions from the dialog
|
|
980
1746
|
|
|
981
1747
|
|
|
982
1748
|
|
|
1749
|
+
|
|
1750
|
+
|
|
983
1751
|
You can run functions that may affect any other part of your scene. These functions get triggered when the player interacts with the dialog window, or when the NPC displays speech bubbles.
|
|
984
1752
|
|
|
985
1753
|
|
|
986
1754
|
|
|
1755
|
+
|
|
1756
|
+
|
|
987
1757
|
- `triggeredByNext`: Is executed when the player advances to the next dialog on a non-question dialog. The function also gets called if the dialog is the end of the conversation. It also gets called when a speech bubble advances to the next entry.
|
|
988
1758
|
|
|
989
1759
|
|
|
990
1760
|
|
|
1761
|
+
|
|
1762
|
+
|
|
991
1763
|
- `triggeredActions`: This property is associated to a button and is executed on a question dialog if the player activates the corresponding button. You can have up to 4 different buttons per entry, each with its own actions.
|
|
992
1764
|
|
|
993
1765
|
|
|
994
1766
|
|
|
1767
|
+
|
|
1768
|
+
|
|
995
1769
|
```ts
|
|
996
1770
|
|
|
1771
|
+
|
|
1772
|
+
|
|
997
1773
|
export let GemsMission: Dialog[] = [
|
|
998
1774
|
|
|
1775
|
+
|
|
1776
|
+
|
|
999
1777
|
{
|
|
1000
1778
|
|
|
1779
|
+
|
|
1780
|
+
|
|
1001
1781
|
text: `Hello stranger`,
|
|
1002
1782
|
|
|
1783
|
+
|
|
1784
|
+
|
|
1003
1785
|
triggeredByNext: () => {
|
|
1004
1786
|
|
|
1787
|
+
|
|
1788
|
+
|
|
1005
1789
|
// NPC plays animation to show a gem
|
|
1006
1790
|
|
|
1791
|
+
|
|
1792
|
+
|
|
1007
1793
|
}
|
|
1008
1794
|
|
|
1795
|
+
|
|
1796
|
+
|
|
1009
1797
|
},
|
|
1010
1798
|
|
|
1799
|
+
|
|
1800
|
+
|
|
1011
1801
|
{
|
|
1012
1802
|
|
|
1803
|
+
|
|
1804
|
+
|
|
1013
1805
|
text: `Can you help me finding my missing gems?`,
|
|
1014
1806
|
|
|
1807
|
+
|
|
1808
|
+
|
|
1015
1809
|
isQuestion: true,
|
|
1016
1810
|
|
|
1811
|
+
|
|
1812
|
+
|
|
1017
1813
|
buttons: [
|
|
1018
1814
|
|
|
1815
|
+
|
|
1816
|
+
|
|
1019
1817
|
{
|
|
1020
1818
|
|
|
1819
|
+
|
|
1820
|
+
|
|
1021
1821
|
label: `Yes!`,
|
|
1022
1822
|
|
|
1823
|
+
|
|
1824
|
+
|
|
1023
1825
|
goToDialog: 2,
|
|
1024
1826
|
|
|
1827
|
+
|
|
1828
|
+
|
|
1025
1829
|
triggeredActions: () => {
|
|
1026
1830
|
|
|
1831
|
+
|
|
1832
|
+
|
|
1027
1833
|
// NPC plays an animation to celebrate
|
|
1028
1834
|
|
|
1835
|
+
|
|
1836
|
+
|
|
1029
1837
|
}
|
|
1030
1838
|
|
|
1839
|
+
|
|
1840
|
+
|
|
1031
1841
|
},
|
|
1032
1842
|
|
|
1843
|
+
|
|
1844
|
+
|
|
1033
1845
|
{
|
|
1034
1846
|
|
|
1847
|
+
|
|
1848
|
+
|
|
1035
1849
|
label: `I'm busy`,
|
|
1036
1850
|
|
|
1851
|
+
|
|
1852
|
+
|
|
1037
1853
|
goToDialog: 4
|
|
1038
1854
|
|
|
1855
|
+
|
|
1856
|
+
|
|
1039
1857
|
triggeredActions: () => {
|
|
1040
1858
|
|
|
1859
|
+
|
|
1860
|
+
|
|
1041
1861
|
// NPC waves goodbye
|
|
1042
1862
|
|
|
1863
|
+
|
|
1864
|
+
|
|
1043
1865
|
}
|
|
1044
1866
|
|
|
1867
|
+
|
|
1868
|
+
|
|
1045
1869
|
},
|
|
1046
1870
|
|
|
1871
|
+
|
|
1872
|
+
|
|
1047
1873
|
]
|
|
1048
1874
|
|
|
1875
|
+
|
|
1876
|
+
|
|
1049
1877
|
},
|
|
1050
1878
|
|
|
1879
|
+
|
|
1880
|
+
|
|
1051
1881
|
{
|
|
1052
1882
|
|
|
1883
|
+
|
|
1884
|
+
|
|
1053
1885
|
text: `Ok, awesome, thanks!`,
|
|
1054
1886
|
|
|
1887
|
+
|
|
1888
|
+
|
|
1055
1889
|
},
|
|
1056
1890
|
|
|
1891
|
+
|
|
1892
|
+
|
|
1057
1893
|
{
|
|
1058
1894
|
|
|
1895
|
+
|
|
1896
|
+
|
|
1059
1897
|
text: `I need you to find 10 gems scattered around this scene, go find them!`,
|
|
1060
1898
|
|
|
1899
|
+
|
|
1900
|
+
|
|
1061
1901
|
isEndOfDialog: true
|
|
1062
1902
|
|
|
1903
|
+
|
|
1904
|
+
|
|
1063
1905
|
triggeredByNext: () => {
|
|
1064
1906
|
|
|
1907
|
+
|
|
1908
|
+
|
|
1065
1909
|
// Gems are rendered all around the scene
|
|
1066
1910
|
|
|
1911
|
+
|
|
1912
|
+
|
|
1067
1913
|
}
|
|
1068
1914
|
|
|
1915
|
+
|
|
1916
|
+
|
|
1069
1917
|
},
|
|
1070
1918
|
|
|
1919
|
+
|
|
1920
|
+
|
|
1071
1921
|
{
|
|
1072
1922
|
|
|
1923
|
+
|
|
1924
|
+
|
|
1073
1925
|
text: `Ok, come back soon`,
|
|
1074
1926
|
|
|
1927
|
+
|
|
1928
|
+
|
|
1075
1929
|
isEndOfDialog: true
|
|
1076
1930
|
|
|
1931
|
+
|
|
1932
|
+
|
|
1077
1933
|
}
|
|
1078
1934
|
|
|
1935
|
+
|
|
1936
|
+
|
|
1079
1937
|
]
|
|
1080
1938
|
|
|
1939
|
+
|
|
1940
|
+
|
|
1081
1941
|
```
|
|
1082
1942
|
|
|
1083
1943
|
|
|
1084
|
-
|
|
1944
|
+
|
|
1945
|
+
## No-NPC Dialogs
|
|
1946
|
+
|
|
1947
|
+
|
|
1085
1948
|
|
|
1086
1949
|
|
|
1087
1950
|
|
|
@@ -1089,136 +1952,217 @@ You can open a Dialog window that isn't associated with any `NPC` object in the
|
|
|
1089
1952
|
|
|
1090
1953
|
|
|
1091
1954
|
|
|
1955
|
+
|
|
1956
|
+
|
|
1092
1957
|
### The Dialog window
|
|
1093
1958
|
|
|
1094
1959
|
|
|
1095
1960
|
|
|
1961
|
+
|
|
1962
|
+
|
|
1096
1963
|
To create a new dialog window, call `createDialogWindow()` and store as a variable. This will instantiate the window but keep it hidden until you open it.
|
|
1097
1964
|
|
|
1965
|
+
|
|
1966
|
+
|
|
1098
1967
|
```ts
|
|
1099
1968
|
|
|
1969
|
+
|
|
1970
|
+
|
|
1100
1971
|
let dialogWindow = npc.createDialogWindow()
|
|
1101
1972
|
|
|
1973
|
+
|
|
1974
|
+
|
|
1102
1975
|
```
|
|
1103
1976
|
|
|
1104
|
-
|
|
1977
|
+
|
|
1978
|
+
|
|
1105
1979
|
<img src="screenshots/NPC1.png" width="500">
|
|
1106
1980
|
|
|
1107
|
-
|
|
1981
|
+
|
|
1982
|
+
|
|
1108
1983
|
When instantiating a new blank dialog, you can pass the following optional parameters:
|
|
1109
1984
|
|
|
1985
|
+
|
|
1986
|
+
|
|
1110
1987
|
|
|
1111
1988
|
- `defaultPortrait`: Sets a default portrait image to use on the left of all dialogs that don't specify an image. If a dialog has no portrait and no default is provided, no image is shown on the left. This field expects a `Portrait` object, that may include the following fields: - `path`: Path to the image file - `xOffset`: Offset on X, relative to the normal position of the portrait. - `yOffset`: Offset on Y, relative to the normal position of the portrait. - `section`: Use only a section of the image file, useful when arranging multiple icons into an image atlas. This field takes an `ImageSection` object, specifying `sourceWidth` and `sourceHeight`, and optionally also `sourceLeft` and `sourceTop`.
|
|
1112
1989
|
|
|
1990
|
+
|
|
1991
|
+
|
|
1113
1992
|
- `useDarkTheme`: Switch the style of the window to the dark theme.
|
|
1114
1993
|
|
|
1994
|
+
|
|
1995
|
+
|
|
1115
1996
|
- `sound`: Path to a sound file that will be played once for every dialog entry shown, as long as the dialog entry doesn't have its own `audio` property.
|
|
1116
1997
|
|
|
1117
1998
|
|
|
1118
1999
|
|
|
2000
|
+
|
|
2001
|
+
|
|
1119
2002
|
Once you have created a dialog window, you can open a dialog window with the `openDialogWindow()` function.
|
|
1120
2003
|
|
|
1121
2004
|
|
|
1122
2005
|
|
|
2006
|
+
|
|
2007
|
+
|
|
1123
2008
|
```ts
|
|
1124
2009
|
|
|
2010
|
+
|
|
2011
|
+
|
|
1125
2012
|
npc.openDialogWindow(dialogWindow, NPCTalk, 0)
|
|
1126
2013
|
|
|
2014
|
+
|
|
2015
|
+
|
|
1127
2016
|
```
|
|
1128
2017
|
|
|
1129
2018
|
|
|
1130
2019
|
|
|
2020
|
+
|
|
2021
|
+
|
|
1131
2022
|
When calling this function, you must specify:
|
|
1132
2023
|
|
|
1133
2024
|
|
|
1134
2025
|
|
|
2026
|
+
|
|
2027
|
+
|
|
1135
2028
|
- `NPCScript`: A JSON object composed of an array of `Dialog` objects, that includes all the dialog tree.
|
|
1136
2029
|
|
|
1137
2030
|
|
|
1138
2031
|
|
|
2032
|
+
|
|
2033
|
+
|
|
1139
2034
|
A second optional parameter is also available:
|
|
1140
2035
|
|
|
1141
2036
|
|
|
1142
2037
|
|
|
2038
|
+
|
|
2039
|
+
|
|
1143
2040
|
- `textId`: The index or `name` property of the entry to show first from the script. The first entry is 0.
|
|
1144
2041
|
|
|
1145
2042
|
|
|
1146
2043
|
|
|
2044
|
+
|
|
2045
|
+
|
|
1147
2046
|
> TIP: It's always better to refer to an entry by name, since the array index might shift if you add more entries and it can get hard to keep track of these references.
|
|
1148
2047
|
|
|
1149
2048
|
|
|
1150
2049
|
|
|
2050
|
+
|
|
2051
|
+
|
|
1151
2052
|
Close a dialog window at any time by calling the `closeDialogWindow()` function.
|
|
1152
2053
|
|
|
1153
2054
|
|
|
1154
2055
|
|
|
2056
|
+
|
|
2057
|
+
|
|
1155
2058
|
```ts
|
|
1156
2059
|
|
|
2060
|
+
|
|
2061
|
+
|
|
1157
2062
|
npc.closeDialogWindow(dialogWindow)
|
|
1158
2063
|
|
|
2064
|
+
|
|
2065
|
+
|
|
1159
2066
|
```
|
|
1160
2067
|
|
|
1161
2068
|
|
|
1162
2069
|
|
|
2070
|
+
|
|
2071
|
+
|
|
1163
2072
|
For details on how to construct the dialog tree, see the sections above. The required `NPCScript` by the `DialogWindow` has exactly the same characteristics as the one used on the `NPC` object when calling the `talk()` function.
|
|
1164
2073
|
|
|
1165
2074
|
|
|
1166
2075
|
|
|
2076
|
+
|
|
2077
|
+
|
|
1167
2078
|
---
|
|
1168
2079
|
|
|
2080
|
+
|
|
2081
|
+
|
|
1169
2082
|
## Contribute
|
|
1170
2083
|
|
|
1171
2084
|
|
|
1172
2085
|
|
|
2086
|
+
|
|
2087
|
+
|
|
1173
2088
|
In order to test changes made to this repository in active scenes, do the following:
|
|
1174
2089
|
|
|
1175
2090
|
|
|
1176
2091
|
|
|
2092
|
+
|
|
2093
|
+
|
|
1177
2094
|
1. Run `npm run build` for the internal files of the library to be generated
|
|
1178
2095
|
|
|
2096
|
+
|
|
2097
|
+
|
|
1179
2098
|
2. Run `npm run link` on this repository
|
|
1180
2099
|
|
|
2100
|
+
|
|
2101
|
+
|
|
1181
2102
|
3. On a new Decentraland scene, import this library as you normally would and include the tests you need
|
|
1182
2103
|
|
|
2104
|
+
|
|
2105
|
+
|
|
1183
2106
|
4. On the scene directory, run `npm link dcl-npc-toolkit`
|
|
1184
2107
|
|
|
1185
2108
|
|
|
1186
2109
|
|
|
2110
|
+
|
|
2111
|
+
|
|
1187
2112
|
> Note: When done testing, run `npm unlink` on both folders, so that the scene stops using the local version of the library.
|
|
1188
2113
|
|
|
1189
2114
|
|
|
2115
|
+
|
|
1190
2116
|
|
|
1191
2117
|
|
|
1192
2118
|
## CI/CD
|
|
1193
2119
|
|
|
1194
2120
|
|
|
1195
2121
|
|
|
2122
|
+
|
|
2123
|
+
|
|
1196
2124
|
This repository uses `semantic-release` to automatically release new versions of the package to NPM.
|
|
1197
2125
|
|
|
1198
2126
|
|
|
1199
2127
|
|
|
2128
|
+
|
|
2129
|
+
|
|
1200
2130
|
Use the following convention for commit names:
|
|
1201
2131
|
|
|
1202
2132
|
|
|
1203
2133
|
|
|
2134
|
+
|
|
2135
|
+
|
|
1204
2136
|
`feat: something`: Minor release, every time you add a feature or enhancement that doesn’t break the api.
|
|
1205
2137
|
|
|
1206
2138
|
|
|
1207
2139
|
|
|
2140
|
+
|
|
2141
|
+
|
|
1208
2142
|
`fix: something`: Bug fixing / patch
|
|
1209
2143
|
|
|
1210
2144
|
|
|
1211
2145
|
|
|
2146
|
+
|
|
2147
|
+
|
|
1212
2148
|
`chore: something`: Anything that doesn't require a release to npm, like changing the readme. Updating a dependency is **not** a chore if it fixes a bug or a vulnerability, that's a `fix`.
|
|
1213
2149
|
|
|
1214
2150
|
|
|
1215
2151
|
|
|
2152
|
+
|
|
2153
|
+
|
|
1216
2154
|
If you break the API of the library, you need to do a major release, and that's done a different way. You need to add a second comment that starts with `BREAKING CHANGE`, like:
|
|
1217
2155
|
|
|
1218
2156
|
|
|
1219
2157
|
|
|
2158
|
+
|
|
2159
|
+
|
|
1220
2160
|
```
|
|
1221
2161
|
|
|
2162
|
+
|
|
2163
|
+
|
|
1222
2164
|
commit -m "feat: changed the signature of a method" -m "BREAKING CHANGE: this commit breaks the API, changing foo(arg1) to foo(arg1, arg2)"
|
|
1223
2165
|
|
|
2166
|
+
|
|
2167
|
+
|
|
1224
2168
|
```
|