Skip to content

Instantly share code, notes, and snippets.

@afk-mario
Last active March 17, 2023 02:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save afk-mario/c6ce7768fca750b0efafd3eae1999271 to your computer and use it in GitHub Desktop.
Save afk-mario/c6ce7768fca750b0efafd3eae1999271 to your computer and use it in GitHub Desktop.
SFX Manager
tool
extends Resource
class_name SfxEvent, "res://ui/editor_icons/sfx.svg"
const PROPERTY_HINT_TYPE_STRING := PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS + 2
enum SEQUENCE_TYPE { RANDOM, LOOP, HOLD }
enum SEQUENCE_RESET { TIME, NEVER }
var audio_streams: Array
var sequence_type: int setget _set_sequence_type
var sequence_reset: int setget _set_sequence_reset
var sequence_reset_time := 1.0
var volume_randomize := false setget _set_volume_random
var volume_db := 0.0
var volume_min := 0.0
var volume_max := 0.0
var pitch_randomize := false setget _set_pitch_random
var pitch_scale := 1.0
var pitch_min := 0.01
var pitch_max := 4.0
func _set_volume_random(value: bool) -> void:
volume_randomize = value
property_list_changed_notify()
func _set_pitch_random(value: bool) -> void:
pitch_randomize = value
property_list_changed_notify()
func _set_sequence_type(value: int) -> void:
sequence_type = value
property_list_changed_notify()
func _set_sequence_reset(value: int) -> void:
sequence_reset = value
property_list_changed_notify()
func property_can_revert(property):
if property == "volume_db":
return true
if property == "sequence_reset_time":
return true
return false
func property_get_revert(property):
if property == "volume_db":
return 0.0
if property == "sequence_reset_time":
return 1.0
func _get_property_list() -> Array:
var properties = []
#https://stackoverflow.com/questions/71175503/how-to-add-array-with-hint-and-hint-string
properties.append(
{
name = "audio_streams",
type = TYPE_ARRAY,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_TYPE_STRING,
hint_string = str(TYPE_OBJECT) + ":"
}
)
properties.append(
{
name = "Sequence",
type = TYPE_NIL,
hint_string = "sequence_",
usage = PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SCRIPT_VARIABLE
}
)
properties.append(
{
name = "sequence_type",
type = TYPE_INT,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_ENUM,
hint_string = PoolStringArray(SEQUENCE_TYPE.keys()).join(",").capitalize()
}
)
if sequence_type != SEQUENCE_TYPE.RANDOM:
properties.append(
{
name = "sequence_reset",
type = TYPE_INT,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_ENUM,
hint_string = PoolStringArray(SEQUENCE_RESET.keys()).join(",").capitalize()
}
)
if sequence_reset == SEQUENCE_RESET.TIME:
properties.append(
{
name = "sequence_reset_time",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_RANGE,
hint_string = "0.0,10.0,.01"
}
)
properties.append(
{
name = "Volume",
type = TYPE_NIL,
hint_string = "volume_",
usage = PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SCRIPT_VARIABLE
}
)
properties.append({name = "volume_randomize", type = TYPE_BOOL})
if not volume_randomize:
properties.append(
{
name = "volume_db",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_EXP_RANGE,
hint_string = "-80.0,24.0,.001"
}
)
else:
properties.append(
{
name = "volume_min",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_EXP_RANGE,
hint_string = "-80.0,24.0,.001"
}
)
properties.append(
{
name = "volume_max",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_EXP_RANGE,
hint_string = "-80.0,24.0,.001"
}
)
properties.append(
{
name = "Pitch",
type = TYPE_NIL,
hint_string = "pitch_",
usage = PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SCRIPT_VARIABLE
}
)
properties.append({name = "pitch_randomize", type = TYPE_BOOL})
if not pitch_randomize:
properties.append(
{
name = "pitch_scale",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_RANGE,
hint_string = "0.01,4.0"
}
)
else:
properties.append(
{
name = "pitch_min",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_RANGE,
hint_string = "0.01,4.0"
}
)
properties.append(
{
name = "pitch_max",
type = TYPE_REAL,
usage = PROPERTY_USAGE_DEFAULT,
hint = PROPERTY_HINT_RANGE,
hint_string = "0.01,4.0"
}
)
return properties
extends Node
# Using this addon as a base for sound busses
# https://github.com/nathanhoad/godot_sound_manager
const events_dir := "res://sfx/events/"
var events_dict := {}
var events_sequence := {}
var events_timers := {}
func _init() -> void:
var dir = Directory.new()
assert(dir.open(events_dir) == OK)
dir.list_dir_begin(true, true)
var filename = dir.get_next()
while filename != "":
var name: String = filename.get_file().split(".")[0]
events_dict[name] = load(events_dir + filename)
filename = dir.get_next()
func _ready() -> void:
SoundManager.set_sound_volume(SettingsSaved.data.get("sfx_volume", 1.0))
func play(event_name: String) -> AudioStreamPlayer:
var event: SfxEvent = events_dict.get(event_name, null)
if event == null:
push_warning("No sfx event named " + event_name)
return null
return play_event(event)
func play_event(event: SfxEvent) -> AudioStreamPlayer:
var event_name := event.get_path().get_file().split(".")[0]
if event.audio_streams.size() < 1:
push_warning("Sfx event " + event_name + " has empty audio_streams")
return null
var index: int = events_sequence.get(event_name, 0)
if event.sequence_type == SfxEvent.SEQUENCE_TYPE.RANDOM:
index = randi() % event.audio_streams.size()
var audio: AudioStream = event.audio_streams[index]
var player := SoundManager.play_sound(audio)
if event.pitch_randomize:
player.pitch_scale = rand_range(event.pitch_min, event.pitch_max)
else:
player.pitch_scale = event.pitch_scale
if event.volume_randomize:
player.volume_db = rand_range(event.volume_min, event.volume_max)
else:
player.volume_db = event.volume_db
if event.sequence_type != SfxEvent.SEQUENCE_TYPE.RANDOM:
if event.sequence_type == SfxEvent.SEQUENCE_TYPE.LOOP:
index = (index + 1) % event.audio_streams.size()
elif event.sequence_type == SfxEvent.SEQUENCE_TYPE.HOLD:
index = int(min(index + 1, event.audio_streams.size() - 1))
if event.sequence_reset == SfxEvent.SEQUENCE_RESET.TIME:
var timer: SceneTreeTimer = events_timers.get(event_name, null)
if timer != null:
timer.disconnect("timeout", self, "_on_timer_timeout")
timer.emit_signal("timeout")
timer = null
timer = get_tree().create_timer(event.sequence_reset_time)
events_timers[event_name] = timer
assert(timer.connect("timeout", self, "_on_timer_timeout", [event_name]) == OK)
events_sequence[event_name] = index
return player
func _on_timer_timeout(event_name: String) -> void:
events_sequence[event_name] = 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment