vimp-engine 0.32.0 → 0.32.2
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/core/Cargo.toml +1 -1
- package/package.json +1 -1
- package/src/client/SoundManager.js +47 -6
package/core/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "vimp-engine-core"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.14.1"
|
|
4
4
|
edition = "2024"
|
|
5
5
|
description = "VIMP — движковый каркас симуляции (физика, карта, снапшот-фрейминг, интерполяция/предикт/raycast-примитивы, нав-утилиты). Без wasm-bindgen — обёртки для WASM-ABI собирает game-crate."
|
|
6
6
|
license = "MIT"
|
package/package.json
CHANGED
|
@@ -43,6 +43,13 @@ export default class SoundManager {
|
|
|
43
43
|
// pannerAttr ставится один раз на экземпляр, а не каждый кадр
|
|
44
44
|
this._equalPowerIds = new Set();
|
|
45
45
|
|
|
46
|
+
// экземпляры, у которых PannerNode УЖЕ создан. Howler создаёт узел
|
|
47
|
+
// лениво — на первом pos()/pannerAttr(id) — и заканчивает создание
|
|
48
|
+
// парой pause()/play() (setupPanner в howler.js), то есть щелчком.
|
|
49
|
+
// Пока источник стоит в точке слушателя, паннер не нужен вовсе:
|
|
50
|
+
// сигнал идёт прямо в gain, сохраняя стерео сэмпла
|
|
51
|
+
this._pannedIds = new Set();
|
|
52
|
+
|
|
46
53
|
// позиция слушателя
|
|
47
54
|
this._listenerX = 0;
|
|
48
55
|
this._listenerY = 0;
|
|
@@ -164,7 +171,9 @@ export default class SoundManager {
|
|
|
164
171
|
* @param {boolean} [data?.spatial=true] - Принадлежит ли звук миру.
|
|
165
172
|
* `false` — источник игрока (двигатель и выстрел своего танка): он
|
|
166
173
|
* стоит ровно на слушателе, и HRTF на нулевой дистанции сворачивается
|
|
167
|
-
* в гребенчатую окраску («гул»), а не в тишину панорамы.
|
|
174
|
+
* в гребенчатую окраску («гул»), а не в тишину панорамы. Такому звуку
|
|
175
|
+
* PannerNode не создаётся вовсе — он идёт прямо в gain и остаётся
|
|
176
|
+
* стерео.
|
|
168
177
|
* @param {function} [callback] - Функция, вызываемая по завершении.
|
|
169
178
|
* @returns {symbol | null} Уникальный ID звука или null, если звук не найден.
|
|
170
179
|
*/
|
|
@@ -348,6 +357,7 @@ export default class SoundManager {
|
|
|
348
357
|
sound.stop(soundId);
|
|
349
358
|
this._activeInstances.delete(soundId);
|
|
350
359
|
this._equalPowerIds.delete(soundId);
|
|
360
|
+
this._pannedIds.delete(soundId);
|
|
351
361
|
continue;
|
|
352
362
|
}
|
|
353
363
|
|
|
@@ -407,6 +417,7 @@ export default class SoundManager {
|
|
|
407
417
|
|
|
408
418
|
this._activeInstances.delete(soundId);
|
|
409
419
|
this._equalPowerIds.delete(soundId);
|
|
420
|
+
this._pannedIds.delete(soundId);
|
|
410
421
|
},
|
|
411
422
|
soundId,
|
|
412
423
|
);
|
|
@@ -425,6 +436,7 @@ export default class SoundManager {
|
|
|
425
436
|
instanceData.sound.stop(soundId);
|
|
426
437
|
this._activeInstances.delete(soundId);
|
|
427
438
|
this._equalPowerIds.delete(soundId);
|
|
439
|
+
this._pannedIds.delete(soundId);
|
|
428
440
|
}
|
|
429
441
|
}
|
|
430
442
|
|
|
@@ -445,11 +457,14 @@ export default class SoundManager {
|
|
|
445
457
|
|
|
446
458
|
if (spatial === false) {
|
|
447
459
|
// источник игрока: звук не принадлежит миру, он принадлежит игроку.
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
460
|
+
// Паннер ему не нужен ни в каком виде — ни HRTF (на нулевой
|
|
461
|
+
// дистанции это не тишина панорамы, а фронтальная свёртка:
|
|
462
|
+
// гребенчатая окраска, из-за которой двигатель слышен как гул), ни
|
|
463
|
+
// equalpower (тот схлопывает стерео сэмпла в моно). Пока узла нет,
|
|
464
|
+
// pos() не зовётся вовсе: Howler создал бы паннер и щёлкнул
|
|
465
|
+
// pause()/play()
|
|
452
466
|
sound.volume(volume, soundId);
|
|
467
|
+
this._recenterIfPanned(sound, soundId, true);
|
|
453
468
|
|
|
454
469
|
return;
|
|
455
470
|
}
|
|
@@ -467,9 +482,34 @@ export default class SoundManager {
|
|
|
467
482
|
// если дистанция позволяет панорамировать звук
|
|
468
483
|
if (distance > MIN_SPATIAL_DISTANCE) {
|
|
469
484
|
sound.pos(x - this._listenerX, 0, y - this._listenerY, soundId);
|
|
485
|
+
this._pannedIds.add(soundId);
|
|
470
486
|
} else {
|
|
471
|
-
|
|
487
|
+
// внутри дед-зоны звук идёт по центру. Экземпляру, у которого паннер
|
|
488
|
+
// ещё не создан, здесь не место его заводить: узел появится на
|
|
489
|
+
// первом же выходе из дед-зоны
|
|
490
|
+
this._recenterIfPanned(sound, soundId);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* @private Возвращает в центр экземпляр, у которого PannerNode УЖЕ есть
|
|
496
|
+
* (источник успел побывать в стороне от слушателя). Экземпляр без узла
|
|
497
|
+
* не трогается: создание паннера — это лишний узел в цепочке, потеря
|
|
498
|
+
* стерео и щелчок от pause()/play() внутри setupPanner Howler'а.
|
|
499
|
+
* @param {boolean} [equalPower=false] - Перевести узел на equalpower:
|
|
500
|
+
* так делается только для источника игрока, миру HRTF сохраняется —
|
|
501
|
+
* он снова понадобится, как только источник выйдет из дед-зоны.
|
|
502
|
+
*/
|
|
503
|
+
_recenterIfPanned(sound, soundId, equalPower = false) {
|
|
504
|
+
if (!this._pannedIds.has(soundId)) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (equalPower) {
|
|
509
|
+
this._applyEqualPower(sound, soundId);
|
|
472
510
|
}
|
|
511
|
+
|
|
512
|
+
sound.pos(0, 0, 0, soundId);
|
|
473
513
|
}
|
|
474
514
|
|
|
475
515
|
/**
|
|
@@ -521,6 +561,7 @@ export default class SoundManager {
|
|
|
521
561
|
Howler.stop();
|
|
522
562
|
this._activeInstances.clear();
|
|
523
563
|
this._equalPowerIds.clear();
|
|
564
|
+
this._pannedIds.clear();
|
|
524
565
|
|
|
525
566
|
// луп переживает reset: его владелец жив, и ближайший
|
|
526
567
|
// processAudibility() запустит звук заново. Одноразовый — нет:
|