Komponent Dźwięku (Sound) w Defoldzie jest prosty, ale potężny. Istnieją tylko dwie koncepcje, o których musisz wiedzieć:
Komponenty dźwięku można tworzyć tylko w miejscu w obiekcie gry. Aby utworzyć nowy obiekt gry, kliknij go prawym przyciskiem myszy i wybierz Add Component ▸ Sound oraz kliknij “OK”.
Utworzony komponent ma zestaw właściwości (properties), które powinny zostać ustawione:
Gdy masz komponent dźwięku właściwie skonfigurowany, możesz spowodować odtworzenie dźwięku, wywołując sound.play()
:
sound.play("go#sound", {delay = 1, gain = 0.5, pan = -1.0, speed = 1.25})
Można też wysłać wiadomość "play_sound"
do komponentu dźwięku (szczegóły w dokumentacji):
msg.post("#sound", "play_sound", {delay = 1, gain = 0.5})
Dźwięk będzie nadal odtwarzany nawet wtedy, gdy obiekt gry, do którego należy komponent dźwięku, zostanie usunięty. Możesz wywołać sound.stop()
, aby zatrzymać dźwięk (patrz poniżej).
Każda wywołanie tej funkcji lub wiadomość wysłana do komponentu spowoduje odtworzenie kolejnego wystąpienia dźwięku, aż dostępny bufor dźwięku zostanie wypełniony, a silnik wyświetli błędy w konsoli. Zaleca się zaimplementowanie mechanizmu filtrowania i grupowania dźwięków.
If you wish to stop playing a sound you can call sound.stop()
:
sound.stop("go#sound")
Można też wysłać wiadomość “stop_sound”:
msg.post("#sound", "stop_sound")
System dźwięku ma 4 poziomy wzmocnienia (gain):
sound.play()
lub zmianę wzmocnienia na głosie poprzez wywołanie sound.set_gain()
.sound.set_group_gain()
.sound.set_group_gain(hash("master"))
.Wzmocnienie wyjściowe jest wynikiem przemnóżenia tych 4 wzmocnień. Domyślne wzmocnienie wynosi wszędzie 1.0 (0 dB).
Dowolny komponent dźwięku z określoną nazwą grupy dźwiękowej zostanie umieszczony w grupie dźwiękowej o tej nazwie. Jeśli nie określisz grupy, dźwięk zostanie przypisany do grupy wbudowanej “master”. Możesz także jawnie ustawić grupę na komponencie dźwięku na “master”, co ma ten sam efekt.
Dostępne są pewne funkcje, które pozwalają na pobranie wszystkich dostępnych grup, pobranie nazwy (stringa), ustawienie i pobranie wzmocnienia, średnią kwadratową RMS (patrz http://pl.wikipedia.org/wiki/Root_mean_square) i wzmocnienie szczytowe (ang. peak gain). Istnieje również funkcja, która pozwala sprawdzić, czy czasem aktualnie nie działa odtwarzacz muzyki na urządzeniu docelowym:
-- Jeśli dźwięk jest odtwarzany na tym urządzeniu iPhone/Android, wycisz wszystko
if sound.is_music_playing() then
for i, group_hash in ipairs(sound.get_groups()) do
sound.set_group_gain(group_hash, 0)
end
end
Grupy są identyfikowane za pomocą wartości hash. Nazwę (stringa) można pobrać za pomocą sound.get_group_name()
, co można wykorzystać do wyświetlania nazw grup w narzędziach deweloperskich, na przykład w mikserze do testowania poziomów grup.
Nie należy pisać kodu, który polega na wartości typu string grupy dźwiękowej, ponieważ nie są one dostępne w wersji końcowej, w release.
Wszystkie wartości są liniowe w zakresie od 0 do 1.0 (0 dB). Aby przeliczyć na decybele, wystarczy użyć standardowej formuły:
\[db = 20 \times \log \left( gain \right)\]for i, group_hash in ipairs(sound.get_groups()) do
-- Nazwa w typie string jest dostępna tylko w trybie debug. Zwraca "unknown_*" w wersji końcowej.
local name = sound.get_group_name(group_hash)
local gain = sound.get_group_gain(group_hash)
-- Przelicz na decybele.
local db = 20 * math.log10(gain)
-- Pobierz średnią kwadratową RMS (Root Mean Square). Lewy i prawy kanał oddzielnie.
local left_rms, right_rms = sound.get_rms(group_hash, 2048 / 65536.0)
left_rmsdb = 20 * math.log10(left_rms)
right_rmsdb = 20 * math.log10(right_rms)
-- Pobierz wzmocnienie szczytowe. Lewy i prawy kanał oddzielnie.
left_peak, right_peak = sound.get_peak(group_hash, 2048 * 10 / 65536.0)
left_peakdb = 20 * math.log10(left_peak)
right_peakdb = 20 * math.log10(right_peak)
end
-- Ustaw wzmocnienie grupy "master" na +6 dB (math.pow(10, 6/20)).
sound.set_group_gain("master", 1.995)
Jeśli Twoja gra odtwarza ten sam dźwięk w przypadku zdarzenia, a to zdarzenie jest często wyzwalane, istnieje ryzyko odtwarzania tego samego dźwięku dwa lub więcej razy niemal jednocześnie. W takim przypadku dźwięki zostaną przesunięte fazowo, co może prowadzić do wyraźnych artefaktów.
Najprostszym sposobem radzenia sobie z tym problemem jest stworzenie bramy (gate), która filtrowałaby wiadomości dźwiękowe i nie pozwalałaby na odtworzenie tego samego dźwięku więcej niż raz w określonym odstępie czasu:
-- Nie pozwól na odtworzenie tego samego dźwięku w określonym odstępie czasu "gate_time".
local gate_time = 0.3
function init(self)
-- Przechowuj timery odtwarzanych dźwięków w tabeli i odliczaj każdy klatkowy,
-- aż będą w tabeli przez "gate_time" sekundy. Następnie usuń je.
self.sounds = {}
end
function update(self, dt)
-- Odliczaj zapisane timery
for k,_ in pairs(self.sounds) do
self.sounds[k] = self.sounds[k] - dt
if self.sounds[k] < 0 then
self.sounds[k] = nil
end
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("play_gated_sound") then
-- Odtwarzaj tylko dźwięki, które nie znajdują się obecnie w tabeli filtrującej.
if self.sounds[message.soundcomponent] == nil then
-- Zapisz timer dźwięku w tabeli
self.sounds[message.soundcomponent] = gate_time
-- Odtwórz dźwięk
sound.play(message.soundcomponent, { gain = message.gain })
else
-- Próba odtworzenia dźwięku była filtrowana
print("gated " .. message.soundcomponent)
end
end
end
Aby skorzystać teraz z takiej bramy, po prostu wyślij jej wiadomość play_gated_sound
i określ docelowy komponent dźwięku oraz wzmocnienie dźwięku. Brama wywoła sound.play()
z docelowym komponentem dźwięku, jeśli jest otwarta:
msg.post("/sound_gate#script", "play_gated_sound", { soundcomponent = "/sounds#explosion1", gain = 1.0 })
Nie zadziała to, gdy brama nasłuchiwać będzie wiadomości play_sound
, ponieważ ta nazwa jest zarezerwowana przez silnik Defold. Mamy do czynienia z nieoczekiwanym zachowaniem, jeśli użyjesz zarezerwowanych nazw wiadomości.
Możesz manipulować dźwiękami w czasie rzeczywistym za pomocą różnych właściwości (szczegóły w dokumentacji API). Następujące właściwości można manipulować przy użyciu go.get()
i go.set()
:
gain
number
).pan
number
). Panorama musi mieć wartość między -1 (lewo - 45 stopni) a 1 (prawo - 45 stopni). Dzięki panoramie mamy kontrolę nad tym, z której strony (lub też – z którego głośnika) dźwięk odtwarzany jest z większa głośnością.speed
number
). Wartość 1.0 to normalna prędkość, 0.5 to prędkość o połowę mniejsza, a 2.0 to prędkość podwójna.sound
hash)
. Możesz użyć ścieżki zasobu do zmiany dźwięku za pomocą resource.set_sound(path, buffer)
. Przykład:local boom = sys.load_resource("/sounds/boom.wav")
local path = go.get("#sound", "sound")
resource.set_sound(path, boom)
Plik game.project zawiera kilka ustawień projektu związanych z komponentami dźwięku.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB