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