feat: add sounds
This commit is contained in:
@@ -8,7 +8,7 @@ class AppConfig {
|
||||
/// با تغییر شبکه/IP مک، مقدار dart-define یا همین پیشفرض را عوض کنید.
|
||||
static const String baseUrl = String.fromEnvironment(
|
||||
'BASE_URL',
|
||||
defaultValue: 'http://192.168.100.6:8080',
|
||||
defaultValue: 'http://192.168.1.105:8080',
|
||||
);
|
||||
|
||||
static String get apiUrl => '$baseUrl/api';
|
||||
|
||||
@@ -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); // کلیکِ کوتاه
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../service/app_sounds.dart';
|
||||
import '../theme/app_theme.dart';
|
||||
|
||||
/// مجموعهی ویجتهای گرافیکیِ مشترک برای ظاهرِ بازیِ (Unity-style):
|
||||
@@ -111,7 +112,12 @@ class _GameButtonState extends State<GameButton> {
|
||||
onTapDown: enabled ? (_) => setState(() => _down = true) : null,
|
||||
onTapUp: enabled ? (_) => setState(() => _down = false) : null,
|
||||
onTapCancel: enabled ? () => setState(() => _down = false) : null,
|
||||
onTap: widget.onTap,
|
||||
onTap: enabled
|
||||
? () {
|
||||
AppSounds.button();
|
||||
widget.onTap!();
|
||||
}
|
||||
: null,
|
||||
child: AnimatedScale(
|
||||
scale: _down ? 0.96 : 1.0,
|
||||
duration: const Duration(milliseconds: 90),
|
||||
|
||||
Reference in New Issue
Block a user