webtalekit-alpha 0.2.10

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.
@@ -0,0 +1,654 @@
1
+ import { Drawer } from './drawer'
2
+ import { ScenarioManager } from './scenarioManager'
3
+ import { ImageObject } from '../resource/ImageObject'
4
+ import { ResourceManager } from './resourceManager'
5
+ import { SoundObject } from '../resource/soundObject'
6
+ import engineConfig from '../../engineConfig.json'
7
+ import { outputLog } from '../utils/logger'
8
+ import { sleep } from '../utils/waitUtil'
9
+
10
+ export class Core {
11
+ bgm = null
12
+ isAuto = false
13
+ isNext = false
14
+ isSkip = false
15
+ onNextHandler = null
16
+ sceneFile = {}
17
+ sceneConfig = {}
18
+ commandList = {
19
+ text: this.textHandler,
20
+ choice: this.choiceHandler,
21
+ show: this.showHandler,
22
+ newpage: this.newpageHandler,
23
+ hide: this.hideHandler,
24
+ jump: this.jumpHandler,
25
+ sound: this.soundHandler,
26
+ say: this.sayHandler,
27
+ if: this.ifHandler,
28
+ call: this.callHandler,
29
+ moveto: this.moveToHandler,
30
+ route: this.routeHandler,
31
+ wait: this.waitHandler,
32
+ }
33
+
34
+ constructor() {
35
+ this.gameContainer = document.getElementById('gameContainer')
36
+ // Drawerの初期化(canvasタグのサイズを設定する)
37
+ this.drawer = new Drawer(this.gameContainer)
38
+ // ScenarioManagerの初期化(変数の初期値設定)
39
+ this.scenarioManager = new ScenarioManager()
40
+ // ResourceManagerの初期化(引数にconfigを渡して、リソース管理配列を作る)
41
+ this.resourceManager = new ResourceManager(import(/* webpackIgnore: true */ '/src/resource/config.js')) // webpackIgnoreでバンドルを無視する
42
+ this.displayedImages = {}
43
+ this.usedSounds = {}
44
+ }
45
+
46
+ async start(initScene) {
47
+ outputLog('call', 'debug', initScene)
48
+ // TODO: ブラウザ用のビルドの場合は、最初にクリックしてもらう
49
+ // titleタグの内容を書き換える
50
+ document.title = engineConfig.title
51
+ // sceneファイルを読み込む
52
+ await this.loadScene(initScene || 'title')
53
+ // 画面を表示する
54
+ await this.loadScreen(this.sceneConfig)
55
+ // 入力イベントを設定する
56
+ document.querySelector('#gameContainer').addEventListener('keydown', (e) => {
57
+ if (e.key === 'Enter') {
58
+ this.onNextHandler()
59
+ } else if (e.key === 'Control') {
60
+ this.drawer.isSkip = true
61
+ this.isNext = true
62
+ }
63
+ })
64
+ document.querySelector('#gameContainer').addEventListener('keyup', (e) => {
65
+ if (e.key === 'Control') {
66
+ this.drawer.isSkip = true
67
+ this.isNext = false
68
+ }
69
+ })
70
+ document.querySelector('#gameContainer').addEventListener('click', (e) => {
71
+ this.onNextHandler()
72
+ })
73
+
74
+ await this.textHandler('タップでスタート')
75
+ // BGMを再生する
76
+ this.bgm.play(true)
77
+ // シナリオを実行する
78
+ while (this.scenarioManager.hasNext()) {
79
+ await this.runScenario()
80
+ }
81
+ }
82
+
83
+ async loadScene(sceneFileName) {
84
+ outputLog('call', 'debug', sceneFileName)
85
+ // sceneファイルを読み込む
86
+ this.sceneFile = await import(/* webpackChunkName: "[request]" */ `/src/js/${sceneFileName}.js`)
87
+ // sceneファイルの初期化処理を実行
88
+ if (this.sceneFile.init) {
89
+ this.sceneFile.init(this.getAPIForScript())
90
+ }
91
+ // シナリオの進行状況を初期化
92
+ this.scenarioManager.setScenario(this.sceneFile.scenario, sceneFileName)
93
+ this.sceneConfig = { ...this.sceneConfig, ...this.sceneFile.sceneConfig }
94
+ outputLog('sceneFile', 'debug', this.sceneFile)
95
+ }
96
+
97
+ async loadScreen(sceneConfig) {
98
+ outputLog('call', 'debug', sceneConfig)
99
+ // sceneConfig.templateを読み込んで、HTMLを表示する
100
+ const htmlString = await (await fetch(sceneConfig.template)).text()
101
+ // 読み込んだhtmlからIDにmainを持つdivタグとStyleタグ以下を取り出して、gameContainerに表示する
102
+ var parser = new DOMParser()
103
+ var doc = parser.parseFromString(htmlString, 'text/html')
104
+ this.gameContainer.innerHTML = doc.getElementById('main').innerHTML
105
+ // 既に読み込んだスタイルシートがあったら削除する
106
+ const styleTags = document.head.getElementsByTagName('style')
107
+ for (const styleTag of styleTags) {
108
+ document.head.removeChild(styleTag)
109
+ }
110
+
111
+ // Styleタグを取り出して、headタグに追加する
112
+ const styleElement = doc.head.getElementsByTagName('style')[0]
113
+ document.head.appendChild(styleElement)
114
+ // ゲーム進行用に必要な情報をセットする
115
+ this.drawer.setScreen(this.gameContainer, engineConfig.resolution)
116
+ // シナリオの進行状況を保存
117
+ this.scenarioManager.progress.currentScene = sceneConfig.name
118
+ // 背景画像を表示する
119
+ const background = await new ImageObject().setImageAsync(sceneConfig.background)
120
+ this.displayedImages['background'] = {
121
+ image: background,
122
+ size: {
123
+ width: this.gameContainer.clientWidth,
124
+ height: this.gameContainer.clientHeight,
125
+ },
126
+ }
127
+ this.drawer.show(this.displayedImages)
128
+ this.bgm = await new SoundObject().setAudioAsync(sceneConfig.bgm)
129
+ }
130
+
131
+ async runScenario() {
132
+ outputLog('call index:', 'debug', this.scenarioManager.getIndex())
133
+ let scenarioObject = this.scenarioManager.next()
134
+ if (!scenarioObject) {
135
+ return
136
+ }
137
+ outputLog('scenarioObject', 'debug', scenarioObject)
138
+ // シナリオオブジェクトのtypeプロパティに応じて、対応する関数を実行する
139
+ const boundFunction = this.commandList[scenarioObject.type || 'text'].bind(this)
140
+ outputLog(`boundFunction:${boundFunction.name.split(' ')[1]}`, 'debug', scenarioObject)
141
+ scenarioObject = await this.httpHandler(scenarioObject)
142
+ await boundFunction(scenarioObject)
143
+ }
144
+
145
+ async textHandler(scenarioObject) {
146
+ outputLog('textHandler:line', 'debug', scenarioObject)
147
+ // 文章だけの場合は、contentプロパティに配列として設定する
148
+ if (typeof scenarioObject === 'string') scenarioObject = { content: [scenarioObject] }
149
+ // httpレスポンスがある場合は、list.contentに追加して、表示対象に加える
150
+ if (scenarioObject.then || scenarioObject.error) {
151
+ scenarioObject.content = scenarioObject.content.concat(scenarioObject.then || scenarioObject.error)
152
+ }
153
+ outputLog('call', 'debug', scenarioObject)
154
+
155
+ // 名前が設定されている場合は、名前を表示する
156
+ if (scenarioObject.name) {
157
+ this.drawer.drawName(scenarioObject.name)
158
+ } else {
159
+ this.drawer.drawName('')
160
+ }
161
+
162
+ //prettier-ignore
163
+ this.onNextHandler = () => { this.drawer.isSkip = true }
164
+ this.drawer.clearText() // テキスト表示領域をクリア
165
+ // 表示する文章を1行ずつ表示する
166
+ for (const text of scenarioObject.content) {
167
+ outputLog('textSpeed', 'debug', text)
168
+ if (typeof text === 'string') {
169
+ await this.drawer.drawText(this.expandVariable(text), scenarioObject.speed || 25)
170
+ } else {
171
+ if (text.type === 'br' || text.type === 'wait') {
172
+ outputLog('text', 'debug', text)
173
+ if (text.type === 'br') this.drawer.drawLineBreak()
174
+ if (!text.nw) {
175
+ await this.waitHandler({ wait: text.time })
176
+ }
177
+ } else {
178
+ const container = this.drawer.createDecoratedElement(text)
179
+ await this.drawer.drawText(this.expandVariable(text.content[0]), text.speed || 25, container)
180
+ }
181
+ }
182
+ }
183
+ await this.waitHandler({ wait: scenarioObject.time })
184
+ this.drawer.isSkip = false
185
+ this.scenarioManager.setHistory(scenarioObject.content)
186
+ }
187
+
188
+ expandVariable(text) {
189
+ outputLog('call', 'debug', text)
190
+ if (typeof text !== 'string') return text
191
+ return text.replace(/{{([^{}]+)}}/g, (match) => {
192
+ const expr = match.slice(2, -2)
193
+ const returnValue = this.executeCode(`return ${expr}`)
194
+ return typeof returnValue == 'object' ? JSON.stringify(returnValue) : returnValue
195
+ })
196
+ }
197
+
198
+ async waitHandler(line) {
199
+ // line.timeがある場合、line.waitに代入する
200
+ if (line.time) line.wait = line.time
201
+ outputLog('call', 'debug', line)
202
+ //prettier-ignore
203
+ this.onNextHandler = () => { this.isNext = true }
204
+ outputLog('wait type', 'debug', typeof line.wait)
205
+
206
+ // line.waitが数値に変換可能な文字列の場合、数値に変換
207
+ if (typeof line.wait === 'string' && !isNaN(Number(line.wait))) {
208
+ line.wait = Number(line.wait)
209
+ }
210
+ if (typeof line.wait === 'number') {
211
+ outputLog('wait number', 'debug', line.wait)
212
+ if (line.wait > 0 || this.isAuto) {
213
+ const waitTime = line.wait || 1500
214
+ // 指定された時間だけ待機
215
+ await sleep(waitTime)
216
+ }
217
+ } else {
218
+ // 改行ごとに入力待ち
219
+ await this.clickWait()
220
+ }
221
+ }
222
+
223
+ // クリック待ち処理
224
+ async clickWait() {
225
+ outputLog('call', 'debug')
226
+ this.drawer.setVisibility('#waitCircle', true)
227
+ return new Promise((resolve) => {
228
+ const intervalId = setInterval(() => {
229
+ if (this.isNext) {
230
+ this.drawer.setVisibility('#waitCircle', false)
231
+ clearInterval(intervalId)
232
+ this.isNext = false
233
+ resolve(null)
234
+ }
235
+ }, 500)
236
+ })
237
+ }
238
+
239
+ async sayHandler(line) {
240
+ outputLog('call', 'debug', line)
241
+ // say(name:string, pattern: string, voice: {playの引数}, ...text)
242
+ if (line.voice) await this.soundHandler({ path: line.voice, play: undefined })
243
+ await this.textHandler({ content: line.content, name: line.name, speed: line.speed || 25 })
244
+ this.scenarioManager.setHistory(line)
245
+ }
246
+
247
+ async choiceHandler(line) {
248
+ outputLog('call', 'debug', line)
249
+ document.querySelector('#interactiveView').style.visibility = 'visible'
250
+ if (line.prompt) this.textHandler(line.prompt)
251
+ // ムスタッシュ構文があるときは、変数の展開
252
+ line.content.forEach((choice) => {
253
+ choice.label = this.expandVariable(choice.label)
254
+ })
255
+ const { selectId, onSelect: selectHandler } = await this.drawer.drawChoices(line)
256
+ if (selectHandler !== undefined) {
257
+ this.scenarioManager.addScenario(selectHandler)
258
+ }
259
+ this.scenarioManager.setHistory({ line, ...selectId })
260
+ document.querySelector('#interactiveView').style.visibility = 'hidden'
261
+ }
262
+
263
+ jumpHandler(line) {
264
+ outputLog('call:', 'debug', line.index)
265
+ // ジャンプ先が現在の行より小さいときは、今の行とジャンプ先の行の間で、sub=falseの行を抽出して、scenarioManagerに追加する
266
+ if (line.index < this.scenarioManager.getIndex()) {
267
+ // scenarioManagerからシナリオを取得
268
+ const scenario = this.scenarioManager.getScenario()
269
+ // 結合用に、ジャンプ先までのインデックスを取得
270
+ const noEditScenarioList = {
271
+ before: scenario.slice(0, line.index),
272
+ after: scenario.slice(this.scenarioManager.getIndex()),
273
+ }
274
+ outputLog('noEditScenarioList', 'debug', noEditScenarioList)
275
+ // ジャンプ先のインデックスまでのシナリオを取得
276
+ const scenarioList = scenario.slice(line.index, this.scenarioManager.getIndex())
277
+ outputLog('scenarioList', 'debug', scenarioList)
278
+ // sub=falseの行だけを取得
279
+ const subFalseScenario = scenarioList.filter((line) => !line.sub)
280
+ outputLog('subFalseScenario', 'debug', subFalseScenario)
281
+ // scenarioManagerに追加
282
+ this.scenarioManager.setScenario([...noEditScenarioList.before, ...subFalseScenario, ...noEditScenarioList.after])
283
+ outputLog('scenarioManager', 'debug', this.scenarioManager.getScenario())
284
+ }
285
+ this.newpageHandler()
286
+ this.scenarioManager.setIndex(Number(line.index))
287
+ }
288
+
289
+ async showHandler(line) {
290
+ outputLog('line', 'debug', line)
291
+ // ムスタッシュ構文があるときは、変数の展開
292
+ Object.keys(line).forEach((item) => {
293
+ line[item] = this.expandVariable(line[item])
294
+ })
295
+ // 表示する画像の情報を管理オブジェクトに追加
296
+ const modeList = { bg: 'background', cutin: '', chara: '', cg: 'background', effect: 'effect' }
297
+ const key = Object.keys(modeList).includes(line.mode) ? modeList[line.mode] : line.name || line.src.split('/').pop()
298
+ const baseLine = engineConfig.resolution.height / 2
299
+ const centerPoint = {
300
+ left: { x: engineConfig.resolution.width * 0.25, y: baseLine },
301
+ center: { x: engineConfig.resolution.width * 0.5, y: baseLine },
302
+ right: { x: engineConfig.resolution.width * 0.75, y: baseLine },
303
+ }
304
+ line.src = this.expandVariable(line.src) || line.name
305
+
306
+ const image = await this.getImageObject(line)
307
+ // 画像の表示位置を設定
308
+ let position = { x: line.x || 0, y: line.y || 0 }
309
+ // prettier-ignore
310
+ let size = line.width && line.height ? { width: line.width, height: line.height } : { width: image.getSize().width, height: image.getSize().height }
311
+
312
+ // line.modeが'cutin'の場合、center:middleのエイリアスを強制する
313
+ if (line.mode === 'cutin') {
314
+ line.pos = 'center:middle'
315
+ }
316
+
317
+ if (line.mode === 'cg') {
318
+ this.tempImages = { ...this.displayedImages }
319
+ this.displayedImages = { background: line.src }
320
+ size = { width: engineConfig.resolution.width, height: engineConfig.resolution.height }
321
+ }
322
+
323
+ if (line.pos) {
324
+ const pos = line.pos.split(':')
325
+ const baseLines = {
326
+ top: 0 + size.height,
327
+ middle: engineConfig.resolution.height / 2,
328
+ bottom: engineConfig.resolution.height - size.height,
329
+ }
330
+ // エイリアスが設定されている場合、画像の中心点を求めて、画像の表示位置を設定する
331
+ position.x = centerPoint[pos[0]].x - size.width / 2
332
+ if (pos[1] === 'middle') {
333
+ position.y = baseLines[pos[1]] - size.width / 2
334
+ } else if (pos[1]) {
335
+ position.y = baseLines[pos[1]]
336
+ } else {
337
+ position.y = baseLine / 2
338
+ }
339
+ }
340
+ this.displayedImages[key] = {
341
+ image,
342
+ pos: position,
343
+ size: size,
344
+ look: line.look,
345
+ entry: line.entry,
346
+ }
347
+
348
+ outputLog('displayedImages', 'debug', this.displayedImages[key])
349
+ if (line.sepia) this.displayedImages[key].image.setSepia(line.sepia)
350
+ if (line.mono) this.displayedImages[key].image.setMonochrome(line.mono)
351
+ if (line.blur) this.displayedImages[key].image.setBlur(line.blur)
352
+ if (line.opacity) this.displayedImages[key].image.setOpacity(line.opacity)
353
+
354
+ if (line.transition === 'fade') {
355
+ // フェードイン効果で表示
356
+ await this.drawer.fadeIn(line.duration || 2000, await this.getImageObject(line), {
357
+ pos: position,
358
+ size,
359
+ look: line.look,
360
+ entry: line.entry,
361
+ })
362
+ this.drawer.show(this.displayedImages)
363
+ } else {
364
+ // 通常の表示処理
365
+ this.drawer.show(this.displayedImages)
366
+ }
367
+ outputLog('this.displayedImages', 'debug', this.displayedImages)
368
+ }
369
+
370
+ async hideHandler(line) {
371
+ outputLog('call', 'debug', line)
372
+ const targetImage = this.displayedImages[line.name]
373
+ if (line.mode === 'cg') {
374
+ this.displayedImages = { ...this.tempImages }
375
+ this.tempImages = {}
376
+ } else {
377
+ delete this.displayedImages[line.name]
378
+ }
379
+ this.drawer.show(this.displayedImages)
380
+ if (line.transition === 'fade') {
381
+ // フェードアウト効果で非表示
382
+ await this.drawer.fadeOut(line.duration || 1000, targetImage.image, {
383
+ pos: targetImage.pos,
384
+ size: targetImage.size,
385
+ look: targetImage.look,
386
+ })
387
+ }
388
+ }
389
+
390
+ async moveToHandler(line) {
391
+ outputLog('moveToHandler:line', 'debug', line)
392
+ const key = line.name
393
+ outputLog('moveToHandler:displayedImages', 'debug', this.displayedImages)
394
+ await this.drawer.moveTo(key, this.displayedImages, { x: line.x, y: line.y }, line.duration | 1)
395
+ }
396
+
397
+ async getImageObject(line) {
398
+ outputLog('call', 'debug', line)
399
+ const name = line.name || line.src.split('/').pop()
400
+ let image
401
+ // 既にインスタンスがある場合は、それを使う
402
+ if (Object.hasOwn(this.displayedImages, name)) {
403
+ const targetImage = this.displayedImages[name]
404
+ const imageObject = targetImage ? targetImage.image : new ImageObject()
405
+ image = await imageObject.setImageAsync(line.src)
406
+ } else {
407
+ outputLog('new ImageObject', 'debug')
408
+ image = await new ImageObject().setImageAsync(line.src)
409
+ }
410
+ return image
411
+ }
412
+
413
+ async soundHandler(line) {
414
+ outputLog('call', 'debug', line)
415
+ let soundObject = null
416
+ if (line.mode === 'bgm') {
417
+ if (this.bgm.isPlaying) {
418
+ this.bgm.stop()
419
+ }
420
+ soundObject = await this.getSoundObject(line)
421
+ this.bgm = soundObject
422
+ } else {
423
+ // soundObjectを作成
424
+ soundObject = await this.getSoundObject(line)
425
+ // playプロパティが存在する場合は、再生する
426
+ }
427
+ if ('play' in line) {
428
+ 'loop' in line ? soundObject.play(true) : soundObject.play()
429
+ } else if ('stop' in line) {
430
+ soundObject.stop()
431
+ } else if ('pause' in line) {
432
+ soundObject.pause()
433
+ }
434
+ // soundObjectを管理オブジェクトに追加
435
+ const key = line.name || line.src.split('/').pop()
436
+ this.usedSounds[key] = {
437
+ audio: soundObject,
438
+ }
439
+ }
440
+
441
+ async getSoundObject(line) {
442
+ outputLog('call', 'debug', line)
443
+ const name = line.name || line.src.split('/').pop()
444
+ let resource
445
+ if (Object.hasOwn(this.usedSounds, name)) {
446
+ const targetResource = this.usedSounds[name]
447
+ const soundObject = targetResource ? targetResource.audio : new SoundObject()
448
+ resource = await soundObject.setAudioAsync(line.src)
449
+ } else {
450
+ resource = await new SoundObject().setAudioAsync(line.src)
451
+ }
452
+ return resource
453
+ }
454
+
455
+ newpageHandler() {
456
+ outputLog('call', 'debug')
457
+ this.displayedImages = {
458
+ background: {
459
+ image: this.getBackground(),
460
+ size: {
461
+ width: this.gameContainer.clientWidth,
462
+ height: this.gameContainer.clientHeight,
463
+ },
464
+ },
465
+ }
466
+ this.drawer.clear()
467
+ this.drawer.show(this.displayedImages)
468
+ }
469
+
470
+ async ifHandler(line) {
471
+ outputLog('call', 'debug', line)
472
+ const isTrue = this.executeCode(`return ${line.condition}`)
473
+ outputLog(`${isTrue}`, 'debug')
474
+ const appendScenario = isTrue ? line.content[0].content : line.content[1].content
475
+ outputLog('', 'debug', appendScenario)
476
+ this.scenarioManager.addScenario(appendScenario)
477
+ }
478
+
479
+ async routeHandler(line) {
480
+ outputLog('call', 'debug', line)
481
+ if (this.bgm.isPlaying) {
482
+ this.bgm.stop()
483
+ this.bgm = null
484
+ }
485
+ this.newpageHandler()
486
+ if (this.sceneFile.cleanUp) {
487
+ // 終了処理を実行する
488
+ this.sceneFile.cleanUp()
489
+ }
490
+ // sceneファイルを読み込む
491
+ await this.loadScene(line.to)
492
+ // 画面を表示する
493
+ await this.loadScreen(this.sceneConfig)
494
+ // BGMを再生する
495
+ this.bgm.play(true)
496
+ }
497
+
498
+ // Sceneファイルに、ビルド時に実行処理を追加して、そこに処理をお願いしたほうがいいかも?
499
+ callHandler(line) {
500
+ outputLog('call', 'debug', line)
501
+ this.executeCode(line.method)
502
+ }
503
+
504
+ async httpHandler(line) {
505
+ if (!(line.get || line.post || line.put || line.delete)) {
506
+ return line
507
+ }
508
+ outputLog('call', 'debug', line)
509
+ // progress属性を処理する
510
+ // prettier-ignore
511
+ const progressText = line.content.filter((content) => content.type === 'progress')[0]
512
+ if (progressText) {
513
+ await this.textHandler({ content: [progressText.content][0], wait: 0 })
514
+ }
515
+ // get,post,put,delete属性を処理する
516
+ const headers = line.content
517
+ .filter((content) => content.type === 'header')[0]
518
+ .content.reduce(
519
+ (acc, header) => ({
520
+ ...acc,
521
+ [header.type]: header.content,
522
+ }),
523
+ {},
524
+ )
525
+ const body = line.content
526
+ .filter((content) => content.type === 'data')[0]
527
+ .content.reduce(
528
+ (acc, header) => ({
529
+ ...acc,
530
+ [header.type]: header.content,
531
+ }),
532
+ {},
533
+ )
534
+ outputLog('headers', 'debug', headers)
535
+ outputLog('body', 'debug', body)
536
+ const response = await fetch(line.get || line.post || line.put || line.delete, {
537
+ method: line.get ? 'GET' : line.post ? 'POST' : line.put ? 'PUT' : 'DELETE',
538
+ headers: headers,
539
+ body: JSON.stringify(body),
540
+ })
541
+ if (response.ok) {
542
+ const json = await response.json()
543
+ this.sceneFile.res = json
544
+ outputLog('res', 'debug', json)
545
+ line.then = line.content.filter((content) => content.type === 'then')[0].content
546
+ } else {
547
+ this.sceneFile.res = json
548
+ line.error = line.content.filter((content) => content.type === 'error')[0].content
549
+ }
550
+ if (line.content) {
551
+ line.content = line.content.filter(
552
+ (content) =>
553
+ !(
554
+ content.type &&
555
+ (content.type === 'header' ||
556
+ content.type === 'data' ||
557
+ content.type === 'then' ||
558
+ content.type === 'error' ||
559
+ content.type === 'progress')
560
+ ),
561
+ )
562
+ }
563
+ return line
564
+ }
565
+
566
+ setBackground(image) {
567
+ this.displayedImages['background'] = image
568
+ }
569
+
570
+ getBackground() {
571
+ return this.displayedImages['background'].image
572
+ }
573
+
574
+ executeCode(code) {
575
+ outputLog('call', 'debug', code)
576
+ try {
577
+ const context = { ...this.sceneFile }
578
+ const func = new Function(...Object.keys(context), code)
579
+ return func.apply(null, Object.values(context))
580
+ } catch (error) {
581
+ console.error('Error executing code:', error)
582
+ }
583
+ }
584
+
585
+ // Scriptから安全にアクセスできるメソッドを定義
586
+ getAPIForScript() {
587
+ return {
588
+ drawer: {
589
+ drawName: this.drawer.drawName.bind(this.drawer),
590
+ drawText: this.drawer.drawText.bind(this.drawer),
591
+ drawChoices: this.drawer.drawChoices.bind(this.drawer),
592
+ clearText: this.drawer.clearText.bind(this.drawer),
593
+ show: this.drawer.show.bind(this.drawer),
594
+ moveTo: this.drawer.moveTo.bind(this.drawer),
595
+ fadeIn: this.drawer.fadeIn.bind(this.drawer),
596
+ fadeOut: this.drawer.fadeOut.bind(this.drawer),
597
+ },
598
+ sound: {
599
+ play: this.soundHandler.bind(this),
600
+ stop: (name) => this.soundHandler({ name, stop: true }),
601
+ pause: (name) => this.soundHandler({ name, pause: true }),
602
+ },
603
+ scenario: {
604
+ jump: this.jumpHandler.bind(this),
605
+ addScene: this.scenarioManager.addScenario.bind(this.scenarioManager),
606
+ getProgress: () => this.scenarioManager.progress,
607
+ setProgress: (progress) => (this.scenarioManager.progress = progress),
608
+ getIndex: () => this.scenarioManager.getIndex(),
609
+ setIndex: (index) => this.scenarioManager.setIndex(index),
610
+ hasNext: () => this.scenarioManager.hasNext(),
611
+ next: () => this.scenarioManager.next(),
612
+ getHistory: () => this.scenarioManager.getHistory(),
613
+ setHistory: (history) => this.scenarioManager.setHistory(history),
614
+ setScenario: (scenario) => this.scenarioManager.setScenario(scenario),
615
+ getScenario: () => this.scenarioManager.getScenario(),
616
+ getSceneName: () => this.scenarioManager.progress.currentScene,
617
+ setScreenName: (name) => (this.sceneConfig.name = name),
618
+ },
619
+ images: {
620
+ get: this.getImageObject.bind(this),
621
+ getAll: () => this.displayedImages,
622
+ set: (name, image) => (this.displayedImages[name] = image),
623
+ delete: (name) => delete this.displayedImages[name],
624
+ },
625
+ sounds: {
626
+ get: (name) => this.usedSounds[name],
627
+ getAll: () => this.usedSounds,
628
+ set: (name, sound) => (this.usedSounds[name] = sound),
629
+ delete: (name) => delete this.usedSounds[name],
630
+ load: this.getSoundObject.bind(this),
631
+ },
632
+ background: {
633
+ set: this.setBackground.bind(this),
634
+ get: this.getBackground.bind(this),
635
+ },
636
+ wait: this.waitHandler.bind(this),
637
+ clickWait: this.clickWait.bind(this),
638
+ core: {
639
+ text: this.textHandler.bind(this),
640
+ choice: this.choiceHandler.bind(this),
641
+ show: this.showHandler.bind(this),
642
+ newpage: this.newpageHandler.bind(this),
643
+ hide: this.hideHandler.bind(this),
644
+ jump: this.jumpHandler.bind(this),
645
+ sound: this.soundHandler.bind(this),
646
+ say: this.sayHandler.bind(this),
647
+ if: this.ifHandler.bind(this),
648
+ moveto: this.moveToHandler.bind(this),
649
+ route: this.routeHandler.bind(this),
650
+ wait: this.waitHandler.bind(this),
651
+ },
652
+ }
653
+ }
654
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResourceManager = void 0;
4
+ var ResourceManager = /** @class */ (function () {
5
+ function ResourceManager() {
6
+ this.resourceMap = {}; // リソースを管理するオブジェクト
7
+ }
8
+ // リソースを追加または更新
9
+ ResourceManager.prototype.addResource = function (name, path) {
10
+ this.resourceMap[name] = path;
11
+ };
12
+ // リソースのパスを取得
13
+ ResourceManager.prototype.getResourcePath = function (name) {
14
+ return this.resourceMap[name];
15
+ };
16
+ return ResourceManager;
17
+ }());
18
+ exports.ResourceManager = ResourceManager;
19
+ //# sourceMappingURL=resourceManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceManager.js","sourceRoot":"","sources":["../../../src/core/resourceManager.ts"],"names":[],"mappings":";;;AAAA;IAGE;QACE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,kBAAkB;IAC3C,CAAC;IAED,eAAe;IACf,qCAAW,GAAX,UAAY,IAAY,EAAE,IAAY;QACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,CAAC;IAED,aAAa;IACb,yCAAe,GAAf,UAAgB,IAAY;QAC1B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IACH,sBAAC;AAAD,CAAC,AAhBD,IAgBC;AAhBY,0CAAe"}