当前位置: 首页 > news >正文

学习游戏制作记录(音频的制作和使用)8.28

1.音频管理器

创建管理器对象

创建AudioManager脚本:

public static AudioManager instance;

[SerializeField] private AudioSource[] SFX;//音效
[SerializeField] private AudioSource[] BGM;//bgm


public bool playBGM;//是否播放bgm
private int bgmIndex;//bgm的索引

public void Awake()
{
if (instance != null)
{
Destroy(instance.gameObject);
}
else
{
instance = this;
}
}
void Update()
{
if(!playBGM)//确保bgm的正确播放
StopAllBGM();
else
{
if (!BGM[bgmIndex].isPlaying)
PlayBGM(bgmIndex);
}
}

public void PlaySFX(int _SFXindex)
{
if(_SFXindex<SFX.Length)

        {

         SFX[_SFXindex].pitch = Random.Range(.85f, 1.1f);//每次音效的效果不同
SFX[_SFXindex].Play();//播放指定音效
}


}

public void StopSFX(int _SFXindex) => SFX[_SFXindex].Stop();

public void PlayRandomBGM()//播放随机bgm
{
bgmIndex =Random.Range(0, BGM.Length);
PlayBGM(bgmIndex);
}
public void PlayBGM(int _BGMindex)//播放指定bgm
{
bgmIndex= _BGMindex;

    StopAllBGM();

    BGM[bgmIndex].Play();

}
public void StopAllBGM()
{
for(int i = 0; i < BGM.Length; i++)
{

        BGM[i].Stop();

}

}

2.音频的距离限制

AudioManager脚本:

    [SerializeField] private float sfxMinDistance;

    public void PlaySFX(int _SFXindex,Transform _source)//传入声源的位置
{
if (SFX[bgmIndex].isPlaying)//防止重复播放
return;

        if (_source != null && Vector2.Distance(PlayerManage.instance.player.transform.position, _source.position) > sfxMinDistance)//检测距离
return;


        if(_SFXindex<SFX.Length)
{
SFX[_SFXindex].pitch = Random.Range(.85f, 1.1f);
SFX[_SFXindex].Play();
}
}

SkeletonIdleState脚本:

    public override void Exit()
{
base.Exit();

        AudioManager.instance.PlaySFX(14,enemy.transform);//敌人退出待机状态时播放音乐
}

3.更多音频的设置

 PlayerMoveState脚本:

    public override void Enter()
{
base.Enter();

        AudioManager.instance.PlaySFX(14, null);//播放脚步声
}

    public override void Exit()
{
base.Exit();

        AudioManager.instance.StopSFX(14);
}

Checkpoint脚本:

    public void ActiveCheckPoints()
{
if(activeStatus==false)
{
AudioManager.instance.PlaySFX(5, transform);//播放检查点激活的音效

        }
activeStatus=true;
anim.SetBool("active", true);
}

ItemObject脚本:

    public void PickupObject()
{
if (!Inventory.instance.canAddItem() && itemData.itemType==ItemType.Equipment)
{
rb.velocity = new Vector2(0, 7);
return;
}
Inventory.instance.AddItem(itemData);
AudioManager.instance.PlaySFX(18, transform);//物品拾取的音效
Destroy(gameObject);
}

Blackhole_Skill脚本:

    public override void UseSkill()
{
base.UseSkill();

GameObject newblackhole = Instantiate(blackholePrefab,player.transform.position,Quaternion.identity);

        currentBlackholeScript = newblackhole.GetComponent<Blackhole_Skill_Control>();

        currentBlackholeScript.SetupBlackhole(maxSize, growSpeed, shrinkSpeed, cloneAttackCooldown, amountofAttack,blackholeDuration);

        AudioManager.instance.PlaySFX(3,player.transform);//播放黑洞的声音
AudioManager.instance.PlaySFX(6, player.transform);
}

4.音频混合器的设置

UI_VolumeSlider脚本:

  public Slider slider;//滑块
public string pamater;//音频混合器的参数

  [SerializeField] private AudioMixer audioMixer;//音频混合器
[SerializeField] private float mutiplier;//乘数
private const string delayedMethodName = "DelayedSetVolume";
private float pendingValue;

  public void SliderValue(float _value)
{

      if (IsInvoking(delayedMethodName))
{
CancelInvoke(delayedMethodName);
}

      pendingValue = _value;

      Invoke(delayedMethodName, 0.01f);//延迟调用声音调整
}

  private void DelayedSetVolume()
{
float dB = Mathf.Log10(pendingValue) * mutiplier;
audioMixer.SetFloat(pamater, dB);//修改音频混合器

  }


  public void LoadSlider(float _value)//加载数据
{

      if (_value >= 0.001f)
slider.value = _value;
}

GameData脚本:

    public SerializbleDictionary<string, float> volumeSettings;//需要保存的数据

UI脚本:

public class UI : MonoBehaviour,ISaveManager实现保存接口

 [SerializeField] public UI_VolumeSlider[] volumeSettings;

    public void LoadDate(GameData gameData)//加载声音的调整
{
foreach (KeyValuePair<string,float> pair in gameData.volumeSettings)
{
foreach(UI_VolumeSlider item in volumeSettings)
{
if(item.pamater==pair.Key)
item.LoadSlider(pair.Value);
}
}
}

    public void SaveDate(ref GameData gameData)//保存声音的调整
{
gameData.volumeSettings.Clear();

        foreach(UI_VolumeSlider volumeSlider in volumeSettings)
{
gameData.volumeSettings.Add(volumeSlider.pamater, volumeSlider.slider.value);
}

    }‘

5.音频时间限制器

AudioManager脚本:

    private bool canPlaySFX;//是否可以播放音效

   public void PlaySFX(int _SFXindex, Transform _source)
{
if(canPlaySFX==false)//不能则直接返回
{
return;
}
//if (SFX[bgmIndex].isPlaying)
//return;

       if (_source != null && Vector2.Distance(PlayerManage.instance.player.transform.position, _source.position) > sfxMinDistance)
return;


       if (_SFXindex < SFX.Length)
{
SFX[_SFXindex].pitch = Random.Range(.85f, 1.1f);
SFX[_SFXindex].Play();
}
}

private void AllowSFXPlay()=>canPlaySFX = true;//启用音效

    public void Awake()
{
if (instance != null)
{
Destroy(instance.gameObject);
}
else
{
instance = this;
}

        Invoke("AllowSFXPlay", 1f); //延迟调用
}

6.区域音效制作

创建AreaSound脚本并挂载在一片空对象上:

    [SerializeField] private int areaSoundIndex;//该区域对应的音效索引

    private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.GetComponent<Player>() != null)
AudioManager.instance.PlaySFX(areaSoundIndex,null);//进入播放
}

    private void OnTriggerExit2D(Collider2D collision)
{
if (collision.GetComponent<Player>() != null)
AudioManager.instance.StopSFXWithTime(areaSoundIndex);//退出时缓慢的关闭音乐
}

AudioManager脚本:

    public void StopSFXWithTime(int _index)
{
StartCoroutine(DecreaseVolume(SFX[_index]));
}

    private IEnumerator DecreaseVolume(AudioSource _audio)//延迟关闭,并且缓慢较小音效的音调大小
{
float defualtVolume=_audio.volume;

        while(_audio.volume > .1f)
{
_audio.volume -= _audio.volume * .2f;
yield return new WaitForSeconds(.6f);

            if(_audio.volume <.1f)
{
_audio.Stop();
_audio.volume=defualtVolume;
break;
}

        }
}

http://www.dtcms.com/a/356755.html

相关文章:

  • 算法题打卡力扣第169题:多数元素(easy)
  • 【二叉树(DFS)- LeetCode】124. 二叉树中的最大路径和
  • 考民航安检员证需要具备哪些技能和知识?
  • 卷积神经网络为什么要填充(Padding)
  • Python爬虫实战:研究Pyplot模块,构建IMDb数据采集和分析系统
  • 【Tools】C#文件自动生成UML图
  • Vue3 全面介绍
  • ArcGIS Pro 地图打包与解包
  • STM32CubeMX + HAL 库:基于 I²C 通信的 AHT20 高精度温湿度测量实验
  • 佳易王钓场计时计费系统:全方位赋能钓场智能化管理,软件操作教程
  • Halcon那些事:如何使用差异模型create_variation_model检测印刷品缺陷
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(22):文法+单词第7回4 + 考え方1
  • Java全栈开发工程师面试实录:从基础到微服务的深度技术解析
  • LangChain如何使用通义千问的向量模型
  • 嵌入式学习日志————MPU6050简介
  • 2025年社交广告投放技术解析:应对CPM上涨的核心策略与实战方法
  • 元宇宙与娱乐产业:沉浸式体验与内容生态的重构
  • 前端工程化深度实践:从构建优化到CI/CD的完整解决方案
  • 基于无人机的风电叶片全自动智能巡检:高精度停角估计与细节优先曝光调控技术
  • 【Flask】测试平台开发,产品管理实现添加功能-第五篇
  • 【Flask】测试平台开发,集成禅道
  • 【Spring Cloud微服务】6.通信的利刃:深入浅出 Spring Cloud Feign 实战与原理
  • 前端-什么是Vue
  • 如何禁止网站内容被复制:技术、策略与深度思考
  • 【面试系列】谈谈你对数据库ACID的理解
  • 鸿蒙Next导航与路由指南:组件导航与页面路由的完美协作
  • Java中使用Spring Boot+Ollama实现本地AI的MCP接入
  • Dify平台:Agent开发初学者指南
  • Rust:所有权
  • Swift 解法详解:LeetCode 366《寻找二叉树的叶子节点》