Статьи

Управление звуками с помощью команд

Управление звуком очень важно для многих типов приложений Flash, таких как интерактивные веб-сайты и игры. Если вы хотите предоставить богатый интерактивный опыт, вы можете рассмотреть возможность использования звуковых эффектов и фоновой музыки. В этом уроке я представлю минималистичную структуру управления звуком, которая управляет звуками в звуковые дорожки. И я покажу, как интегрировать звуковую среду с командной структурой из моих предыдущих уроков.


Я играл в игры с неосторожным управлением звуком, и это ухудшает пользовательский опыт. Вы когда-нибудь играли в игру, скажем, в экшн, где восклицательный голос персонажа играет до того, как предыдущий закончится, перекрывая друг друга? Это результат плохого управления звуком: не должно быть более одного голоса одного персонажа, играющего одновременно. Система управления звуком, которую я собираюсь рассмотреть, позаботится об этой проблеме, управляя звуками со звуковыми дорожками.

В примерах, приведенных в этом руководстве, используются командная среда и среда управления сценами из моего предыдущего урока «Мышление в командах» ( часть 1 , часть 2 ), а в примерах также используется класс диспетчера данных из « Загрузка данных с помощью команд» . Я настоятельно рекомендую вам сначала пройти эти уроки, прежде чем продолжить. Кроме того, вам понадобится платформа GreenSock Tweening для завершения примеров.


Звуковая дорожка, о которой мы здесь говорим, не имеет ничего общего со звуковыми дорожками игр или фильмов. Звуковая дорожка — это воображаемая «дорожка», связанная с воспроизведением одного звука. Одна звуковая дорожка не позволяет воспроизводить более одного звука одновременно. Если звуковая дорожка в данный момент воспроизводит звук, мы говорим, что он занят . Если на занятой звуковой дорожке должен воспроизводиться другой звук, текущий воспроизводимый звук останавливается, а затем на дорожке воспроизводится новый. Таким образом, целесообразно воспроизводить голоса одного персонажа на одной звуковой дорожке, чтобы избежать проблемы перекрытия звука, упомянутой ранее. Кроме того, в большинстве случаев для фоновой музыки должен быть только один трек.

Давайте посмотрим на некоторые концептуальные фигуры. Одно приложение может иметь несколько звуковых дорожек.

Каждая звуковая дорожка может содержать один воспроизводимый звук.

Если звук должен воспроизводиться на занятой дорожке, «старый» звук сначала останавливается, а затем на дорожке воспроизводится «новый» звук.


Среда Sound Management состоит из двух классов : класса SoundManager и класса SoundTrack . Каждой звуковой дорожке назначается уникальная строка клавиш. Основной воспроизводимый звук занятой звуковой дорожки на самом деле является собственным объектом SoundChannel, полученным из собственного метода Sound.play () , а класс SoundManager управляет звуковыми дорожками и организует воспроизведение звуков.

Вот несколько кратких обзоров использования фреймворка. Следующий код воспроизводит новый звук на звуковой дорожке, связанной с цепочкой клавиш «music», где MySound является классом звука из библиотеки.

1
2
//play a sound on the «music» track
SoundManager.play(«music», new MySound());

Если та же строка кода выполняется снова до завершения воспроизведения, исходный звук останавливается, и на дорожке «музыка» воспроизводится новый звук.

1
2
//stop the original sound on the «music» track and play a new one
SoundManager.play(«music», new MySound());

Метод SoundManager.stop () останавливает звуковую дорожку, связанную с указанной строкой клавиш.

1
2
//stop the «music» sound track
SoundManager.stop(«music»);

Чтобы преобразовать звук, например, отрегулировать громкость, нам нужно получить ссылку на основной звуковой канал звуковой дорожки. Ссылка может быть получена путем доступа к свойству SoundTrack.channel .

1
2
3
4
var channel:SoundChannel = SoundManager.getSoundTrack(«music»).channel;
var transform:SoundTransform = channel.soundTransform;
transform.volume = 0.5;
channel.soundTransform = transform;

Достаточно теории. Давайте приступим к кодированию. Мы будем использовать разные ключевые последовательности, чтобы различать разные звуковые дорожки. Вот класс SoundTrack , который по существу представляет пару ключ-канал. Подробности описаны в комментариях.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package sounds {
    import flash.media.SoundChannel;
     
    /**
     * A sound track represents a key-channel pair.
     */
    public class SoundTrack{
         
        //read-only key value
        private var _key:String;
        public function get key():String { return _key;
         
        //read-only sound channel reference
        private var _channel:SoundChannel;
        public function get channel():SoundChannel { return _channel;
         
        public function SoundTrack(key:String, channel:SoundChannel) {
            _key = key;
            _channel = channel;
        }
         
        /**
         * Stops the underlying sound channel.
         */
        public function stop():void {
            _channel.stop();
        }
    }
}

А вот и класс SoundManager . Обратите внимание, что сопоставление ключевой дорожки обрабатывается с помощью класса Dictionary . Дорожка очищается автоматически, если воспроизводимый звук достиг конца.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package sounds {
    import flash.events.Event;
    import flash.media.Sound;
    import flash.media.SoundChannel;
    import flash.media.SoundTransform;
    import flash.utils.Dictionary;
     
    /**
     * This class allows you to manage sounds in terms of sound tracks.
     */
    public class SoundManager{
         
        //a dictionary that keeps tracks of all sound tracks
        private static var _soundTracks:Dictionary = new Dictionary();
         
        //a dictionary that maps a sound channel to its corresponding key for playback completion handling
        private static var _soundKeys:Dictionary = new Dictionary();
         
        /**
         * Plays a sound and returns a corresponding sound track object.
         */
        public static function play(key:String, sound:Sound, startTime:int = 0, loops:int = 0, transform:SoundTransform = null):SoundTrack {
             
            //if the sound track is occupied, stop the current sound track
            if (isPlaying(key)) stop(key);
             
            //play the sound, creating a new sound channel
            var channel:SoundChannel = sound.play(startTime, loops, transform);
             
            //listen for the complete event of the sound channel
            channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
             
            //create a new sound track
            var soundTrack:SoundTrack = new SoundTrack(key, channel);
             
            //add the sound track to the dictionary
            _soundTracks[key] = soundTrack;
             
            //add the channel-key mapping relation
            _soundKeys[channel] = key;
             
            return soundTrack;
        }
         
        /**
         * Returns a reference to the sound track corresponding to the provided key string.
         */
        public static function getSoundTrack(key:String):SoundTrack {
            return _soundTracks[key];
        }
         
        /**
         * Determines if a sound track is currently playing.
         */
        public static function isPlaying(key:String):Boolean {
            return Boolean(_soundTracks[key]);
        }
         
        /**
         * Stops a sound track.
         */
        public static function stop(key:String):void {
            var soundTrack:SoundTrack = _soundTracks[key];
             
            //check if the sound track exists
            if (soundTrack) {
                 
                //stop the sound track
                soundTrack.stop();
                 
                //and remove it from the dictionary
                delete _soundTracks[key];
                 
                //along with the channel-key relation
                delete _soundKeys[soundTrack.channel];
            }
        }
         
        /**
         * Removes a sound track when the sound playback is complete
         */
        private static function onSoundComplete(e:Event):void {
             
            //cast the event dispatcher to a sound channel object
            var channel:SoundChannel = SoundChannel(e.target);
             
            //remove the event listener
            channel.removeEventListener(Event.SOUND_COMPLETE, onSoundComplete);
             
            //extract the corresponding key
            var key:String = _soundKeys[channel];
             
            //remove the sound track
            stop(key);
        }
    }
}

Теперь давайте проверим нашу систему управления звуком. Мы собираемся сравнить результаты повторных запросов на воспроизведение звука с использованием и без использования менеджера звука.


Создайте новый документ Flash (дух).


Создайте две кнопки на сцене. Вы можете нарисовать свои собственные и преобразовать их в символы, или вы можете, как в моем случае, перетащить два компонента Button с панели «Компоненты». Назовите их «boing_btn» и «managedBoing_btn».


Импортируйте звук, который мы собираемся воспроизвести, в библиотеку. Вы можете найти файл Boing.wav в исходной папке примера.


Наконец, создайте файл AS для класса документа . Код довольно прост, поэтому я все объясняю в комментариях.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package {
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.media.Sound;
    import sounds.SoundManager;
     
    public class BoingPlayer extends Sprite {
         
        public function BoingPlayer() {
             
            //add the click listeners for both buttons
            boing_btn.addEventListener(MouseEvent.CLICK, onBoing);
            managedBoing_btn.addEventListener(MouseEvent.CLICK, onManagedBoing);
        }
         
        //play the sound directly by invoking the Sound.play() method.
        private function onBoing(e:MouseEvent):void {
            var sound:Sound = new Boing();
            sound.play();
        }
         
        //play the sound with the sound manager on the «boing» sound track
        private function onManagedBoing(e:MouseEvent):void {
            var sound:Sound = new Boing();
            SoundManager.play(«boing», sound);
        }
    }
}

Были сделаны. Нажмите Ctrl + Enter, чтобы проверить фильм, и попробуйте быстро нажать кнопки (не забудьте включить динамики). Для «Боинга!» кнопка, несколько звуков перекрываются при воспроизведении. Что касается «Управляемого Боинга!» Кнопка, которая использует диспетчер звука, заставляет один звук останавливаться до воспроизведения следующего, поэтому вы не услышите смешанные звуки.


Команды, команды, команды. Всегда приятно интегрировать свою работу с предыдущими, верно? Теперь мы собираемся интегрировать среду управления звуком с командной средой вместе со средой управления сценой. Опять же, если вы не знакомы с командной структурой и структурой управления сценой, вам лучше проверить их в моих предыдущих уроках ( часть 1 , часть 2 ), прежде чем продолжить.


Название этой команды довольно очевидно: она воспроизводит звук с помощью менеджера звука.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package commands.sounds {
    import commands.Command;
    import flash.media.Sound;
    import flash.media.SoundTransform;
    import sounds.SoundManager;
     
    /**
     * This command plays a sound.
     */
    public class PlaySound extends Command {
         
        public var key:String;
        public var sound:Sound;
        public var startTime:int;
        public var loops:int;
        public var transform:SoundTransform;
         
        public function PlaySound(key:String, sound:Sound, startTime:int = 0, loops:int = 0, transform:SoundTransform = null) {
            this.key = key;
            this.sound = sound;
            this.startTime = startTime;
            this.loops = loops;
            this.transform = transform;
        }
         
        override protected function execute():void {
             
            //tell the sound manager to play the sound
            SoundManager.play(key, sound, startTime, loops, transform);
             
            //complete the command
            complete();
        }
    }
}

Это в основном злой двоюродный брат предыдущей команды. Эта команда останавливает звуковую дорожку с помощью менеджера звука.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package commands.sounds {
    import commands.Command;
    import sounds.SoundManager;
     
    /**
     * This command stops a sound track corresponding to a given key.
     */
    public class StopSound extends Command {
         
        public var key:String;
         
        public function StopSound(key:String) {
            this.key = key;
        }
         
        override protected function execute():void {
         
            //tell the sound manager to stop the sound track, how evil >:]
            SoundManager.stop(key);
             
            //complete the command
            complete();
        }
    }
}

Эта команда загружает внешний MP3-файл в объект Sound . Только после завершения загрузки будет вызван метод complete () команды . Это позволяет нам легко объединять команды с другими командами, не беспокоясь об обработке завершения загрузки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package commands.loading {
    import commands.Command;
    import flash.events.Event;
    import flash.media.Sound;
    import flash.net.URLRequest;
     
    /**
     * This command loads a sound.
     */
    public class SoundLoad extends Command {
         
        public var sound:Sound;
        public var url:URLRequest;
         
        public function SoundLoad(sound:Sound, url:URLRequest) {
            this.sound = sound;
            this.url = url;
        }
         
        override protected function execute():void {
             
            //add the complete listener
            sound.addEventListener(Event.COMPLETE, onComplete);
             
            //begin loading
            sound.load(url);
        }
         
        private function onComplete(e:Event):void {
             
            //remove the complete listener
            sound.removeEventListener(Event.COMPLETE, onComplete);
             
            //complete the command
            complete();
        }
    }
}

Интеграция завершена. Будьте готовы к нашему последнему примеру!


В этом примере мы собираемся позволить пользователям воспроизводить две музыки на одной звуковой дорожке. Если звук должен воспроизводиться, когда звуковая дорожка занята, оригинальная музыка сначала исчезает, а затем воспроизводится новая музыка. Затухание обрабатывается командой TweenMaxTo , которая внутренне использует том специальных свойств, предоставленный классом TweenMax из платформы GreenSock Tweening. Эти две музыки — внешние файлы MP3, загруженные во время выполнения.

Обратите внимание, что мы собираемся использовать среду управления сценой. Если вы хотите освежить свою память, проверьте это здесь .


Сделайте копию файла FLA, использованного в предыдущем примере. Переименуйте кнопки в «music1_btn» и «music2_btn». Вы также можете изменить метки кнопок на «Музыка 1» и «Музыка 2». И добавьте дополнительную кнопку с именем «stop_btn», которая предназначена для остановки музыки.


Файлы MP3 можно найти в исходной папке. Скопируйте их в ту же папку, что и FLA-файл.


Создайте новый AS-файл для класса документа нового FLA-файла. Создайте менеджер сцены и инициализируйте его в состояние загрузки, в котором загружаются два файла MP3.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
package {
    import flash.display.Sprite;
    import scenes.SceneManager;
     
    public class MusicPlayer extends Sprite {
         
        public function MusicPlayer() {
             
            //instantiate a scene manager object
            var sceneManager:SceneManager = new SceneManager();
             
            //set a loading scene as the initial scene
            sceneManager.setScene(new LoadingScene(this));
        }
    }
}

Сцена загрузки создает два объекта Sound для загрузки двух файлов MP3. Кнопки становятся невидимыми в начале и снова становятся видимыми после завершения загрузки. Когда загрузка завершена, сцена немедленно инструктирует менеджер сцены перейти к основной сцене, как написано в переопределенном методе onSceneSet () . Дальнейшие подробности описаны в комментариях.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package {
    import commands.Command;
    import 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;
    import scenes.Scene;
 
    public class LoadingScene extends Scene {
         
        //a reference to the document root container
        private var container:MusicPlayer;
         
        public function LoadingScene(container:MusicPlayer) {
            this.container = container;
        }
         
        override public function createIntroCommand():Command {
             
            //create two sound objects to load the two MP3 files
            var music1:Sound = new Sound();
            var music2:Sound = new Sound();
             
            var command:Command =
                new ParallelCommand(0,
                     
                    //hide the buttons
                    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}),
                     
                    //register the two sound objects to the data manager
                    new RegisterData(«music1», music1),
                    new RegisterData(«music2», music2),
                     
                    //begin the loading of the MP3 files
                    new SoundLoad(music1, new URLRequest(«Music1.mp3»)),
                    new SoundLoad(music2, new URLRequest(«Music2.mp3»))
                );
                 
            return command;
        }
         
        override public function onSceneSet():void {
             
            //tell the scene manager to switch to the main scene directly after the intro command is complete
            sceneManager.setScene(new MainScene(container));
        }
    }
}

Основная сцена возвращает скрытые кнопки обратно к видимым и регистрирует метод playMusic () и метод stopMusic () в качестве слушателей события click. В методе playMusic () последовательная команда выполняется, если звуковая дорожка «bgm» занята. Команда сначала временно удаляет прослушиватели щелчков, затухает текущую музыку, останавливает текущую музыку, воспроизводит новую музыку на теперь пустой звуковой дорожке «bgm», а затем, наконец, повторно добавляет прослушиватели щелчков. Метод stopMusic делает в основном то же самое, только при отсутствии воспроизведения новой музыки. Этот сложный ряд действий выполняется всего за несколько строк чистого кода. Довольно аккуратно, а?

Обратите внимание, что добавление и удаление слушателей являются общими действиями, которые присутствуют как в методе playMusic (), так и в методе stopMusic () . Таким образом, они выделяются как два закрытых свойства, addListeners и removeListeners , инициализированные в конструкторе.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package {
    import commands.Command;
    import commands.events.AddEventListener;
    import commands.events.RemoveEventListener;
    import commands.greensock.TweenMaxTo;
    import commands.ParallelCommand;
    import commands.SerialCommand;
    import commands.sounds.PlaySound;
    import commands.sounds.StopSound;
    import data.DataManager;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.media.Sound;
    import flash.utils.Dictionary;
    import scenes.Scene;
    import sounds.SoundManager;
    import sounds.SoundTrack;
     
    /**
     * The main scene is displayed when the loading is complete.
     */
    public class MainScene extends Scene {
         
        //a reference to the document root container
        private var container:MusicPlayer;
         
        private var btn1:Sprite;
        private var btn2:Sprite;
        private var btn3:Sprite;
        private var dataKeys:Dictionary = new Dictionary();
         
        private var addListeners:Command;
        private var removeListeners:Command;
         
        public function MainScene(container:MusicPlayer) {
            this.container = container;
             
            btn1 = container.music1_btn;
            btn2 = container.music2_btn;
            btn3 = container.stop_btn;
             
            //data keys used to retrieve sound objects from the data manager in the playMusic() method
            dataKeys[btn1] = «music1»;
            dataKeys[btn2] = «music2»;
             
            //this command adds all listeners
            addListeners =
                new ParallelCommand(0,
                    new AddEventListener(btn1, MouseEvent.CLICK, playMusic),
                    new AddEventListener(btn2, MouseEvent.CLICK, playMusic),
                    new AddEventListener(btn3, MouseEvent.CLICK, stopMusic)
                );
             
            //this command removes all listeners
            removeListeners =
                new ParallelCommand(0,
                    new RemoveEventListener(btn1, MouseEvent.CLICK, playMusic),
                    new RemoveEventListener(btn2, MouseEvent.CLICK, playMusic),
                    new RemoveEventListener(btn3, MouseEvent.CLICK, stopMusic)
                );
        }
         
        override public function createIntroCommand():Command {
             
            var command:Command =
                new SerialCommand(0,
                     
                    //fade in the buttons
                    new ParallelCommand(0,
                        new TweenMaxTo(btn1, 1, {autoAlpha:1}),
                        new TweenMaxTo(btn2, 1, {autoAlpha:1}),
                        new TweenMaxTo(btn3, 1, {autoAlpha:1})
                    ),
                     
                    //add click listeners
                    addListeners
                );
             
            return command;
        }
         
        /**
         * Plays the music.
         */
        private function playMusic(e:Event):void {
             
            //retrieve the sound object corresponding to a data key
            var music:Sound = DataManager.getData(dataKeys[e.target]);
             
            //check if the BGM sound track is already playing
            if (SoundManager.isPlaying(«bgm»)) {
                 
                //retrieve the playing sound track
                var soundTrack:SoundTrack = SoundManager.getSoundTrack(«bgm»);
                 
                var command:Command =
                    new SerialCommand(0,
                        //temporarily remove click listeners
                        removeListeners,
                         
                        //fade out the current sound track
                        new TweenMaxTo(soundTrack.channel, 1, {volume:0}),
                         
                        //and then stop the sound track
                        new StopSound(«bgm»),
                         
                        //play a new sound on the same sound track
                        new PlaySound(«bgm», music, 0, int.MAX_VALUE),
                         
                        //re-add click listeners
                        addListeners
                    );
                 
                command.start();
            } else {
                 
                //just play the sound if the sound track is idle
                SoundManager.play(«bgm», music, 0, int.MAX_VALUE);
            }
        }
         
        /**
         * Stops the music that is currently playing.
         */
        private function stopMusic(e:Event):void {
             
            //check if the BGM sound track is already playing
            if (SoundManager.isPlaying(«bgm»)) {
                 
                //retrieve the playing sound track
                var soundTrack:SoundTrack = SoundManager.getSoundTrack(«bgm»);
                 
                var command:Command =
                    new SerialCommand(0,
                        //temporarily remove click listeners
                        removeListeners,
                         
                        //fade out the current sound track
                        new TweenMaxTo(soundTrack.channel, 1, {volume:0}),
                         
                        //and then stop the sound track
                        new StopSound(«bgm»),
                         
                        //re-add click listeners
                        addListeners
                    );
                 
                command.start();
            }
        }
    }
}

Мы готовы проверить фильм. Нажмите CTRL + ENTER, чтобы проверить это. Когда вы нажимаете кнопку, музыка начинает играть. После нажатия на другую музыка исчезает, а затем начинается новая.


Это конец урока, я знаю. Но я просто не мог удержаться от того, чтобы показать это тебе. Если вы жокей кода, держу пари, вы уже заметили, что есть много общего в методе playMusic () и методе stopMusic () . Почему бы не объединить их в один? Если вас не интересует эта кодовая версия музыкального плеера, вы можете перейти к разделу с резюме. В противном случае, просто продолжайте читать!

Сначала замените все playMusic и stopMusic в исходном коде на handleMusic , наш новый слушатель событий. Затем удалите playMusic и метод stopMusic и добавьте следующий метод handleMusic () в основной класс сцены.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 * Plays or stops the music.
 */
private function handleMusic(e:Event):void {
     
    var music: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»),
                 
                //determine if we’re going to play another music
                (music)?
                (new PlaySound(«bgm», music, 0, int.MAX_VALUE)):
                (new Dummy()),
                 
                addListeners
            );
         
        command.start();
    } else {
        if (music) SoundManager.play(«bgm», music, 0, int.MAX_VALUE);
    }
}

Вы заметите, что единственным существенным отличием этого метода от оригинальных слушателей является следующий фрагмент кода:

1
2
3
(music)?
(new PlaySound(«bgm», music, 0, int.MAX_VALUE)):
(new Dummy()),

Какого черта это все равно? На самом деле это условный оператор?: Это троичный оператор, означающий, что он требует трех операндов, A, B и C. Оператор «A? B: C» оценивается как B, если A истинно, или C в противном случае. Предполагается, что переменная music содержит ссылку на объект Sound , поэтому переменная оценивается как true. Однако, если целью диспетчера событий является кнопка «stop_btn», переменная содержит нулевое значение, которое оценивается как ложное в троичном операторе. Таким образом, если щелкнуть две музыкальные кнопки, приведенный выше фрагмент кода рассматривается как одна строка кода ниже.

1
new PlaySound(«bgm», music, 0, int.MAX_VALUE)

В противном случае, если нажата кнопка остановки, фрагмент кода считается фиктивной командой, которая просто ничего не делает.

1
new Dummy()

Еще одна вещь, чтобы заметить. Следующая строка кода

1
SoundManager.play(«bgm», music, 0, int.MAX_VALUE);

изменено на

1
if (music) SoundManager.play(«bgm», music, 0, int.MAX_VALUE);

Это для обработки исключения, что звуковая дорожка в настоящее время пуста. Если вы можете понять фрагмент кода выше, я уверен, что вы могли бы понять, о чем эта строка.

Протестируйте фильм, нажав Ctrl + Enter, и вы увидите тот же результат, что и в предыдущем примере. Вы можете расценивать это как выполнение кодового тщеславия жокея кода.


Из этого урока вы узнали, как управлять звуками со звуковыми дорожками. Одна звуковая дорожка позволяет воспроизводить только один звук за раз, поэтому идеально подходит для представления голоса или фоновой музыки одного персонажа. Кроме того, вы узнали, как интегрировать инфраструктуру управления звуком с командной платформой, что дает вам огромное удобство обслуживания и гибкость ваших приложений.

Это конец урока. Надеюсь, вам понравилось. Большое спасибо за чтение!