Add looping gameplay music
This commit is contained in:
Binary file not shown.
@@ -278,6 +278,10 @@ class KeyBindings:
|
|||||||
|
|
||||||
def toggle_audio(self):
|
def toggle_audio(self):
|
||||||
self.render_engine.audio = not self.render_engine.audio
|
self.render_engine.audio = not self.render_engine.audio
|
||||||
|
self.audio = self.render_engine.audio
|
||||||
|
if not self.render_engine.audio:
|
||||||
|
self.render_engine.stop_sound()
|
||||||
|
|
||||||
def toggle_pause(self):
|
def toggle_pause(self):
|
||||||
self.game_status = "paused" if self.game_status == "game" else "game"
|
self.game_status = "paused" if self.game_status == "game" else "game"
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ from ctypes import *
|
|||||||
|
|
||||||
import sdl2
|
import sdl2
|
||||||
import sdl2.ext
|
import sdl2.ext
|
||||||
|
try:
|
||||||
|
import sdl2.sdlmixer as sdlmixer
|
||||||
|
except ImportError:
|
||||||
|
sdlmixer = None
|
||||||
from sdl2.ext.compat import byteify
|
from sdl2.ext.compat import byteify
|
||||||
from sdl2 import SDL_AudioSpec
|
from sdl2 import SDL_AudioSpec
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
@@ -124,6 +128,73 @@ class GameWindow:
|
|||||||
self.audio_devs["base"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["base"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
self.audio_devs["effects"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["effects"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
self.audio_devs["music"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
self.audio_devs["music"] = sdl2.SDL_OpenAudioDevice(None, 0, audio_spec, None, 0)
|
||||||
|
self.music_enabled = False
|
||||||
|
self.music_volume = 128
|
||||||
|
self.music_track = None
|
||||||
|
self.music_path = None
|
||||||
|
|
||||||
|
if sdlmixer is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
mixer_flags = getattr(sdlmixer, "MIX_INIT_MP3", 0)
|
||||||
|
init_result = sdlmixer.Mix_Init(mixer_flags)
|
||||||
|
if mixer_flags and init_result & mixer_flags != mixer_flags:
|
||||||
|
print("[audio] SDL_mixer MP3 support not available")
|
||||||
|
return
|
||||||
|
|
||||||
|
if sdlmixer.Mix_OpenAudio(44100, sdl2.AUDIO_S16SYS, sdlmixer.MIX_DEFAULT_CHANNELS, 2048) != 0:
|
||||||
|
print(f"[audio] failed to open music mixer: {sdl2.SDL_GetError()}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.music_enabled = True
|
||||||
|
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
||||||
|
|
||||||
|
def set_volume(self, volume_percent):
|
||||||
|
clamped = max(0, min(int(volume_percent), 100))
|
||||||
|
self.music_volume = int(round(clamped * 128 / 100))
|
||||||
|
if self.music_enabled and sdlmixer is not None:
|
||||||
|
sdlmixer.Mix_VolumeMusic(self.music_volume)
|
||||||
|
|
||||||
|
def play_music(self, music_file, loop=True):
|
||||||
|
if not self.audio or not self.music_enabled or sdlmixer is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
music_path = str(resolve_bundle_path(os.path.join("assets", "music", music_file)))
|
||||||
|
if self.music_path != music_path:
|
||||||
|
self._free_music_track()
|
||||||
|
self.music_track = sdlmixer.Mix_LoadMUS(byteify(music_path, "utf-8"))
|
||||||
|
if not self.music_track:
|
||||||
|
print(f"[audio] failed to load music: {music_path}")
|
||||||
|
return False
|
||||||
|
self.music_path = music_path
|
||||||
|
|
||||||
|
if sdlmixer.Mix_PausedMusic():
|
||||||
|
sdlmixer.Mix_ResumeMusic()
|
||||||
|
return True
|
||||||
|
|
||||||
|
if sdlmixer.Mix_PlayingMusic():
|
||||||
|
return True
|
||||||
|
|
||||||
|
loops = -1 if loop else 0
|
||||||
|
if sdlmixer.Mix_PlayMusic(self.music_track, loops) != 0:
|
||||||
|
print(f"[audio] failed to play music: {music_path}")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def pause_music(self):
|
||||||
|
if self.music_enabled and sdlmixer is not None and sdlmixer.Mix_PlayingMusic() and not sdlmixer.Mix_PausedMusic():
|
||||||
|
sdlmixer.Mix_PauseMusic()
|
||||||
|
|
||||||
|
def stop_music(self):
|
||||||
|
if self.music_enabled and sdlmixer is not None and (sdlmixer.Mix_PlayingMusic() or sdlmixer.Mix_PausedMusic()):
|
||||||
|
sdlmixer.Mix_HaltMusic()
|
||||||
|
|
||||||
|
def _free_music_track(self):
|
||||||
|
self.stop_music()
|
||||||
|
if self.music_enabled and sdlmixer is not None and self.music_track is not None:
|
||||||
|
sdlmixer.Mix_FreeMusic(self.music_track)
|
||||||
|
self.music_track = None
|
||||||
|
self.music_path = None
|
||||||
|
|
||||||
# ======================
|
# ======================
|
||||||
# TEXTURE & IMAGE METHODS
|
# TEXTURE & IMAGE METHODS
|
||||||
@@ -437,6 +508,7 @@ class GameWindow:
|
|||||||
|
|
||||||
def stop_sound(self):
|
def stop_sound(self):
|
||||||
"""Stop all audio playback"""
|
"""Stop all audio playback"""
|
||||||
|
self.stop_music()
|
||||||
for dev in self.audio_devs.values():
|
for dev in self.audio_devs.values():
|
||||||
sdl2.SDL_PauseAudioDevice(dev, 1)
|
sdl2.SDL_PauseAudioDevice(dev, 1)
|
||||||
sdl2.SDL_ClearQueuedAudio(dev)
|
sdl2.SDL_ClearQueuedAudio(dev)
|
||||||
@@ -722,6 +794,11 @@ class GameWindow:
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Close the game window and cleanup"""
|
"""Close the game window and cleanup"""
|
||||||
|
self._free_music_track()
|
||||||
|
if self.music_enabled and sdlmixer is not None:
|
||||||
|
sdlmixer.Mix_CloseAudio()
|
||||||
|
sdlmixer.Mix_Quit()
|
||||||
|
self.music_enabled = False
|
||||||
if self.game_controller:
|
if self.game_controller:
|
||||||
sdl2.SDL_GameControllerClose(self.game_controller)
|
sdl2.SDL_GameControllerClose(self.game_controller)
|
||||||
self.game_controller = None
|
self.game_controller = None
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ from engine.user_profile_integration import UserProfileIntegration
|
|||||||
from runtime_paths import bundle_path
|
from runtime_paths import bundle_path
|
||||||
|
|
||||||
|
|
||||||
|
GAMEPLAY_MUSIC = "Clockwork_Thicket.mp3"
|
||||||
|
|
||||||
|
|
||||||
class MiceMaze(
|
class MiceMaze(
|
||||||
controls.KeyBindings,
|
controls.KeyBindings,
|
||||||
unit_manager.UnitManager,
|
unit_manager.UnitManager,
|
||||||
@@ -44,6 +47,7 @@ class MiceMaze(
|
|||||||
self.render_engine = engine.GameWindow(self.map.width, self.map.height,
|
self.render_engine = engine.GameWindow(self.map.width, self.map.height,
|
||||||
self.cell_size, window_title,
|
self.cell_size, window_title,
|
||||||
key_callback=self.trigger)
|
key_callback=self.trigger)
|
||||||
|
self.render_engine.audio = self.audio
|
||||||
|
|
||||||
# Apply profile settings
|
# Apply profile settings
|
||||||
if hasattr(self.render_engine, 'set_volume'):
|
if hasattr(self.render_engine, 'set_volume'):
|
||||||
@@ -245,7 +249,14 @@ class MiceMaze(
|
|||||||
if random.random() < 0.01:
|
if random.random() < 0.01:
|
||||||
data["count"] = min(data["count"] + 1, data["max"])
|
data["count"] = min(data["count"] + 1, data["max"])
|
||||||
|
|
||||||
|
def update_background_music(self):
|
||||||
|
if self.game_status == "game" and not self.game_end[0]:
|
||||||
|
self.render_engine.play_music(GAMEPLAY_MUSIC, loop=True)
|
||||||
|
return
|
||||||
|
self.render_engine.pause_music()
|
||||||
|
|
||||||
def update_maze(self):
|
def update_maze(self):
|
||||||
|
self.update_background_music()
|
||||||
if self.game_over():
|
if self.game_over():
|
||||||
return
|
return
|
||||||
if self.game_status == "paused":
|
if self.game_status == "paused":
|
||||||
|
|||||||
Reference in New Issue
Block a user