本文目录导读:

我来帮你编写一个自动切换音效场景的脚本,根据不同的触发条件和应用场景,这里有几种常见的实现方式:
基于时间自动切换
import time
import random
class AudioSceneManager:
def __init__(self):
self.scenes = {
"morning": {
"bgm": "morning_bgm.mp3",
"sound_effects": ["birds.mp3", "water_flow.mp3"],
"volume": 0.7
},
"afternoon": {
"bgm": "afternoon_bgm.mp3",
"sound_effects": ["wind.mp3", "traffic.mp3"],
"volume": 0.5
},
"evening": {
"bgm": "evening_bgm.mp3",
"sound_effects": ["cricket.mp3", "fire.mp3"],
"volume": 0.6
},
"night": {
"bgm": "night_bgm.mp3",
"sound_effects": ["owl.mp3", "silence.mp3"],
"volume": 0.3
}
}
self.current_scene = None
def get_current_hour_scene(self):
hour = time.localtime().tm_hour
if 5 <= hour < 12:
return "morning"
elif 12 <= hour < 17:
return "afternoon"
elif 17 <= hour < 21:
return "evening"
else:
return "night"
def switch_scene(self, scene_name):
if scene_name in self.scenes and scene_name != self.current_scene:
print(f"切换场景: {scene_name}")
scene = self.scenes[scene_name]
# 这里添加实际的音频控制代码
self.play_scene_sounds(scene)
self.current_scene = scene_name
def play_scene_sounds(self, scene):
# 示例:播放背景音乐和音效
print(f"播放背景音乐: {scene['bgm']}")
for effect in scene['sound_effects']:
print(f"播放音效: {effect}")
print(f"设置音量: {scene['volume']}")
def auto_switch(self, check_interval=60):
"""自动检测并切换场景"""
while True:
scene_name = self.get_current_hour_scene()
self.switch_scene(scene_name)
time.sleep(check_interval)
# 使用示例
manager = AudioSceneManager()
# manager.auto_switch() # 启动自动切换
基于传感器触发(树莓派示例)
import RPi.GPIO as GPIO
import time
import pygame
class SensorAudioScene:
def __init__(self):
GPIO.setmode(GPIO.BCM)
self.sensors = []
self.current_scene = "idle"
def add_sensor(self, pin, scene_name, scene_config):
GPIO.setup(pin, GPIO.IN)
self.sensors.append({
"pin": pin,
"scene": scene_name,
"config": scene_config,
"last_state": GPIO.LOW
})
def check_sensors(self):
for sensor in self.sensors:
current_state = GPIO.input(sensor["pin"])
if current_state == GPIO.HIGH and sensor["last_state"] == GPIO.LOW:
self.switch_scene(sensor["scene"], sensor["config"])
sensor["last_state"] = current_state
def switch_scene(self, scene_name, scene_config):
print(f"切换场景: {scene_name}")
# 停止当前场景
if self.current_scene:
self.stop_scene(self.current_scene)
# 启动新场景
self.start_scene(scene_config)
self.current_scene = scene_name
def start_scene(self, config):
# 播放音效
if "sound" in config:
pygame.mixer.Sound(config["sound"]).play(-1)
if "music" in config:
pygame.mixer.music.load(config["music"])
pygame.mixer.music.play(-1)
def stop_scene(self, scene_name):
pygame.mixer.stop()
pygame.mixer.music.stop()
def run(self):
try:
while True:
self.check_sensors()
time.sleep(0.1)
except KeyboardInterrupt:
GPIO.cleanup()
# 使用示例
# sensor_scene = SensorAudioScene()
# sensor_scene.add_sensor(17, "enter_room", {"music": "enter.mp3", "sound": "door.mp3"})
# sensor_scene.add_sensor(18, "leave_room", {"music": "leave.mp3", "sound": "exit.mp3"})
# sensor_scene.run()
Unity游戏引擎版本(C#)
using UnityEngine;
using System.Collections;
public class AutoAudioSceneSwitcher : MonoBehaviour
{
[System.Serializable]
public class AudioScene
{
public string sceneName;
public AudioClip backgroundMusic;
public AudioClip[] ambientSounds;
[Range(0f, 1f)]
public float volume = 0.5f;
}
public AudioScene[] scenes;
public float transitionTime = 2f;
private AudioSource musicSource;
private AudioSource[] ambientSources;
private int currentSceneIndex = -1;
private Coroutine transitionCoroutine;
void Start()
{
// 创建音频源
musicSource = gameObject.AddComponent<AudioSource>();
musicSource.loop = true;
// 创建环境音源
if (scenes.Length > 0 && scenes[0].ambientSounds.Length > 0)
{
ambientSources = new AudioSource[scenes[0].ambientSounds.Length];
for (int i = 0; i < ambientSources.Length; i++)
{
ambientSources[i] = gameObject.AddComponent<AudioSource>();
ambientSources[i].loop = true;
}
}
// 开始自动切换协程
StartCoroutine(AutoSwitchRoutine());
}
void Update()
{
// 手动触发场景切换(可根据游戏逻辑调用)
if (Input.GetKeyDown(KeyCode.Space))
{
int nextScene = (currentSceneIndex + 1) % scenes.Length;
SwitchToScene(nextScene);
}
}
IEnumerator AutoSwitchRoutine()
{
// 每隔30秒自动切换场景(示例)
while (true)
{
yield return new WaitForSeconds(30f);
int nextScene = Random.Range(0, scenes.Length);
SwitchToScene(nextScene);
}
}
public void SwitchToScene(int sceneIndex)
{
if (sceneIndex < 0 || sceneIndex >= scenes.Length || sceneIndex == currentSceneIndex)
return;
if (transitionCoroutine != null)
StopCoroutine(transitionCoroutine);
transitionCoroutine = StartCoroutine(TransitionToScene(sceneIndex));
}
IEnumerator TransitionToScene(int sceneIndex)
{
AudioScene targetScene = scenes[sceneIndex];
// 淡出当前场景
if (currentSceneIndex >= 0)
{
float startVolume = musicSource.volume;
float elapsedTime = 0;
while (elapsedTime < transitionTime)
{
elapsedTime += Time.deltaTime;
float t = elapsedTime / transitionTime;
// 淡出音乐
musicSource.volume = Mathf.Lerp(startVolume, 0, t);
// 淡出环境音
if (ambientSources != null)
{
float ambientStartVolume = ambientSources[0].volume;
foreach (var source in ambientSources)
{
source.volume = Mathf.Lerp(ambientStartVolume, 0, t);
}
}
yield return null;
}
}
// 停止当前音频
musicSource.Stop();
if (ambientSources != null)
{
foreach (var source in ambientSources)
{
source.Stop();
}
}
// 设置新场景
musicSource.clip = targetScene.backgroundMusic;
musicSource.Play();
if (ambientSources != null && targetScene.ambientSounds.Length > 0)
{
for (int i = 0; i < ambientSources.Length && i < targetScene.ambientSounds.Length; i++)
{
ambientSources[i].clip = targetScene.ambientSounds[i];
ambientSources[i].Play();
}
}
// 淡入新场景
float targetVolume = targetScene.volume;
float fadeInTime = 0;
while (fadeInTime < transitionTime)
{
fadeInTime += Time.deltaTime;
float t = fadeInTime / transitionTime;
musicSource.volume = Mathf.Lerp(0, targetVolume, t);
if (ambientSources != null)
{
foreach (var source in ambientSources)
{
source.volume = Mathf.Lerp(0, targetVolume * 0.5f, t);
}
}
yield return null;
}
currentSceneIndex = sceneIndex;
transitionCoroutine = null;
}
// 外部调用接口
public void SwitchToSceneByName(string sceneName)
{
for (int i = 0; i < scenes.Length; i++)
{
if (scenes[i].sceneName == sceneName)
{
SwitchToScene(i);
return;
}
}
Debug.LogWarning($"场景 {sceneName} 未找到");
}
}
Web前端版本(JavaScript)
class AudioSceneManager {
constructor() {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.scenes = new Map();
this.currentScene = null;
this.bufferCache = new Map();
this.effects = {
fadeDuration: 2
};
// 初始化场景
this.initScenes();
// 监听场景自动切换条件
this.setupAutoSwitch();
}
initScenes() {
// 添加场景配置
this.addScene('peaceful', {
sounds: ['nature.mp3', 'birds.mp3'],
volume: 0.7,
trigger: 'time',
timeRange: { start: 6, end: 18 }
});
this.addScene('action', {
sounds: ['action_music.mp3', 'effects.mp3'],
volume: 0.9,
trigger: 'event',
event: 'combat'
});
this.addScene('night', {
sounds: ['night_bgm.mp3', 'crickets.mp3'],
volume: 0.3,
trigger: 'time',
timeRange: { start: 18, end: 6 }
});
}
async addScene(name, config) {
this.scenes.set(name, config);
// 预加载音频
const buffers = [];
for (const soundUrl of config.sounds) {
if (!this.bufferCache.has(soundUrl)) {
const buffer = await this.loadSound(soundUrl);
this.bufferCache.set(soundUrl, buffer);
buffers.push(buffer);
} else {
buffers.push(this.bufferCache.get(soundUrl));
}
}
config.buffers = buffers;
}
async loadSound(url) {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
return await this.audioContext.decodeAudioData(arrayBuffer);
}
setupAutoSwitch() {
// 定时检查场景切换
setInterval(() => {
this.checkTimeBasedScenes();
}, 60000); // 每分钟检查一次
// 监听自定义事件
document.addEventListener('gameEvent', (event) => {
this.handleGameEvent(event.detail);
});
}
checkTimeBasedScenes() {
const currentHour = new Date().getHours();
for (const [name, config] of this.scenes) {
if (config.trigger === 'time') {
const { start, end } = config.timeRange;
let isInRange;
if (start <= end) {
isInRange = currentHour >= start && currentHour < end;
} else {
// 跨越午夜的情况
isInRange = currentHour >= start || currentHour < end;
}
if (isInRange && this.currentScene !== name) {
this.switchToScene(name);
break;
}
}
}
}
handleGameEvent(event) {
console.log('处理游戏事件:', event);
for (const [name, config] of this.scenes) {
if (config.trigger === 'event' && config.event === event.type) {
this.switchToScene(name);
break;
}
}
}
async switchToScene(sceneName) {
if (!this.scenes.has(sceneName) || sceneName === this.currentScene) {
return;
}
const config = this.scenes.get(sceneName);
console.log(`切换到场景: ${sceneName}`);
// 淡出当前场景
await this.fadeOutCurrentScene();
// 停止所有音频
this.stopAll();
// 播放新场景
await this.playScene(config);
this.currentScene = sceneName;
// 触发场景切换事件
document.dispatchEvent(new CustomEvent('sceneChanged', {
detail: { scene: sceneName }
}));
}
fadeOutCurrentScene() {
return new Promise((resolve) => {
// 实际项目中需要实现渐出效果
setTimeout(resolve, this.effects.fadeDuration * 1000);
});
}
playScene(config) {
return new Promise((resolve) => {
config.buffers.forEach((buffer, index) => {
const source = this.audioContext.createBufferSource();
const gainNode = this.audioContext.createGain();
source.buffer = buffer;
source.connect(gainNode);
gainNode.connect(this.audioContext.destination);
gainNode.gain.value = config.volume / config.buffers.length;
source.start(0);
// 保存引用以便停止
this.activeSources.push(source);
});
setTimeout(resolve, 100);
});
}
stopAll() {
this.activeSources.forEach(source => {
try {
source.stop();
} catch (e) {
// 忽略已停止的源
}
});
this.activeSources = [];
}
}
// 使用示例
const audioManager = new AudioSceneManager();
// 手动触发场景切换
audioManager.switchToScene('action');
// 手动触发游戏事件
document.dispatchEvent(new CustomEvent('gameEvent', {
detail: { type: 'combat' }
}));
使用建议
-
选择合适的方式:
- 时间自动切换:适用于日常环境音效
- 传感器触发:适合物理交互场景
- 游戏事件触发:适合游戏中的动态场景切换
-
性能优化:
- 预加载音频资源
- 使用音频池管理多个音源
- 实现平滑过渡效果
-
扩展功能:
- 添加音量渐变和混音
- 实现场景优先级系统
- 支持用户手动切换
你可以根据具体的使用环境选择最适合的版本,需要我针对某个特定平台或需求进行修改吗?