-
Notifications
You must be signed in to change notification settings - Fork 0
Integration Examples
Norz3n edited this page Dec 10, 2025
·
2 revisions
Real-world patterns for integrating the Dynamic Ambient System into your Ren'Py project.
# ambient_auto_start.rpy handles this automatically
# Just configure audio_assets.yaml:
main_theme:
file: "audio/main_theme.mp3"
duration: 45
after_theme_arrangement: "main_menu"screen main_menu():
tag menu
on "show" action Function(start_menu_ambient)
on "hide" action Function(stop_menu_ambient)
# ... your menu content
init python:
def start_menu_ambient():
if not ambient.is_active:
ambient.start_with_main_theme()
def stop_menu_ambient():
ambient.stop_ambient()label forest:
scene bg forest
ambient play "forest_day"
"You enter the forest."
jump forest_explore
label city:
scene bg city_street
ambient play "city_daytime"
"The city bustles around you."
jump city_explore# arrangements.yaml
arrangements:
forest_morning:
tracks:
forest_base: { volume: 0.5 }
morning_birds: { volume: 0.6 }
forest_day:
tracks:
forest_base: { volume: 0.6 }
birds: { volume: 0.5 }
insects: { volume: 0.3 }
forest_evening:
tracks:
forest_base: { volume: 0.5 }
crickets: { volume: 0.4 }
forest_night:
tracks:
forest_base: { volume: 0.4 }
night_insects: { volume: 0.5 }
owl: { volume: 0.3 }label enter_forest:
scene bg forest
# Play appropriate arrangement based on time
if time_of_day == "morning":
ambient play "forest_morning"
elif time_of_day == "day":
ambient play "forest_day"
elif time_of_day == "evening":
ambient play "forest_evening"
else:
ambient play "forest_night"
jump forest_main# arrangements.yaml
arrangements:
outdoor_clear:
tracks:
nature_base: { volume: 0.5 }
birds: { volume: 0.4 }
layers:
light_rain:
rain_light: { volume: 0.5 }
rain_drops: { volume: 0.3 }
heavy_rain:
rain_heavy: { volume: 0.8 }
rain_drops: { volume: 0.5 }
storm:
thunder: { volume: 0.7 }
wind_strong: { volume: 0.6 }init python:
def set_weather(weather_type):
"""Update ambient based on weather."""
# Clear all weather layers first
ambient.set_layer("light_rain", False, fade_time=2.0)
ambient.set_layer("heavy_rain", False, fade_time=2.0)
ambient.set_layer("storm", False, fade_time=2.0)
# Apply new weather
if weather_type == "light_rain":
ambient.set_layer("light_rain", True, fade_time=3.0)
elif weather_type == "heavy_rain":
ambient.set_layer("heavy_rain", True, fade_time=3.0)
elif weather_type == "storm":
ambient.set_layer("heavy_rain", True, fade_time=2.0)
ambient.set_layer("storm", True, fade_time=3.0)
label outdoor_scene:
ambient play "outdoor_clear"
"A beautiful day outside."
$ set_weather("light_rain")
"It starts to drizzle."
$ set_weather("heavy_rain")
"The rain intensifies."
$ set_weather("storm")
"A storm rolls in!"
$ set_weather("clear")
"The storm passes."# arrangements.yaml
arrangements:
exploration:
tracks:
ambient_base: { volume: 0.5 }
environment: { volume: 0.4 }
tension_low:
tracks:
ambient_base: { volume: 0.4 }
tension_drone: { volume: 0.3 }
tension_high:
tracks:
tension_drone: { volume: 0.6 }
heartbeat: { volume: 0.4 }
stinger: { volume: 0.3 }
combat:
tracks:
combat_music: { volume: 0.8, type: "mandatory" }
combat_hits: { volume: 0.5 }init python:
tension_level = 0
def update_tension(level):
global tension_level
tension_level = level
if level == 0:
ambient.play_arrangement("exploration", fade_time=3.0)
elif level == 1:
ambient.play_arrangement("tension_low", fade_time=2.0)
elif level == 2:
ambient.play_arrangement("tension_high", fade_time=1.5)
elif level >= 3:
ambient.play_arrangement("combat", fade_time=1.0)
label encounter_enemy:
$ update_tension(1)
"You sense danger nearby..."
$ update_tension(2)
"An enemy appears!"
menu:
"Fight":
$ update_tension(3)
jump combat_scene
"Flee":
$ update_tension(0)
jump escape_scenearrangements:
outdoor_street:
tracks:
traffic: { volume: 0.5 }
crowd: { volume: 0.4 }
birds: { volume: 0.3 }
indoor_cafe:
tracks:
cafe_ambience: { volume: 0.5 }
coffee_machine: { volume: 0.3 }
quiet_chatter: { volume: 0.4 }
layers:
music:
cafe_music: { volume: 0.3 }
indoor_office:
tracks:
office_hum: { volume: 0.4 }
keyboard_typing: { volume: 0.3 }
ac_unit: { volume: 0.2 }init python:
current_location_type = "outdoor"
def enter_location(location, location_type):
global current_location_type
# Determine fade time based on transition type
if current_location_type != location_type:
fade = 2.0 # Longer fade for indoor/outdoor change
else:
fade = 1.0 # Shorter fade for same type
ambient.play_arrangement(location, fade_time=fade)
current_location_type = location_type
label street:
scene bg street
$ enter_location("outdoor_street", "outdoor")
"You walk down the busy street."
label enter_cafe:
scene bg cafe
$ enter_location("indoor_cafe", "indoor")
ambient layer "music" on
"You step into the cozy cafe."
label enter_office:
scene bg office
$ enter_location("indoor_office", "indoor")
"The office is quiet today."Duck only ambient sounds while keeping music at full volume (or vice versa).
init python:
original_ambient_vol = 0.7
def duck_ambient_only():
global original_ambient_vol
# Store current ambient base volume
original_ambient_vol = ambient.base_volume_ambient
# Duck ONLY ambient sounds (wind, birds, etc.)
ambient.set_base_volume(original_ambient_vol * 0.4, "ambient")
def restore_ambient_only():
ambient.set_base_volume(original_ambient_vol, "ambient")
label important_dialogue:
$ duck_ambient_only()
voice "audio/voice/important_line.ogg"
"This line is heard clearly over the quiet wind."
$ restore_ambient_only()Duck everything (Music + Ambient).
init python:
original_volume_mult = 1.0
def duck_all():
# Duck EVERYTHING (Music and Ambient)
ambient.set_base_volume(0.3)
def restore_all():
ambient.set_base_volume(1.0)init python:
def character_callback(event, interact=True, **kwargs):
if event == "begin":
# Duck ambient only when this character speaks
ambient.set_base_volume(0.4, "ambient")
elif event == "end":
ambient.set_base_volume(0.7, "ambient")
define narrator = Character(None, callback=character_callback)The system automatically handles save/load through __getstate__ and __setstate__. However, for complex setups:
init python:
def after_load_callback():
"""Restore ambient state after loading."""
# The system auto-restores, but you can add custom logic
if hasattr(store, 'current_ambient_arrangement'):
if store.current_ambient_arrangement:
ambient.play_arrangement(store.current_ambient_arrangement)
config.after_load_callbacks.append(after_load_callback)
label save_ambient_state:
# Store current arrangement for manual restoration if needed
$ current_ambient_arrangement = ambient.active_arrangement.name if ambient.active_arrangement else Noneinit python:
debug_mode = True
def toggle_ambient_debug():
if hasattr(store, 'show_ambient_debug'):
store.show_ambient_debug = not store.show_ambient_debug
else:
store.show_ambient_debug = True
# In your developer menu or key binding
label dev_menu:
menu:
"Toggle Ambient Debug":
$ toggle_ambient_debug()
"Reload Ambient Config":
$ ambient.load_config()
"Stop All Ambient":
$ ambient.stop_ambient(fade_out=False)init python:
# Press 'D' to toggle debug
config.keymap['toggle_debug'] = ['d']
def toggle_debug_action():
ambient.debug_ui() # If using CDS debug ui
# Or bind to screeninit python:
def optimize_ambient_for_scene(complexity):
"""Adjust ambient based on scene complexity."""
if complexity == "high":
# Complex scene - reduce ambient tracks
ambient.set_base_volume(0.4)
else:
ambient.set_base_volume(0.7)init python:
# Ren'Py handles audio caching, but you can hint
def preload_location_audio(location):
# This is handled by Ren'Py's prediction system
passRenPy Dynamic Ambient System v2.0.0 | Home | Installation | Quick Start | FAQ