1// Sound effects example
2// This sample demonstrates:
3//     - Playing sound effects and music
4//     - Controlling sound and music master volume
5
6#include "Scripts/Utilities/Sample.as"
7
8Array<String> soundNames = {
9    "Fist",
10    "Explosion",
11    "Power-up"
12};
13
14Array<String> soundResourceNames = {
15    "Sounds/PlayerFistHit.wav",
16    "Sounds/BigExplosion.wav",
17    "Sounds/Powerup.wav"
18};
19
20SoundSource@ musicSource;
21
22void Start()
23{
24    // Execute the common startup for samples
25    SampleStart();
26
27    // Create a scene which will not be actually rendered, but is used to hold SoundSource components while they play sounds
28    scene_ = Scene();
29
30    // Create music sound source
31    @musicSource = scene_.CreateComponent("SoundSource");
32    // Set the sound type to music so that master volume control works correctly
33    musicSource.soundType = SOUND_MUSIC;
34
35    // Enable OS cursor
36    input.mouseVisible = true;
37
38    // Create the user interface
39    CreateUI();
40
41    // Set the mouse mode to use in the sample
42    SampleInitMouseMode(MM_FREE);
43}
44
45void CreateUI()
46{
47    XMLFile@ uiStyle = cache.GetResource("XMLFile", "UI/DefaultStyle.xml");
48    // Set style to the UI root so that elements will inherit it
49    ui.root.defaultStyle = uiStyle;
50
51    // Create buttons for playing back sounds
52    for (uint i = 0; i < soundNames.length; ++i)
53    {
54        Button@ button = CreateButton(i * 140 + 20, 20, 120, 40, soundNames[i]);
55        // Store the sound effect resource name as a custom variable into the button
56        button.vars["SoundResource"] = soundResourceNames[i];
57        SubscribeToEvent(button, "Pressed", "HandlePlaySound");
58    }
59
60    // Create buttons for playing/stopping music
61    Button@ button = CreateButton(20, 80, 120, 40, "Play Music");
62    SubscribeToEvent(button, "Released", "HandlePlayMusic");
63
64    button = CreateButton(160, 80, 120, 40, "Stop Music");
65    SubscribeToEvent(button, "Released", "HandleStopMusic");
66
67    // Create sliders for controlling sound and music master volume
68    Slider@ slider = CreateSlider(20, 140, 200, 20, "Sound Volume");
69    slider.value = audio.masterGain[SOUND_EFFECT];
70    SubscribeToEvent(slider, "SliderChanged", "HandleSoundVolume");
71
72    slider = CreateSlider(20, 200, 200, 20, "Music Volume");
73    slider.value = audio.masterGain[SOUND_MUSIC];
74    SubscribeToEvent(slider, "SliderChanged", "HandleMusicVolume");
75}
76
77Button@ CreateButton(int x, int y, int xSize, int ySize, const String&in text)
78{
79    Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
80
81    // Create the button and center the text onto it
82    Button@ button = ui.root.CreateChild("Button");
83    button.SetStyleAuto();
84    button.SetPosition(x, y);
85    button.SetSize(xSize, ySize);
86
87    Text@ buttonText = button.CreateChild("Text");
88    buttonText.SetAlignment(HA_CENTER, VA_CENTER);
89    buttonText.SetFont(font, 12);
90    buttonText.text = text;
91
92    return button;
93}
94
95Slider@ CreateSlider(int x, int y, int xSize, int ySize, const String& text)
96{
97    Font@ font = cache.GetResource("Font", "Fonts/Anonymous Pro.ttf");
98
99    // Create text and slider below it
100    Text@ sliderText = ui.root.CreateChild("Text");
101    sliderText.SetPosition(x, y);
102    sliderText.SetFont(font, 12);
103    sliderText.text = text;
104
105    Slider@ slider = ui.root.CreateChild("Slider");
106    slider.SetStyleAuto();
107    slider.SetPosition(x, y + 20);
108    slider.SetSize(xSize, ySize);
109    // Use 0-1 range for controlling sound/music master volume
110    slider.range = 1.0f;
111
112    return slider;
113}
114
115void HandlePlaySound(StringHash eventType, VariantMap& eventData)
116{
117    Button@ button = GetEventSender();
118    String soundResourceName = button.vars["SoundResource"].GetString();
119
120    // Get the sound resource
121    Sound@ sound = cache.GetResource("Sound", soundResourceName);
122
123    if (sound !is null)
124    {
125        // Create a SoundSource component for playing the sound. The SoundSource component plays
126        // non-positional audio, so its 3D position in the scene does not matter. For positional sounds the
127        // SoundSource3D component would be used instead
128        SoundSource@ soundSource = scene_.CreateComponent("SoundSource");
129        soundSource.autoRemoveMode = REMOVE_COMPONENT;
130        soundSource.Play(sound);
131        // In case we also play music, set the sound volume below maximum so that we don't clip the output
132        soundSource.gain = 0.7f;
133    }
134}
135
136void HandlePlayMusic(StringHash eventType, VariantMap& eventData)
137{
138    Sound@ music = cache.GetResource("Sound", "Music/Ninja Gods.ogg");
139    // Set the song to loop
140    music.looped = true;
141
142    musicSource.Play(music);
143}
144
145void HandleStopMusic(StringHash eventType, VariantMap& eventData)
146{
147    musicSource.Stop();
148}
149
150void HandleSoundVolume(StringHash eventType, VariantMap& eventData)
151{
152    float newVolume = eventData["Value"].GetFloat();
153    audio.masterGain[SOUND_EFFECT] = newVolume;
154}
155
156void HandleMusicVolume(StringHash eventType, VariantMap& eventData)
157{
158    float newVolume = eventData["Value"].GetFloat();
159    audio.masterGain[SOUND_MUSIC] = newVolume;
160}
161
162// Create XML patch instructions for screen joystick layout specific to this sample app
163String patchInstructions =
164        "<patch>" +
165        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button2']]\">" +
166        "        <attribute name=\"Is Visible\" value=\"false\" />" +
167        "    </add>" +
168        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
169        "        <attribute name=\"Is Visible\" value=\"false\" />" +
170        "    </add>" +
171        "</patch>";
172