La gestion du son est très importante pour de nombreux types d’applications Flash, tels que les sites Web interactifs et les jeux. Si vous souhaitez offrir une expérience interactive riche, vous pouvez envisager d'utiliser des effets sonores et une musique de fond. Dans ce tutoriel, je présenterai un cadre de gestion de son minimaliste permettant de gérer les sons en pistes sonores. Et je montrerai comment intégrer le framework sonore au framework de commandes de mes précédents tutoriels.
J'ai joué à des jeux avec une gestion du son imprudente, ce qui nuit à l'expérience utilisateur. Avez-vous déjà joué à un jeu, par exemple, un jeu d'action, où la voix d'exclamation du personnage est jouée avant la fin de la voix précédente, en se chevauchant? C'est le résultat d'une mauvaise gestion du son: il ne devrait pas y avoir plus d'une voix du même personnage à la fois. Le cadre de gestion du son que je vais couvrir couvrira ce problème en gérant les sons avec des pistes sonores..
Les exemples de ce didacticiel utilisent les structures de commande et de gestion de scène de mon précédent didacticiel, Pensée dans les commandes (partie 1, partie 2), et les exemples utilisent également la classe de gestionnaire de données de Chargement de données avec commandes. Je vous recommande vivement de parcourir ces tutoriels avant de continuer. En outre, vous aurez besoin de la plate-forme GreenSock Tweening pour compléter les exemples..
La piste sonore dont nous parlons ici n'a rien à voir avec les pistes sonores de jeux ou de films. Une piste sonore est une "piste" imaginaire associée à la lecture d'un unique du son. Une seule piste sonore ne permet pas la lecture de plus d’un son à la fois. Si une piste sonore joue actuellement un son, on dit que c'est occupé. Si un autre son doit être joué sur une piste audio occupée, le son en cours de lecture est arrêté et le nouveau son est joué sur la piste. Il est donc raisonnable de reproduire les voix d'un seul personnage sur une seule piste sonore afin d'éviter le problème de chevauchement du son mentionné précédemment. De plus, dans la plupart des cas, il ne devrait y avoir qu’une seule piste pour la musique de fond..
Jetons un coup d'oeil à quelques chiffres conceptuels. Une seule application peut avoir plusieurs pistes son.
Chaque piste sonore peut contenir un seul son de lecture.
Si un son doit être joué sur une piste occupée, le "vieux" son est d'abord arrêté, puis le "nouveau" son est joué sur la piste..
Le cadre de gestion du son comprend deux classes, le SoundManager la classe et la Bande sonore classe. Chaque piste sonore se voit attribuer une chaîne de clé unique. Le son de jeu sous-jacent d’une piste sonore occupée est en fait un objet natif SoundChannel obtenu à partir de la méthode native Sound.play (), et le SoundManager la classe gère les pistes sonores et organise la lecture des sons.
Voici quelques aperçus rapides de l'utilisation du framework. Le code suivant joue un nouveau son sur une piste sonore associée à la chaîne de caractères "music", où MySound est une classe sonore de la bibliothèque.
// joue un son sur la piste "music" SoundManager.play ("music", new MySound ());
Si la même ligne de code est exécutée à nouveau avant la fin de la lecture, le son d'origine est arrêté et un nouveau son est joué sur la piste "musique"..
// arrête le son original sur la piste "music" et en lit un nouveau SoundManager.play ("music", new MySound ());
le SoundManager.stop () méthode arrête une piste sonore associée à une chaîne de clé spécifiée.
// arrête la piste sonore "music" SoundManager.stop ("music");
Pour transformer le son, comme pour régler le volume, nous devrons obtenir une référence au canal audio sous-jacent d'une piste sonore. La référence peut être obtenue en accédant à la SoundTrack.channel propriété.
var channel: SoundChannel = SoundManager.getSoundTrack ("music"). channel; Transformation var: SoundTransform = channel.soundTransform; transform.volume = 0,5; channel.soundTransform = transformer;
Assez de théorie. Passons au codage. Nous allons utiliser différents chaînes de clé pour distinguer différentes pistes sonores. Ici se trouve le Bande sonore classe, qui représente essentiellement une paire clé-canal. Les détails sont décrits dans les commentaires.
package sons import flash.media.SoundChannel; / ** * Une piste sonore représente une paire clé-canal. * / public class SoundTrack // valeur de clé en lecture seule private var _key: String; fonction publique get key (): String return _key; // référence de canal audio en lecture seule private var _channel: SoundChannel; fonction publique get channel (): SoundChannel return _channel; fonction publique SoundTrack (key: String, channel: SoundChannel) _key = key; _channel = channel; / ** * Arrête le canal audio sous-jacent. * / public function stop (): void _channel.stop ();
Et voici la SoundManager classe. Notez que l'association clé-piste est gérée à l'aide de la classe Dictionary. Une piste est automatiquement vidée si le son de lecture est arrivé à sa fin..
package sons import flash.events.Event; import flash.media.Sound; import flash.media.SoundChannel; import flash.media.SoundTransform; import flash.utils.Dictionary; / ** * Cette classe vous permet de gérer les sons en termes de pistes sonores. * / public class SoundManager // un dictionnaire qui conserve des traces de toutes les pistes sonores privées static var _soundTracks: Dictionary = new Dictionary (); // un dictionnaire qui mappe un canal audio sur la touche correspondante pour la fin de la lecture et gère la statique privée var _soundKeys: Dictionary = new Dictionary (); / ** * Lit un son et retourne un objet de piste sonore correspondant. * / fonction publique statique (clé: String, sound: Sound, heure de début: int = 0, boucles: int = 0, transformation: SoundTransform = null): SoundTrack // si la piste audio est occupée, arrête la piste audio actuelle if (isPlaying (key)) stop (key); // joue le son en créant un nouveau canal sonore var channel: SoundChannel = sound.play (startTime, loops, transform); // écoute l'événement complet du canal audio channel.addEventListener (Event.SOUND_COMPLETE, onSoundComplete); // crée une nouvelle piste sonore var soundTrack: SoundTrack = new SoundTrack (key, channel); // ajoute la piste sonore au dictionnaire _soundTracks [key] = soundTrack; // ajoute la relation de mappage canal-clé _soundKeys [canal] = clé; return soundTrack; / ** * Retourne une référence à la piste sonore correspondant à la chaîne de clé fournie. * / fonction statique publique getSoundTrack (key: String): SoundTrack return _soundTracks [key]; / ** * Détermine si une piste sonore est en cours de lecture. * / fonction statique publique isPlaying (key: String): Boolean return Boolean (_soundTracks [key]); / ** * Arrête une piste sonore. * / fonction statique publique stop (key: String): void var soundTrack: SoundTrack = _soundTracks [key]; // vérifie si la piste sonore existe si (soundTrack) // arrête la piste sonore soundTrack.stop (); // et le retire du dictionnaire delete _soundTracks [key]; // avec la relation clé-canal delete _soundKeys [soundTrack.channel]; / ** * Supprime une piste sonore lorsque la lecture du son est terminée * / fonction statique privée onSoundComplete (e: Event): void // transforme le répartiteur d'événements en objet de canal audio var channel: SoundChannel = SoundChannel (e. cible); // supprime le programme d'écoute des événements channel.removeEventListener (Event.SOUND_COMPLETE, onSoundComplete); // extrait la clé correspondante clé var: String = _soundKeys [channel]; // supprime la piste sonore stop (key);
Maintenant, testons notre solide cadre de gestion. Nous allons comparer le résultat de demandes répétées de jouer un son avec ou sans le gestionnaire de sons..
Créer un nouveau document Flash (duh).
Créez deux boutons sur la scène. Vous pouvez dessiner les vôtres et les convertir en symboles ou bien, comme dans mon cas, faire glisser deux composants Button du panneau Composants. Nommez-les "boing_btn" et "managedBoing_btn".
Importez le son que nous allons jouer dans la bibliothèque. Vous pouvez trouver le fichier "Boing.wav" dans l'exemple de dossier source.
Enfin, créez un fichier AS pour la classe de document. Le code est plutôt simple, alors je viens d'expliquer tout dans les commentaires.
package import flash.display.Sprite; import flash.events.MouseEvent; import flash.media.Sound; importer des sons. SoundManager; Classe publique BoingPlayer étend Sprite fonction publique BoingPlayer () // ajoute les écouteurs de clic pour les deux boutons boing_btn.addEventListener (MouseEvent.CLICK, onBoing); managedBoing_btn.addEventListener (MouseEvent.CLICK, onManagedBoing); // joue directement le son en appelant la méthode Sound.play (). fonction privée onBoing (e: MouseEvent): void var sound: Sound = new Boing (); sound.play (); // joue le son avec le gestionnaire de sons sur la fonction privée de la piste son "boing" onManagedBoing (e: MouseEvent): void son var: Sound = new Boing (); SoundManager.play ("boing", son);
Avaient fini. Appuyez sur Ctrl + Entrée pour tester le film et essayez de cliquer rapidement sur les boutons (n'oubliez pas d'allumer vos haut-parleurs). Pour le "Boing!" bouton, plusieurs sons se chevauchent lors de la lecture. Quant au "Boing géré!" bouton, qui utilise le gestionnaire de sons, un son est forcé de s’arrêter avant le suivant, de sorte que vous n’entendrez pas de sons mélangés.
Étape importante Voir en ligneCommandes, commandes, commandes. C'est toujours bien d'intégrer votre travail avec vos précédents, non? Nous allons maintenant intégrer le cadre de gestion du son au cadre de commande et au cadre de gestion des scènes. Encore une fois, si vous n'êtes pas familiarisé avec le cadre de commande et le cadre de gestion de scène, vous devriez les vérifier dans mes tutoriels précédents (Partie 1, Partie 2) avant de continuer..
Le nom de cette commande est assez explicite: elle joue un son avec le son manager..
package commands.sounds import commands.Command; import flash.media.Sound; import flash.media.SoundTransform; importer des sons. SoundManager; / ** * Cette commande joue un son. * / public class PlaySound étend la commande public var key: String; son var public: son; public var startTime: int; boucles de variables publiques: int; transformation publique var: SoundTransform; fonction publique PlaySound (clé: chaîne, son: son, heure de début: int = 0, boucles: int = 0, transformation: SoundTransform = null) this.key = clé; this.sound = sound; this.startTime = startTime; this.loops = boucles; this.transform = transformer; écrase la fonction protégée execute (): void // indique au gestionnaire de sons de lire le son SoundManager.play (clé, son, heure de début, boucles, transformation); // complète la commande complete ();
Ceci est fondamentalement le cousin diabolique de la commande précédente. Cette commande arrête une piste sonore en utilisant le gestionnaire de sons.
package commands.sounds import commands.Command; importer des sons. SoundManager; / ** * Cette commande arrête une piste sonore correspondant à une touche donnée. * / public class StopSound étend la commande public var key: String; fonction publique StopSound (key: String) this.key = key; écrase la fonction protégée execute (): void // dit au gestionnaire du son d'arrêter la piste sonore, comment diable>:]] SoundManager.stop (clé); // complète la commande complete ();
Cette commande charge un fichier MP3 externe dans un Du son objet. Tant que le chargement n'est pas terminé, la commande Achevée() méthode soit appelée. Cela nous permet d’enchaîner facilement la commande avec d’autres commandes, sans avoir à nous soucier de la gestion du chargement..
package commands.loading import commands.Command; import flash.events.Event; import flash.media.Sound; import flash.net.URLRequest; / ** * Cette commande charge un son. * / public class SoundLoad étend la commande public var sound: Sound; public var url: URLRequest; fonction publique SoundLoad (sound: Sound, url: URLRequest) this.sound = sound; this.url = url; écrase la fonction protégée execute (): void // ajoute l'auditeur complet sound.addEventListener (Event.COMPLETE, onComplete); // commence le chargement de sound.load (url); fonction privée onComplete (e: Event): void // supprime l'auditeur complet sound.removeEventListener (Event.COMPLETE, onComplete); // complète la commande complete ();
Intégration terminée. Préparez-vous pour notre dernier exemple!
Dans cet exemple, nous allons permettre aux utilisateurs de jouer deux musiques sur la même piste sonore. Si un son doit être joué lorsque la piste sonore est occupée, la musique originale est d'abord atténuée, puis la nouvelle musique est lue. Le fondu enchaîné est géré par le TweenMaxTo commande, qui utilise en interne la propriété spéciale le volume fourni par le TweenMax classe de GreenSock Tweening Platform. Les deux musiques sont des fichiers MP3 externes chargés pendant l'exécution.
Notez que nous allons utiliser le cadre de gestion de scène. Si vous voulez vous rafraîchir la mémoire, allez voir ça ici.
Faites une copie du fichier FLA utilisé dans l'exemple précédent. Renommez les boutons "music1_btn" et "music2_btn". Vous pouvez également changer les étiquettes des boutons en "Music 1" et "Music 2". Et ajoutez un bouton supplémentaire appelé "stop_btn", qui sert à arrêter la musique.
Les fichiers MP3 peuvent être trouvés dans le dossier source. Copiez-les dans le même dossier que le fichier FLA.
Créez un nouveau fichier AS pour la classe de document du nouveau fichier FLA. Instanciez un gestionnaire de scène et initialisez-le à un état de chargement, où les deux fichiers MP3 sont chargés.
package import flash.display.Sprite; importer des scènes.SceneManager; Classe publique MusicPlayer étend Sprite fonction publique MusicPlayer () // instancier un objet de gestionnaire de scènes var sceneManager: SceneManager = new SceneManager (); // définit une scène de chargement comme scène initiale sceneManager.setScene (new LoadingScene (this));
La scène de chargement instancie deux Du son objets pour charger les deux fichiers MP3. Les boutons sont définis comme étant invisibles au début et redeviendront visibles une fois le chargement terminé. Lorsque le chargement est terminé, la scène ordonne immédiatement au gestionnaire de la scène de se rendre à la scène principale, comme indiqué dans la substitution. onSceneSet () méthode. De plus amples détails sont décrits dans les commentaires.
package import commands.Command; importer commands.data.RegisterData; import commands.loading.SoundLoad; import commands.ParallelCommand; import commands.SerialCommand; import commands.utils.SetProperties; import flash.events.Event; import flash.media.Sound; import flash.net.URLRequest; importer des scènes.Scene; public class LoadingScene étend Scene // une référence au conteneur racine du document conteneur privé var: MusicPlayer; fonction publique LoadingScene (conteneur: MusicPlayer) this.container = conteneur; écrase la fonction publique createIntroCommand (): Commande // crée deux objets son pour charger les deux fichiers MP3 var music1: Sound = new Sound (); var music2: Sound = new Sound (); var commande: Command = new ParallelCommand (0, // masque les boutons new SetProperties (container.music1_btn, alpha: 0, visible: false), new SetProperties (container.music2_btn, alpha: 0, visible: false) , new SetProperties (container.stop_btn, alpha: 0, visible: false), // enregistre les deux objets sonores dans le gestionnaire de données new RegisterData ("music1", music1), nouveau RegisterData ("music2", music2), // commence le chargement des fichiers MP3 new SoundLoad (music1, nouvelle URLRequest ("Music1.mp3")), nouvelle SoundLoad (music2, nouvelle URLRequest ("Music2.mp3"))); renvoyer la commande; écrasera la fonction publique onSceneSet (): void // indique au gestionnaire de scène de passer directement à la scène principale une fois la commande d'introduction terminée. sceneManager.setScene (new MainScene (conteneur));
La scène principale ramène les boutons cachés à visible et enregistre le jouer de la musique() méthode et la stopMusic () méthode en tant qu'écouteurs pour l'événement click. dans le jouer de la musique() méthode, une commande série est exécutée si la piste sonore "bgm" est occupée. La commande supprime d'abord temporairement les écouteurs au clic, efface la musique actuelle, arrête la musique actuelle, lit la nouvelle musique sur la piste sonore "bgm" maintenant vide, puis rajoute enfin les écouteurs au clic. le stopMusic méthode fait fondamentalement la même chose, sauf qu'il n'y a pas de nouvelle lecture de musique. Cette série complexe d’actions n’est réalisée que dans quelques lignes de code propre. Plutôt chouette, hein?
Notez que l’ajout et la suppression des écouteurs sont des actions courantes présentes à la fois dans jouer de la musique() méthode et la stopMusic () méthode. Donc, ils sont factorisés comme deux propriétés privées, addListeners et removeListeners, initialisé dans le constructeur.
package import commands.Command; importer commands.events.AddEventListener; importer commands.events.RemoveEventListener; importer commands.greensock.TweenMaxTo; import commands.ParallelCommand; import commands.SerialCommand; importer commands.sounds.PlaySound; importer commands.sounds.StopSound; importer data.DataManager; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.media.Sound; import flash.utils.Dictionary; importer des scènes.Scene; importer des sons. SoundManager; importer des sons.SoundTrack; / ** * La scène principale est affichée à la fin du chargement. * / public class MainScene étend Scene // une référence au conteneur racine du document conteneur privé var: MusicPlayer; private var btn1: Sprite; private var btn2: Sprite; private var btn3: Sprite; var privé dataKeys: Dictionary = new Dictionary (); private var addListeners: Commande; private var removeListeners: Commande; fonction publique MainScene (conteneur: MusicPlayer) this.container = conteneur; btn1 = container.music1_btn; btn2 = conteneur.music2_btn; btn3 = conteneur.stop_btn; // clés de données utilisées pour récupérer des objets son du gestionnaire de données dans la méthode playMusic () dataKeys [btn1] = "music1"; dataKeys [btn2] = "music2"; // cette commande ajoute tous les écouteurs addListeners = new ParallelCommand (0, new AddEventListener (btn1, MouseEvent.CLICK, playMusic), new AddEventListener (btn2, MouseEvent.CLICK, playMusic), new AddEventListener (btn3, MouseEvent.CLICK). ; // cette commande supprime tous les écouteurs removeListeners = new ParallelCommand (0, new RemoveEventListener (btn1, MouseEvent.CLICK, playMusic), new RemoveEventListener (btn2, MouseEvent.CLICK, playMusic), new RemoveEventListener (btn3, MouseEvent.CLICK). ; écrase la fonction publique createIntroCommand (): Command var commande: Command = new SerialCommand (0, // fade dans les boutons new ParallelCommand (0, new TweenMaxTo (btn1, 1, autoAlpha: 1), new TweenMaxTo (btn2, 1, autoAlpha: 1), nouveau TweenMaxTo (btn3, 1, autoAlpha: 1)), // ajoute des écouteurs de clic addListeners); renvoyer la commande; / ** * Lit la musique. * / fonction privée playMusic (e: Event): void // récupère l'objet son correspondant à une clé de données var music: Sound = DataManager.getData (dataKeys [e.target]); // vérifie si la piste sonore BGM est déjà en cours de lecture si (SoundManager.isPlaying ("bgm")) // récupère la piste sonore en cours de lecture var soundTrack: SoundTrack = SoundManager.getSoundTrack ("bgm"); var command: Command = new SerialCommand (0, // enlève temporairement les écouteurs de clic removeListeners, // supprime la fondue de la piste audio actuelle. nouveau TweenMaxTo (soundTrack.channel, 1, volume: 0), // puis arrête la piste audio new StopSound ("bgm"), // joue un nouveau son sur la même piste sonore. nouveau PlaySound ("bgm", musique, 0, int.MAX_VALUE), // rajoute un clic sur les écouteurs addListeners); command.start (); else // joue seulement le son si la piste sonore est inactive SoundManager.play ("bgm", music, 0, int.MAX_VALUE); / ** * Arrête la musique en cours de lecture. * / private function stopMusic (e: Event): void // vérifie si la piste sonore BGM est déjà en cours de lecture si (SoundManager.isPlaying ("bgm")) // récupère la piste sonore en cours var soundTrack: SoundTrack = SoundManager. getSoundTrack ("bgm"); var command: Command = new SerialCommand (0, // enlève temporairement les écouteurs de clic removeListeners, // supprime la fondue de la piste audio actuelle. nouveau TweenMaxTo (soundTrack.channel, 1, volume: 0), // puis arrête la piste audio new StopSound ("bgm"), // rajoute des écouteurs de clic addListeners); command.start ();
Nous sommes prêts à tester le film. Appuyez sur CTRL + ENTRÉE pour le tester. Lorsque vous cliquez sur un bouton, une musique commence à jouer. Après avoir cliqué sur un autre, la musique s’efface, puis une nouvelle commence au début..
Étape importante Voir en ligneC'est la fin du tutoriel, je sais. Mais je ne pouvais pas résister à vous montrer cela. Si vous êtes un code jockey, je parie que vous avez déjà remarqué qu'il y a beaucoup de similitudes dans le jouer de la musique() méthode et la stopMusic () méthode. Pourquoi ne pas les reformer en un seul? Si vous n'êtes pas intéressé par cette version jocky du lecteur de musique, vous pouvez passer directement à la section récapitulative. Sinon, continuez à lire!
Tout d’abord, remplacez tous les jouer de la musique et stopMusic dans le code source avec handleMusic, notre nouvel auditeur d'événement. Ensuite, supprimez le jouer de la musique et le stopMusic méthode, et ajoutez ce qui suit handleMusic () méthode dans la classe de scène principale.
/ ** * Lit ou arrête la musique. Version du code jockey. * / fonction privée handleMusic (e: Event): void var musique: Sound = DataManager.getData (dataKeys [e.target]); if (SoundManager.isPlaying ("bgm")) var soundTrack: SoundTrack = SoundManager.getSoundTrack ("bgm"); var command: Command = new SerialCommand (0, removeListeners, new TweenMaxTo (soundTrack.channel, 1, volume: 0), new StopSound ("bgm"), // détermine si nous allons jouer une autre musique (musique )? (new PlaySound ("bgm", music, 0, int.MAX_VALUE)): (new Dummy ()), addListeners); command.start (); else if (musique) SoundManager.play ("bgm", musique, 0, int.MAX_VALUE);
Vous remarquerez que la seule différence majeure entre cette méthode et les auditeurs d'origine est le bloc de code suivant:
(la musique)? (new PlaySound ("bgm", music, 0, int.MAX_VALUE)): (new Dummy ()),
Qu'est-ce que c'est que ça? C'est en fait l'opérateur?: Conditionnel. C'est un opérateur ternaire, ce qui signifie qu'il nécessite trois opérandes, A, B et C. L'instruction "A? B: C" est évaluée à B si A est vrai ou C sinon. le la musique variable est censée contenir une référence à un Du son objet, de sorte que la variable est évaluée à true. Toutefois, si la cible du répartiteur d'événements est le bouton "stop_btn", la variable contient une valeur null, évaluée à false dans l'opérateur ternaire. Ainsi, si vous cliquez sur les deux boutons musicaux, le bloc de code ci-dessus est considéré comme la seule ligne de code ci-dessous..
nouveau PlaySound ("bgm", musique, 0, int.MAX_VALUE)
Sinon, si le bouton d'arrêt est cliqué, le bloc de code est considéré comme une commande factice, ce qui ne fait tout simplement rien.
nouveau mannequin ()
Juste une autre chose à remarquer. La ligne de code suivante
SoundManager.play ("bgm", musique, 0, int.MAX_VALUE);
est changé en
if (musique) SoundManager.play ("bgm", musique, 0, int.MAX_VALUE);
C'est pour le traitement de l'exception que la piste sonore est actuellement vide. Si vous pouvez comprendre le bloc de code ci-dessus, je suis sûr que vous pourrez comprendre en quoi consiste cette ligne..
Testez le film en appuyant sur Ctrl + Entrée, vous verrez exactement le même résultat que dans le dernier exemple. Vous pouvez le considérer comme un accomplissement de la vanité de codage d'un jockey de code.
Dans ce didacticiel, vous avez appris à gérer les sons avec des pistes sonores. Une piste sonore ne permet de lire qu'un seul son à la fois, il est donc idéal pour représenter la voix ou la musique de fond d'un seul personnage. En outre, vous avez vu comment intégrer la structure de gestion des sons à la structure de commandes, ce qui vous confère une maintenance et une flexibilité considérables pour vos applications..
C'est la fin du tutoriel. J'espère que vous avez aimé. Merci beaucoup d'avoir lu!