feat: add sounds

This commit is contained in:
2026-06-18 21:57:28 +03:30
parent 519752b478
commit f4d99043c4
18 changed files with 312 additions and 55 deletions
+51
View File
@@ -0,0 +1,51 @@
import 'package:flame_audio/flame_audio.dart';
/// سرویسِ متمرکزِ افکت‌های صوتی (فایل‌ها در assets/audio/).
///
/// از AudioPool استفاده می‌شود: برای هر صدا یک مجموعه‌ی محدود از پخش‌کننده‌ها
/// ساخته و بازاستفاده می‌شود. این کار از نشتِ AudioPlayerها (که روی اندروید
/// باعثِ قطعِ کاملِ صدا و پرشِ فریم می‌شد) جلوگیری می‌کند.
class AppSounds {
AppSounds._();
static const _shuffle = 'shuffle.mp3'; // بُر زدن/پخشِ کارت‌ها (شروع دست)
static const _placeCard = 'place_card.mp3'; // گذاشتنِ کارت روی میز (همه‌ی بازیکنان)
static const _takeCard = 'take_card.mp3'; // جمع‌شدنِ دستِ کامل
static const _cut = 'cut.mp3'; // بریدن با حکم (شمشیر)
static const _win = 'win.mp3'; // برد بازی
static const _button = 'button.mp3'; // فشردنِ دکمه‌ها
static const _all = [_shuffle, _placeCard, _takeCard, _cut, _win, _button];
static final Map<String, AudioPool> _pools = {};
static bool muted = false;
/// ساختِ Poolها (یک‌بار، در main). تا آماده‌شدن، پخش‌ها بی‌اثرند.
static Future<void> preload() async {
for (final f in _all) {
try {
_pools[f] = await FlameAudio.createPool(f, maxPlayers: 3);
} catch (_) {/* نبودِ فایل ⇒ بی‌صدا */}
}
}
/// پخش از Pool؛ اگر cutoffMs داده شود، صدا پس از آن مدت قطع می‌شود (کلیکِ کوتاه).
static void _play(String file, double volume, {int? cutoffMs}) {
if (muted) return;
final pool = _pools[file];
if (pool == null) return;
pool.start(volume: volume).then((stop) {
if (cutoffMs != null) {
Future.delayed(Duration(milliseconds: cutoffMs), () => stop());
}
}).catchError((_) {});
}
/// صدای بُر زدن؛ cutoffMs را برابرِ مدتِ انیمیشنِ بُر بده تا هم‌زمان تمام شوند.
static void shuffle({int? cutoffMs}) => _play(_shuffle, 0.7, cutoffMs: cutoffMs);
static void placeCard() => _play(_placeCard, 0.8);
static void takeCard() => _play(_takeCard, 0.7);
static void cut() => _play(_cut, 0.9);
static void win() => _play(_win, 0.9);
static void button() => _play(_button, 0.5, cutoffMs: 130); // کلیکِ کوتاه
}