AudioManager.gd 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. extends Node
  2. const DEFAULT_SFX_LIBRARY := {
  3. "small_jump": ("res://Assets/Audio/SFX/SmallJump.wav"),
  4. "big_jump": ("res://Assets/Audio/SFX/BigJump.wav"),
  5. "coin": ("res://Assets/Audio/SFX/Coin.wav"),
  6. "bump": ("res://Assets/Audio/SFX/Bump.wav"),
  7. "pipe": ("res://Assets/Audio/SFX/Pipe.wav"),
  8. "damage": ("res://Assets/Audio/SFX/Damage.wav"),
  9. "power_up": ("res://Assets/Audio/SFX/Powerup.wav"),
  10. "item_appear": ("res://Assets/Audio/SFX/ItemAppear.wav"),
  11. "block_break": ("res://Assets/Audio/SFX/BreakBlock.wav"),
  12. "enemy_stomp": ("res://Assets/Audio/SFX/Stomp.wav"),
  13. "kick": ("res://Assets/Audio/SFX/Kick.wav"),
  14. "fireball": ("res://Assets/Audio/SFX/Fireball.wav"),
  15. "1_up": ("res://Assets/Audio/SFX/1up.wav"),
  16. "cannon": ("res://Assets/Audio/SFX/Cannon.wav"),
  17. "checkpoint": ("res://Assets/Audio/SFX/Checkpoint.wav"),
  18. "magic": ("res://Assets/Audio/SFX/Magic.wav"),
  19. "beep": ("res://Assets/Audio/SFX/Score.wav"),
  20. "switch": ("res://Assets/Audio/SFX/Switch.wav"),
  21. "boo_laugh": ("res://Assets/Audio/SFX/BooLaugh.wav"),
  22. "icicle_fall": ("res://Assets/Audio/SFX/IcicleFall.wav"),
  23. "icicle_break": ("res://Assets/Audio/SFX/IcicleCrash.wav"),
  24. "score": "res://Assets/Audio/SFX/ScoreLoop.wav",
  25. "score_end": "res://Assets/Audio/SFX/Score.wav",
  26. "pause": ("res://Assets/Audio/SFX/Pause.wav"),
  27. "spring": ("res://Assets/Audio/SFX/Spring.wav"),
  28. "swim": ("res://Assets/Audio/SFX/Swim.wav"),
  29. "dry_bones_crumble": ("res://Assets/Audio/SFX/DryBonesCrumble.wav"),
  30. "clock_get": ("res://Assets/Audio/SFX/ClockGet.wav"),
  31. "bowser_flame": ("res://Assets/Audio/SFX/BowserFire.wav"),
  32. "correct": ("res://Assets/Audio/SFX/Correct.wav"),
  33. "note_block": ("res://Assets/Audio/SFX/NoteBlock.wav"),
  34. "podoboo": ("res://Assets/Audio/SFX/Podoboo.wav"),
  35. "hammer_throw": ("res://Assets/Audio/SFX/HammerThrow.wav"),
  36. "firework": "res://Assets/Audio/SFX/Firework.wav",
  37. "timer_beep": "res://Assets/Audio/SFX/TimerBeep.wav",
  38. "hachisuke": "res://Assets/Audio/SFX/Hachisuke.wav",
  39. "burner": "res://Assets/Audio/SFX/Burner.wav",
  40. "rank_up_1": "res://Assets/Audio/SFX/RankUpCBA.wav",
  41. "rank_up_2": "res://Assets/Audio/SFX/RankUpSP.wav",
  42. "rank_down": "res://Assets/Audio/SFX/RankDown.wav",
  43. "combo_lost": "res://Assets/Audio/SFX/ComboMeterLoss.wav",
  44. "lakitu_throw": "res://Assets/Audio/SFX/LakituThrow.wav",
  45. "lift_fall": "res://Assets/Audio/SFX/LiftFall.wav",
  46. "cheep_cheep": "res://Assets/Audio/SFX/CheepCheepJump.wav",
  47. "menu_move": "res://Assets/Audio/SFX/MenuNavigate.wav",
  48. "timer_warning": "res://Assets/Audio/SFX/TimerRunningLow.wav",
  49. "door_open": "res://Assets/Audio/SFX/DoorOpen.wav",
  50. "door_close": "res://Assets/Audio/SFX/DoorClose.wav",
  51. "key_collect": "res://Assets/Audio/SFX/KeyCollect.wav",
  52. "lucky_star": "res://Assets/Audio/SFX/LuckyStar.wav",
  53. "bumper": "res://Assets/Audio/SFX/Bumper.wav",
  54. "bumper_high": "res://Assets/Audio/SFX/BumperHigh.wav",
  55. "door_unlock": "res://Assets/Audio/SFX/DoorUnlock.wav",
  56. "door_locked": "res://Assets/Audio/SFX/DoorLocked.wav"
  57. }
  58. @onready var sfx_library = DEFAULT_SFX_LIBRARY.duplicate()
  59. @onready var music_player: AudioStreamPlayer = $Music
  60. @onready var music_override_player: AudioStreamPlayer = $MusicOverride
  61. var music_override_priority := -1
  62. var active_sfxs := {}
  63. var current_level_theme := ""
  64. var current_clip_idx := 0
  65. signal music_beat
  66. var queued_sfxs := []
  67. var current_music_override: MUSIC_OVERRIDES
  68. enum MUSIC_OVERRIDES{NONE=-1, STAR=0, DEATH, PSWITCH, BOWSER, TIME_WARNING, LEVEL_COMPLETE, CASTLE_COMPLETE, ENDING, FLAG_POLE, HAMMER, RACE_LOSE, RACE_WIN, WING, COIN_HEAVEN_BONUS}
  69. const OVERRIDE_STREAMS := [
  70. ("res://Assets/Audio/BGM/StarMan.json"),
  71. ("res://Assets/Audio/BGM/PlayerDie.json"),
  72. ("res://Assets/Audio/BGM/PSwitch.json"),
  73. "res://Assets/Audio/BGM/Bowser.json",
  74. "res://Assets/Audio/BGM/Hurry.json",
  75. "res://Assets/Audio/BGM/LevelFinish.json",
  76. "res://Assets/Audio/BGM/CastleFinish.json",
  77. "res://Assets/Audio/BGM/Ending.json",
  78. "res://Assets/Audio/SFX/FlagSlide.wav",
  79. "res://Assets/Audio/BGM/Hammer.mp3",
  80. ("res://Assets/Audio/BGM/LoseRace.json"),
  81. ("res://Assets/Audio/BGM/WinRace.json"),
  82. "res://Assets/Audio/BGM/Wing.json",
  83. "res://Assets/Audio/BGM/PerfectCoinHeaven.mp3"
  84. ]
  85. const MUSIC_BASE = preload("uid://da4vqkrpqnma0")
  86. var character_sfx_map := {}
  87. var audio_override_queue := []
  88. func play_sfx(stream_name = "", position := Vector2.ZERO, pitch := 1.0) -> void:
  89. if queued_sfxs.has(stream_name):
  90. return
  91. queued_sfxs.append(stream_name)
  92. if stream_name is String:
  93. if active_sfxs.has(stream_name):
  94. active_sfxs[stream_name].queue_free()
  95. var player = AudioStreamPlayer2D.new()
  96. player.global_position = position
  97. var stream = stream_name
  98. var is_custom = false
  99. if stream_name is String:
  100. is_custom = sfx_library[stream_name].contains("user://custom_characters")
  101. stream = import_stream(sfx_library[stream_name])
  102. if is_custom == false:
  103. player.stream = ResourceSetter.get_resource(stream, player)
  104. else:
  105. player.stream = stream
  106. player.autoplay = true
  107. player.pitch_scale = pitch
  108. player.max_distance = 99999
  109. player.bus = "SFX"
  110. add_child(player)
  111. active_sfxs[stream_name] = player
  112. queued_sfxs.erase(stream_name)
  113. await player.finished
  114. active_sfxs.erase(stream_name)
  115. player.queue_free()
  116. func play_global_sfx(stream_name := "") -> void:
  117. if get_viewport().get_camera_2d() == null:
  118. return
  119. play_sfx(stream_name, get_viewport().get_camera_2d().get_screen_center_position())
  120. func _process(_delta: float) -> void:
  121. handle_music()
  122. func on_beat(idx := 0) -> void:
  123. music_beat.emit(idx)
  124. func stop_all_music() -> void:
  125. AudioManager.music_player.stop()
  126. if Global.current_level != null:
  127. Global.current_level.music = null
  128. AudioManager.audio_override_queue.clear()
  129. AudioManager.stop_music_override(MUSIC_OVERRIDES.NONE, true)
  130. func kill_sfx(sfx_name := "") -> void:
  131. print(active_sfxs)
  132. if active_sfxs.has(sfx_name):
  133. active_sfxs[sfx_name].queue_free()
  134. active_sfxs.erase(sfx_name)
  135. func set_music_override(stream: MUSIC_OVERRIDES, priority := 0, stop_on_finish := true, restart := true) -> void:
  136. if audio_override_queue.has(stream):
  137. if current_music_override == stream and restart:
  138. music_override_player.play()
  139. return
  140. if music_override_priority > priority:
  141. audio_override_queue.push_front(stream)
  142. return
  143. else:
  144. audio_override_queue.append(stream)
  145. current_music_override = stream
  146. print(OVERRIDE_STREAMS[stream])
  147. music_override_player.stream = create_stream_from_json(OVERRIDE_STREAMS[stream])
  148. music_override_player.bus = "Music" if stream != MUSIC_OVERRIDES.FLAG_POLE else "SFX"
  149. music_override_player.play()
  150. music_override_priority = priority
  151. if stop_on_finish:
  152. await music_override_player.finished
  153. stop_music_override(stream)
  154. func stop_music_override(stream: MUSIC_OVERRIDES, force := false) -> void:
  155. if not force:
  156. if stream == null:
  157. return
  158. elif stream != current_music_override:
  159. audio_override_queue.erase(stream)
  160. return
  161. audio_override_queue.pop_back()
  162. current_music_override = MUSIC_OVERRIDES.NONE
  163. music_override_player.stop()
  164. music_override_priority = -1
  165. if audio_override_queue.is_empty():
  166. audio_override_queue.clear()
  167. music_override_priority = -1
  168. current_music_override = MUSIC_OVERRIDES.NONE
  169. music_override_player.stop()
  170. else:
  171. set_music_override(audio_override_queue[audio_override_queue.size() - 1])
  172. func load_sfx_map(json := {}) -> void:
  173. sfx_library = DEFAULT_SFX_LIBRARY.duplicate()
  174. for i in json:
  175. sfx_library[i] = json[i]
  176. print(json)
  177. func handle_music() -> void:
  178. if Global.in_title_screen:
  179. current_level_theme = ""
  180. AudioServer.set_bus_effect_enabled(1, 0, Global.game_paused)
  181. if is_instance_valid(Global.current_level):
  182. if Global.current_level.music == null or current_music_override != MUSIC_OVERRIDES.NONE:
  183. music_player.stop()
  184. handle_music_override()
  185. return
  186. music_player.stream_paused = false
  187. if current_level_theme != Global.current_level.music.resource_path and Global.current_level.music != null:
  188. var stream = create_stream_from_json(Global.current_level.music.resource_path)
  189. music_player.stream = stream
  190. current_level_theme = Global.current_level.music.resource_path
  191. if music_player.is_playing() == false and current_music_override == MUSIC_OVERRIDES.NONE:
  192. music_player.stop()
  193. current_music_override = MUSIC_OVERRIDES.NONE
  194. music_player.play()
  195. if music_player.stream is AudioStreamInteractive and music_player.is_playing():
  196. if Global.time <= 100:
  197. if music_player.get_stream_playback().get_current_clip_index() != 1:
  198. music_player.get_stream_playback().switch_to_clip(1)
  199. elif music_player.get_stream_playback().get_current_clip_index() != 0:
  200. music_player.get_stream_playback().switch_to_clip(0)
  201. if DiscoLevel.in_disco_level:
  202. music_player.pitch_scale = 2
  203. func handle_music_override() -> void:
  204. if music_override_player.stream is AudioStreamInteractive and music_override_player.is_playing():
  205. if Global.time <= 100:
  206. if music_override_player.get_stream_playback().get_current_clip_index() != 1:
  207. music_override_player.get_stream_playback().switch_to_clip(1)
  208. elif music_override_player.get_stream_playback().get_current_clip_index() != 0:
  209. music_override_player.get_stream_playback().switch_to_clip(0)
  210. func create_stream_from_json(json_path := "") -> AudioStream:
  211. if json_path.contains(".json") == false:
  212. var path = ResourceSetter.get_pure_resource_path(json_path)
  213. if path.contains("user://"):
  214. match json_path.get_slice(".", 1):
  215. "wav":
  216. return AudioStreamWAV.load_from_file(ResourceSetter.get_pure_resource_path(json_path))
  217. "mp3":
  218. return AudioStreamMP3.load_from_file(ResourceSetter.get_pure_resource_path(json_path))
  219. elif path.contains("res://"):
  220. return load(path)
  221. var bgm_file = $ResourceSetterNew.get_variation_json(JSON.parse_string(FileAccess.open(ResourceSetter.get_pure_resource_path(json_path), FileAccess.READ).get_as_text()).variations).source
  222. var path = json_path.replace(json_path.get_file(), bgm_file)
  223. path = ResourceSetter.get_pure_resource_path(path)
  224. var stream = null
  225. if path.get_file().contains(".bgm"):
  226. stream = generate_interactive_stream(JSON.parse_string(FileAccess.open(path, FileAccess.READ).get_as_text()))
  227. else:
  228. if path.contains("res://"):
  229. stream = load(path)
  230. else:
  231. stream = AudioStreamMP3.load_from_file(path)
  232. return stream
  233. func generate_interactive_stream(bgm_file := {}) -> AudioStreamInteractive:
  234. var stream = MUSIC_BASE.duplicate()
  235. var normal_path = ResourceSetter.get_pure_resource_path("res://Assets/Audio/BGM/" + bgm_file.Normal.source)
  236. var hurry_path = ResourceSetter.get_pure_resource_path("res://Assets/Audio/BGM/" + bgm_file.Hurry.source)
  237. stream.set_clip_stream(0, import_stream(normal_path, bgm_file.Normal.loop))
  238. stream.set_clip_stream(1, import_stream(hurry_path, bgm_file.Hurry.loop))
  239. return stream
  240. func import_stream(file_path := "", loop_point := -1.0) -> AudioStream:
  241. var path = file_path
  242. var stream = null
  243. if path.contains("res://"):
  244. stream = load(path)
  245. elif path.contains(".mp3"):
  246. stream = AudioStreamMP3.load_from_file(ResourceSetter.get_pure_resource_path(file_path))
  247. elif path.contains(".wav"):
  248. stream = AudioStreamWAV.load_from_file(path)
  249. print([path, stream])
  250. if path.contains(".mp3"):
  251. stream.set_loop(loop_point >= 0)
  252. stream.set_loop_offset(loop_point)
  253. return stream