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