Aggiungi audio e musica al tuo gioco Flutter

Aggiungere audio e musica al tuo gioco Flutter

Informazioni su questo codelab

subjectUltimo aggiornamento: giu 6, 2025
account_circleScritto da: Filip Hracek

1. Prima di iniziare

I giochi sono esperienze audiovisive. Flutter è un ottimo strumento per creare immagini bellissime e un'interfaccia utente solida, quindi ti aiuta molto dal punto di vista visivo. L'ingrediente mancante è l'audio. In questo codelab imparerai a utilizzare il plug-in flutter_soloud per inserire audio e musica a bassa latenza nel tuo progetto. Inizia con uno scheletro di base per passare direttamente alle parti interessanti.

Un'illustrazione disegnata a mano di cuffie.

Ovviamente, puoi utilizzare ciò che impari qui per aggiungere audio alle tue app, non solo ai giochi. Tuttavia, mentre quasi tutti i giochi richiedono audio e musica, la maggior parte delle app no, quindi questo codelab si concentra sui giochi.

  • Familiarità di base con Flutter.
  • Conoscenza di come eseguire ed eseguire il debug di app Flutter.

Cosa imparerai

  • Come riprodurre i suoni una tantum.
  • Come riprodurre e personalizzare i loop musicali senza interruzioni.
  • Come attenuare e aumentare gradualmente i suoni.
  • Come applicare effetti ambientali ai suoni.
  • Come gestire le eccezioni.
  • Come incapsulare tutte queste funzionalità in un unico controller audio.

Cosa serve

  • L'SDK Flutter
  • Un editor di codice a tua scelta

2. Configura

  1. Scarica i seguenti file. Se la connessione è lenta, non preoccuparti. Poiché avrai bisogno dei file effettivi, puoi lasciarli scaricare mentre lavori.
  1. Crea un progetto Flutter con un nome a tua scelta.
  1. Crea un file lib/audio/audio_controller.dart nel progetto.
  2. Nel file, inserisci il seguente codice:

lib/audio/audio_controller.dart

import 'dart:async';

import 'package:logging/logging.dart';

class AudioController {
 
static final Logger _log = Logger('AudioController');

 
Future<void> initialize() async {
   
// TODO
 
}

 
void dispose() {
   
// TODO
 
}

 
Future<void> playSound(String assetKey) async {
   
_log.warning('Not implemented yet.');
 
}

 
Future<void> startMusic() async {
   
_log.warning('Not implemented yet.');
 
}

 
void fadeOutMusic() {
   
_log.warning('Not implemented yet.');
 
}

 
void applyFilter() {
   
// TODO
 
}

 
void removeFilter() {
   
// TODO
 
}
}

Come puoi vedere, si tratta solo di uno scheletro per le funzionalità future. Lo implementeremo tutto durante questo codelab.

  1. Successivamente, apri il file lib/main.dart e sostituisci i relativi contenuti con il seguente codice:

lib/main.dart

import 'dart:developer' as dev;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';

import 'audio/audio_controller.dart';

void main() async {
 
// The `flutter_soloud` package logs everything
 
// (from severe warnings to fine debug messages)
 
// using the standard `package:logging`.
 
// You can listen to the logs as shown below.
 
Logger.root.level = kDebugMode ? Level.FINE : Level.INFO;
 
Logger.root.onRecord.listen((record) {
   
dev.log(
     
record.message,
     
time: record.time,
     
level: record.level.value,
     
name: record.loggerName,
     
zone: record.zone,
     
error: record.error,
     
stackTrace: record.stackTrace,
   
);
 
});

 
WidgetsFlutterBinding.ensureInitialized();

 
final audioController = AudioController();
 
await audioController.initialize();

 
runApp(MyApp(audioController: audioController));
}

class MyApp extends StatelessWidget {
 
const MyApp({required this.audioController, super.key});

 
final AudioController audioController;

 
@override
 
Widget build(BuildContext context) {
   
return MaterialApp(
     
title: 'Flutter SoLoud Demo',
     
theme: ThemeData(
       
colorScheme: ColorScheme.fromSeed(seedColor: Colors.brown),
     
),
     
home: MyHomePage(audioController: audioController),
   
);
 
}
}

class MyHomePage extends StatefulWidget {
 
const MyHomePage({super.key, required this.audioController});

 
final AudioController audioController;

 
@override
 
State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 
static const _gap = SizedBox(height: 16);

 
bool filterApplied = false;

 
@override
 
Widget build(BuildContext context) {
   
return Scaffold(
     
appBar: AppBar(title: const Text('Flutter SoLoud Demo')),
     
body: Center(
       
child: Column(
         
mainAxisAlignment: MainAxisAlignment.center,
         
children: <Widget>[
           
OutlinedButton(
             
onPressed: () {
               
widget.audioController.playSound('assets/sounds/pew1.mp3');
             
},
             
child: const Text('Play Sound'),
           
),
           
_gap,
           
OutlinedButton(
             
onPressed: () {
               
widget.audioController.startMusic();
             
},
             
child: const Text('Start Music'),
           
),
           
_gap,
           
OutlinedButton(
             
onPressed: () {
               
widget.audioController.fadeOutMusic();
             
},
             
child: const Text('Fade Out Music'),
           
),
           
_gap,
           
Row(
             
mainAxisSize: MainAxisSize.min,
             
children: [
               
const Text('Apply Filter'),
               
Checkbox(
                 
value: filterApplied,
                 
onChanged: (value) {
                   
setState(() {
                     
filterApplied = value!;
                   
});
                   
if (filterApplied) {
                     
widget.audioController.applyFilter();
                   
} else {
                     
widget.audioController.removeFilter();
                   
}
                 
},
               
),
             
],
           
),
         
],
       
),
     
),
   
);
 
}
}
  1. Dopo aver scaricato i file audio, crea una directory nella directory principale del progetto denominata assets.
  2. Nella directory assets, crea due sottodirectory, una denominata music e l'altra sounds.
  3. Sposta i file scaricati nel progetto in modo che il file del brano sia nel file assets/music/looped-song.ogg e i suoni della panca siano nei seguenti file:
  • assets/sounds/pew1.mp3
  • assets/sounds/pew2.mp3
  • assets/sounds/pew3.mp3

La struttura del progetto dovrebbe ora essere simile a questa:

Una visualizzazione ad albero del progetto, con cartelle come &quot;android&quot;, &quot;ios&quot;, file come &quot;README.md&quot; e &quot;analysis_options.yaml&quot;.   Tra queste, possiamo vedere la directory &quot;assets&quot; con le sottodirectory &quot;music&quot; e &quot;sounds&quot;, la directory &quot;lib&quot; con &quot;main.dart&quot; e una sottodirectory &quot;audio&quot; con &quot;audio_controller.dart&quot; e il file &quot;pubspec.yaml&quot;.  Le frecce rimandano alle nuove directory e ai file che hai toccato finora.

Ora che i file sono presenti, devi comunicarli a Flutter.

  1. Apri il file pubspec.yaml e sostituisci la sezione flutter: in fondo al file con quanto segue:

pubspec.yaml

...

flutter
:
  uses
-material-design: true

  assets
:
   
- assets/music/
   
- assets/sounds/
  1. Aggiungi una dipendenza dal pacchetto flutter_soloud e dal pacchetto logging.
flutter pub add flutter_soloud logging

Il file pubspec.yaml ora dovrebbe avere dipendenze aggiuntive dai pacchetti flutter_soloud e logging.

pubspec.yaml

...

dependencies
:
  flutter
:
    sdk
: flutter

  flutter_soloud
: ^3.1.10
  logging
: ^1.3.0

...
  1. Esegui il progetto. Non funziona ancora perché aggiungi la funzionalità nelle sezioni seguenti.

10f0f751c9c47038.png

3. Inizializzazione e arresto

Per riprodurre l'audio, utilizza il plug-in flutter_soloud. Questo plug-in si basa sul progetto SoLoud, un motore audio C++ per giochi utilizzato, tra gli altri, da Nintendo SNES Classic.

7ce23849b6d0d09a.png

Per inizializzare il motore audio SoLoud, segui questi passaggi:

  1. Nel file audio_controller.dart, importa il pacchetto flutter_soloud e aggiungi un campo _soloud privato alla classe.

lib/audio/audio_controller.dart

import 'dart:async';

import 'package:flutter_soloud/flutter_soloud.dart';  // Add this...
import 'package:logging/logging.dart';

class AudioController {
 
static final Logger _log = Logger('AudioController');

 
SoLoud? _soloud;                                    // ... and this.

 
Future<void> initialize() async {
   
// TODO
 
}

 
...

Il controller audio gestisce il motore SoLoud sottostante tramite questo campo e inoltra tutte le chiamate.

  1. Nel metodo initialize(), inserisci il seguente codice:

lib/audio/audio_controller.dart

...

 
Future<void> initialize() async {
    _soloud
= SoLoud.instance;
    await _soloud
!.init();
 
}

...

Il campo _soloud viene compilato e attende l'inizializzazione. Tieni presente quanto segue:

  • SoLoud fornisce un campo singleton instance. Non è possibile creare più istanze di SoLoud. Questo non è consentito dal motore C++, quindi non è consentito nemmeno dal plug-in Dart.
  • L'inizializzazione del plug-in è asincrona e non è completata finché non viene restituito il metodo init().
  • Per brevità, in questo esempio non vengono rilevati errori in un blocco try/catch. Nel codice di produzione, vuoi farlo e segnalare eventuali errori all'utente.
  1. Nel metodo dispose(), inserisci il seguente codice:

lib/audio/audio_controller.dart

...

 
void dispose() {
    _soloud
?.deinit();
 
}

...

È buona norma arrestare SoLoud all'uscita dall'app, anche se tutto dovrebbe funzionare correttamente anche se non lo fai.

  1. Tieni presente che il metodo AudioController.initialize() è già chiamato dalla funzione main(). Ciò significa che il riavvio a caldo del progetto inizializza SoLoud in background, ma non ti sarà utile prima di riprodurre effettivamente alcuni suoni.

4. Riproduci suoni one-shot

Caricare una risorsa e riprodurla

Ora che sai che SoLoud viene inizializzato all'avvio, puoi chiedergli di riprodurre suoni.

SoLoud distingue tra un'origine audio, ovvero i dati e i metadati utilizzati per descrivere un suono, e le relative "istanze audio", ovvero i suoni effettivamente riprodotti. Un esempio di sorgente audio può essere un file MP3 caricato in memoria, pronto per essere riprodotto e rappresentato da un'istanza della classe AudioSource. Ogni volta che riproduci questa sorgente audio, SoLoud crea un'"istanza audio" rappresentata dal tipo SoundHandle.

Puoi ottenere un'istanza AudioSource caricandola. Ad esempio, se hai un file MP3 tra le risorse, puoi caricarlo per ottenere un AudioSource. Poi chiedi a SoLoud di riprodurre questo AudioSource. Puoi giocarci più volte, anche contemporaneamente.

Quando non hai più bisogno di un'origine audio, puoi rimuoverla con il metodo SoLoud.disposeSource().

Per caricare un asset e riprodurlo:

  1. Nel metodo playSound() della classe AudioController, inserisci il seguente codice:

lib/audio/audio_controller.dart

  ...

  Future<void> playSound(String assetKey) async {
    final source = await _soloud!.loadAsset(assetKey);
    await _soloud!.play(source);
  }

  ...
  1. Salva il file, esegui il ricaricamento rapido e seleziona Riproduci suono. Dovresti sentire un suono buffo. Tieni presente quanto segue:
  • L'argomento assetKey fornito è simile a assets/sounds/pew1.mp3, la stessa stringa che forniresti a qualsiasi altra API Flutter di caricamento di asset, ad esempio il widget Image.asset().
  • L'istanza SoLoud fornisce un metodo loadAsset() che carica in modo asincrono un file audio dalle risorse del progetto Flutter e restituisce un'istanza della classe AudioSource. Esistono metodi equivalenti per caricare un file dal file system (metodo loadFile()) e per caricarlo tramite la rete da un URL (metodo loadUrl()).
  • L'istanza AudioSource appena acquisita viene poi passata al metodo play() di SoLoud. Questo metodo restituisce un'istanza del tipo SoundHandle che rappresenta l'audio appena riprodotto. Questo handle può essere passato ad altri metodi SoLoud per eseguire operazioni come mettere in pausa, interrompere o modificare il volume dell'audio.
  • Sebbene play() sia un metodo asincrono, la riproduzione inizia praticamente istantaneamente. Il pacchetto flutter_soloud utilizza l'interfaccia di funzione esterna (FFI) di Dart per chiamare il codice C in modo diretto e sincrono. I soliti messaggi tra il codice Dart e il codice della piattaforma, caratteristici della maggior parte dei plug-in Flutter, non sono presenti. L'unico motivo per cui alcuni metodi sono asincroni è che parte del codice del plug-in viene eseguita nel proprio isolato e la comunicazione tra gli istanze Dart è asincrona.
  • Affermi che il campo _soloud non è nullo con _soloud!. Anche in questo caso, per brevità. Il codice di produzione deve gestire in modo elegante la situazione in cui lo sviluppatore tenta di riprodurre un suono prima che il controller audio abbia avuto la possibilità di inizializzarsi completamente.

Gestire le eccezioni

Potresti aver notato che, ancora una volta, stai ignorando possibili eccezioni. È giunto il momento di correggere questo problema per questo metodo specifico a scopo didattico. Per brevità, il codelab torna a ignorare le eccezioni dopo questa sezione.

  • Per gestire le eccezioni in questo caso, inserisci le due righe del metodo playSound() in un blocco try/catch e rileva solo le istanze di SoLoudException.

lib/audio/audio_controller.dart

  ...

  Future<void> playSound(String assetKey) async {
    try {
      final source = await _soloud!.loadAsset(assetKey);
      await _soloud!.play(source);
    } on SoLoudException catch (e) {
      _log.severe("Cannot play sound '$assetKey'. Ignoring.", e);
    }
  }

  ...

SoLoud genera varie eccezioni, ad esempio le eccezioni SoLoudNotInitializedException o SoLoudTemporaryFolderFailedException. La documentazione dell'API di ogni metodo elenca i tipi di eccezioni che potrebbero essere lanciate.

SoLoud fornisce anche una classe principale per tutte le sue eccezioni, l'eccezione SoLoudException, in modo da poter rilevare tutti gli errori relativi alla funzionalità del motore audio. Questo è particolarmente utile nei casi in cui la riproduzione dell'audio non è fondamentale. Ad esempio, quando non vuoi che la sessione di gioco del giocatore abbia un arresto anomalo solo perché non è stato possibile caricare uno dei suoni pew-pew.

Come probabilmente previsto, il metodo loadAsset() può anche generare un errore FlutterError se fornisci una chiave asset non esistente. In genere, dovresti risolvere i problemi relativi al caricamento di asset non inclusi nel gioco, pertanto si tratta di un errore.

Riproduci suoni diversi

Potresti aver notato che riproduci solo il file pew1.mp3, ma nella directory delle risorse sono presenti altre due versioni dell'audio. Spesso sembra più naturale quando i giochi hanno più versioni dello stesso suono e le riproducono in modo casuale o a rotazione. In questo modo, ad esempio, i passi e gli spari non risulteranno troppo uniformi e quindi falsi.

  • Come esercizio facoltativo, modifica il codice in modo da riprodurre un suono diverso ogni volta che viene toccato il pulsante.

Illustrazione di

5. Riprodurre loop musicali

Gestire gli audio più lunghi

Alcuni contenuti audio sono pensati per essere riprodotti per periodi di tempo prolungati. La musica è l'esempio più ovvio, ma molti giochi riproducono anche l'ambiente, ad esempio il vento che ulula nei corridoi, il canto lontano dei monaci, il cigolio di metallo secolare o le tossi lontane dei pazienti.

Si tratta di sorgenti audio con durate che possono essere misurate in minuti. Devi monitorarli per poterli mettere in pausa o interrompere quando necessario. Inoltre, spesso sono supportati da file di grandi dimensioni e possono consumare molta memoria. Un altro motivo per monitorarli è che puoi eliminare l'istanza di AudioSource quando non è più necessaria.

Per questo motivo, dovrai introdurre un nuovo campo privato in AudioController. Si tratta di un handle del brano in riproduzione, se presente. Aggiungi la seguente riga:

lib/audio/audio_controller.dart

...

class AudioController {
 
static final Logger _log = Logger('AudioController');

 
SoLoud? _soloud;

 
SoundHandle? _musicHandle;    // ← Add this.

 
...

Avvia la musica

In sostanza, riprodurre musica non è diverso dalla riproduzione di un suono una tantum. Devi comunque prima caricare il file assets/music/looped-song.ogg come istanza della classe AudioSource, quindi utilizzare il metodo play() di SoLoud per riprodurlo.

Questa volta, però, prendi il handle audio restituito dal metodo play() per manipolare l'audio durante la riproduzione.

  • Se vuoi, puoi implementare il metodo AudioController.startMusic() autonomamente. Non preoccuparti se non ricordi alcuni dettagli. L'importante è che la musica inizi quando selezioni Avvia musica.

Ecco un'implementazione di riferimento:

lib/audio/audio_controller.dart

...

  Future<void> startMusic() async {
    if (_musicHandle != null) {
      if (_soloud!.getIsValidVoiceHandle(_musicHandle!)) {
        _log.info('Music is already playing. Stopping first.');
        await _soloud!.stop(_musicHandle!);
      }
    }
    final musicSource = await _soloud!.loadAsset(
      'assets/music/looped-song.ogg',
      mode: LoadMode.disk,
    );
  }

...

Tieni presente che carichi il file musicale in modalità disco (l'enum LoadMode.disk). Ciò significa che il file viene caricato solo a blocchi, in base alle esigenze. Per l'audio di durata più lunga, in genere è meglio caricare in modalità disco. Per gli effetti sonori brevi, ha più senso caricarli e decomprimerli in memoria (l'enum LoadMode.memory predefinito).

Tuttavia, ci sono un paio di problemi. Innanzitutto, la musica è troppo alta e copre i suoni. Nella maggior parte dei giochi, la musica è in sottofondo la maggior parte del tempo, lasciando spazio agli elementi audio più informativi, come i dialoghi e gli effetti sonori. Questo serve a correggere l'utilizzo del parametro volume del metodo play. Ad esempio, puoi provare a dire _soloud!.play(musicSource, volume: 0.6) per riprodurre il brano con il volume al 60%. In alternativa, puoi impostare il volume in un secondo momento con un comando come _soloud!.setVolume(_musicHandle, 0.6).

Il secondo problema è che il brano si interrompe bruscamente. Questo perché si tratta di un brano che dovrebbe essere riprodotto in loop e il punto di partenza del loop non è l'inizio del file audio.

88d2c57fffdfe996.png

Si tratta di una scelta popolare per la musica di gioco perché il brano inizia con un'introduzione naturale e viene riprodotto per tutto il tempo necessario senza un punto di loop evidente. Quando il gioco deve uscire dal brano in riproduzione, il brano viene attenuato.

Fortunatamente, SoLoud offre modi per riprodurre l'audio in loop. Il metodo play() accetta un valore booleano per il parametro looping e il valore per il punto di partenza del ciclo come parametro loopingStartAt. Il codice risultante sarà simile al seguente:

lib/audio/audio_controller.dart

...

_musicHandle = await _soloud!.play(
  musicSource,
  volume: 0.6,
  looping: true,
  // The exact timestamp of the start of the loop.
  loopingStartAt: const Duration(seconds: 25, milliseconds: 43),
);

...

Se non imposti il parametro loopingStartAt, il valore predefinito è Duration.zero (in altre parole, l'inizio del file audio). Se hai una traccia musicale che è un loop perfetto senza introduzione, è quello che ti serve.

  • Per verificare che l'origine audio venga eliminata correttamente al termine della riproduzione, ascolta lo stream allInstancesFinished fornito da ogni origine audio. Con le chiamate di log aggiunte, il metodo startMusic() avrà il seguente aspetto:

lib/audio/audio_controller.dart

...

  Future<void> startMusic() async {
    if (_musicHandle != null) {
      if (_soloud!.getIsValidVoiceHandle(_musicHandle!)) {
        _log.info('Music is already playing. Stopping first.');
        await _soloud!.stop(_musicHandle!);
      }
    }
    _log.info('Loading music');
    final musicSource = await _soloud!.loadAsset(
      'assets/music/looped-song.ogg',
      mode: LoadMode.disk,
    );
    musicSource.allInstancesFinished.first.then((_) {
      _soloud!.disposeSource(musicSource);
      _log.info('Music source disposed');
      _musicHandle = null;
    });

    _log.info('Playing music');
    _musicHandle = await _soloud!.play(
      musicSource,
      volume: 0.6,
      looping: true,
      loopingStartAt: const Duration(seconds: 25, milliseconds: 43),
    );
  }

...

Dissolvenza audio

Il problema successivo è che la musica non finisce mai. È il momento di implementare una dissolvenza.

Un modo per implementare l'attenuazione è avere una sorta di funzione chiamata più volte al secondo, ad esempio Ticker o Timer.periodic, e abbassare il volume della musica con piccoli decrementi. Funziona, ma richiede molto lavoro.

Fortunatamente, SoLoud offre comodi metodi di esecuzione che fanno tutto per te. Ecco come puoi attenuare la musica nel corso di cinque secondi e poi interrompere l'istanza audio in modo che non consumi risorse della CPU inutilmente. Sostituisci il metodo fadeOutMusic() con questo codice:

lib/audio/audio_controller.dart

...

  void fadeOutMusic() {
    if (_musicHandle == null) {
      _log.info('Nothing to fade out');
      return;
    }
    const length = Duration(seconds: 5);
    _soloud!.fadeVolume(_musicHandle!, 0, length);
    _soloud!.scheduleStop(_musicHandle!, length);
  }

...

6. Applicare effetti

Un enorme vantaggio di avere a disposizione un motore audio adeguato è che puoi eseguire l'elaborazione audio, ad esempio instradare alcuni suoni tramite un riverbero, un equalizzatore o un filtro passa basso.

Nei giochi, può essere utilizzato per la differenziazione uditiva delle posizioni. Ad esempio, un applauso suona in modo diverso in una foresta rispetto a un bunker di cemento. Mentre una foresta aiuta a dissipare e assorbire il suono, le pareti spoglie di un bunker riflettono le onde sonore, causando il riverbero. Analogamente, le voci delle persone suonano in modo diverso quando vengono ascoltate attraverso una parete. Le frequenze più alte di questi suoni vengono attenuate maggiormente mentre si propagano attraverso il mezzo solido, con un effetto di filtro passa basso.

Illustrazione di due persone che parlano in una stanza. Le onde sonore non passano solo da una persona all&#39;altra, ma rimbalzano anche sulle pareti e sul soffitto.

SoLoud offre diversi effetti audio che puoi applicare all'audio.

  • Per far sembrare che il tuo giocatore si trovi in una grande stanza, come una cattedrale o una grotta, utilizza il campo SoLoud.filters:

lib/audio/audio_controller.dart

...

 
void applyFilter() {
    _soloud
!.filters.freeverbFilter.activate();
    _soloud
!.filters.freeverbFilter.wet.value = 0.2;
    _soloud
!.filters.freeverbFilter.roomSize.value = 0.9;
 
}

 
void removeFilter() {
    _soloud
!.filters.freeverbFilter.deactivate();
 
}

...

Il campo SoLoud.filters ti consente di accedere a tutti i tipi di filtri e ai relativi parametri. Ogni parametro ha anche funzionalità integrate come l'oscillazione e lo sbiadimento graduale.

Nota: _soloud!.filters espone i filtri globali. Se vuoi applicare filtri a una singola origine, utilizza l'opzione AudioSource.filters, che ha lo stesso comportamento.

Con il codice precedente, esegui le seguenti operazioni:

  • Attiva il filtro freeverb a livello globale.
  • Imposta il parametro Wet su 0.2, il che significa che l'audio risultante sarà per l'80% originale e per il 20% l'output dell'effetto riverbero. Se imposti questo parametro su 1.0, è come sentire solo le onde sonore che ti ritornano dalle pareti lontane della stanza e nessun audio originale.
  • Imposta il parametro Dimensioni della camera su 0.9. Puoi modificare questo parametro in base alle tue esigenze o addirittura cambiarlo in modo dinamico. 1.0 è una grotta enorme, mentre 0.0 è un bagno.
  • Se vuoi, modifica il codice e applica uno dei seguenti filtri o una combinazione di questi:
  • biquadFilter (può essere utilizzato come filtro passa basso)
  • pitchShiftFilter
  • equalizerFilter
  • echoFilter
  • lofiFilter
  • flangerFilter
  • bassboostFilter
  • waveShaperFilter
  • robotizeFilter

7. Complimenti

Hai implementato un controller audio che riproduce suoni, riproduce musica in loop e applica effetti.

Scopri di più

  • Prova a migliorare il controller audio con funzionalità come il precaricamento dei suoni all'avvio, la riproduzione dei brani in sequenza o l'applicazione graduale di un filtro nel tempo.
  • Leggi la documentazione del pacchetto di flutter_soloud.
  • Leggi la home page della libreria C++ sottostante.
  • Scopri di più su Dart FFI, la tecnologia utilizzata per l'interfaccia con la libreria C++.
  • Guarda il talk di Guy Somberg sulla programmazione audio dei giochi per trovare ispirazione. Esiste anche una versione più lunga. Quando Guy parla di "middleware", si riferisce a librerie come SoLoud e FMOD. Il resto del codice tende ad essere specifico per ogni gioco.
  • Crea e rilascia il tuo gioco.

Illustrazione di cuffie