文章目录
- 单脚步声
- 多脚步声,跳跃落地音效
- 播放不同材质的多脚步声
- 完结
单脚步声
public AudioClip walkingSound;
public AudioClip runningSound;
//移动音效
public void MoveSound()
{
// 如果在地面上并且移动长度大于0.9
if (isGround && moveDirection.sqrMagnitude > 0.9f)
{
audioSource.clip = isRun ? runningSound : walkingSound;
if (!audioSource.isPlaying) audioSource.Play();
}
else
{
if (audioSource.isPlaying) audioSource.Pause();
}
}
多脚步声,跳跃落地音效
[SerializeField] private float m_StepInterval; // 脚步声间隔
[SerializeField] private AudioClip[] m_FootstepSounds; // 脚步声音效数组
[SerializeField] private AudioClip m_JumpSound; // 跳跃声音效
[SerializeField] private AudioClip m_LandSound; // 落地声音效
private void Update()
{
if (!m_Jump)
{
m_Jump = Input.GetButtonDown("Jump"); // 检测跳跃输入
}
ProgressStepCycle(speed); // 更新步行声音
//判断角色是否落地,这个判断非常巧妙,假设角色起跳,m_PreviouslyGrounded和m_CharacterController.isGrounded肯定都是false,
//执行到下一步时角色到达地上,m_CharacterController.isGrounded变为true,因为m_PreviouslyGrounded还未执行,所以还是false,及此时角色刚落地
if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
{
PlayLandingSound(); // 播放落地声音
}
if (m_CharacterController.isGrounded)
{
if (m_Jump)
{
PlayJumpSound(); // 播放跳跃声音
}
}
m_PreviouslyGrounded = m_CharacterController.isGrounded;
}
private void PlayLandingSound()
{
m_AudioSource.clip = m_LandSound; // 设置落地声音
m_AudioSource.Play();
//播放落地声音后延迟0.5s再播放脚步声
m_NextStep = m_StepCycle + .5f;
}
private void PlayJumpSound()
{
m_AudioSource.clip = m_JumpSound; // 设置跳跃声音
m_AudioSource.Play();
}
private void ProgressStepCycle(float speed)
{
//判断角色是否在移动。
if (m_CharacterController.velocity.sqrMagnitude > 0 && (m_Input.x != 0 || m_Input.y != 0))
{
//如果角色在移动,根据角色当前的速度和行走/奔跑状态来更新步行声音循环计数器 m_StepCycle 的值。
m_StepCycle += (m_CharacterController.velocity.magnitude + (speed * (m_IsWalking ? 1f : m_RunstepLenghten))) * Time.fixedDeltaTime;
}
//然后,检查是否到达了下一个播放脚步声音的时间点。如果没有到达,就直接返回
if (!(m_StepCycle > m_NextStep))
{
return;
}
//如果到达了下一个播放脚步声音的时间点,就更新 m_NextStep 的值
m_NextStep = m_StepCycle + m_StepInterval;
PlayFootStepAudio(); // 播放脚步声音
}
private void PlayFootStepAudio()
{
if (!m_CharacterController.isGrounded)
{
return;
}
int n = UnityEngine.Random.Range(1, m_FootstepSounds.Length);
m_AudioSource.clip = m_FootstepSounds[n]; // 随机选择一个脚步声音
m_AudioSource.PlayOneShot(m_AudioSource.clip);
//播放过的脚步声放置第一位,避免连续播放相同的脚步声
m_FootstepSounds[n] = m_FootstepSounds[0];
m_FootstepSounds[0] = m_AudioSource.clip;
}
播放不同材质的多脚步声
using System.Collections.Generic;
using UnityEngine;
public class FootStepSound : MonoBehaviour
{
public RaycastHit hit; // 射线检测结果
public GameObject RayGo; // 射线起点对象
public AudioClip[] clipsMetal, clipsTree, clipsGrass, clipsDirt, clipsWater; // 不同类型表面的声音剪辑数组
public float dist = 2; // 射线的长度
private string tagProv; // 上一次射线检测到的地面标签
private int go = 0; // 控制播放声音的变量,0表示重新播放,1表示继续播放
public AudioSource AS; // 声音源组件
public float PitchWalk, PitchRun; // 行走和奔跑时的音调
// 创建一个列表用于存储之前选择过的音效索引
private List<int> playedIndexes = new List<int>();
void Update()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
if (Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.W))
AS.pitch = PitchRun; // 如果同时按下左Shift和W键,则设置为奔跑音调
else
AS.pitch = PitchWalk; // 否则设置为行走音调
if (horizontal != 0 || vertical != 0)
{
if (Physics.Raycast(RayGo.transform.position, Vector3.down, out hit, dist)) // 向下发射射线检测地面
{
if (hit.collider)
{
if (hit.collider.tag != tagProv) go = 0;
tagProv = hit.collider.tag;
switch (hit.collider.tag) // 根据地面的标签选择对应的声音类型
{
case "Metal":
PlayRandomSound(clipsMetal); // 播放金属声音
break;
case "Tree":
PlayRandomSound(clipsTree); // 播放树木声音
break;
case "Grass":
PlayRandomSound(clipsGrass); // 播放草地声音
break;
case "Dirt":
PlayRandomSound(clipsDirt); // 播放土地声音
break;
case "Water":
PlayRandomSound(clipsWater); // 播放水声音
break;
default:
StopSound(); // 停止播放声音
break;
}
}
}
}
else
{
StopSound(); // 停止播放声音
}
}
// 从给定的声音剪辑数组中随机播放一个声音
void PlayRandomSound(AudioClip[] clips)
{
if (go == 0) // 如果需要重新设置音频剪辑
{
AS.clip = null;
go = 1;
}
if (!AS.isPlaying) // 如果当前没有正在播放的声音
{
// AS.clip = clips[Random.Range(0, clips.Length)]; // 随机选择一个声音剪辑
int randomIndex = GetUniqueRandomIndex(clips.Length); // 获取一个未播放过的随机索引
AS.clip = clips[randomIndex]; // 根据索引选择一个声音剪辑
AS.Play(); // 播放声音
}
}
// 获取一个未播放过的随机索引
int GetUniqueRandomIndex(int arrayLength)
{
int randomIndex;
do
{
randomIndex = Random.Range(0, arrayLength); // 生成一个随机索引
} while (playedIndexes.Contains(randomIndex)); // 循环判断该索引是否已经播放过
playedIndexes.Add(randomIndex); // 将新的索引添加到已播放列表中
if (playedIndexes.Count >= arrayLength)
{
playedIndexes.Clear(); // 如果已播放列表包含所有索引,则清空列表,重新开始播放
}
return randomIndex;
}
// 停止播放声音并重置go变量
void StopSound()
{
AS.clip = null; // 清空音频剪辑
AS.Stop(); // 停止播放声音
go = 0; // 重置go变量
}
}
解释:
go 的这个逻辑保证了只有在需要重新设置音频剪辑时才会执行,避免了声音的混叠和中断。如果去除这个逻辑,可能会导致声音播放不正常。
AS.pitch是用来控制音频的音调(pitch)的属性。音调指的是声音的高低,可以用数字表示,其中1.0表示原始音调,小于1.0表示降低音调,大于1.0表示提高音调。
通过改变音调,可以实现音频的加速或减速播放。较高的音调会使音频听起来更快,而较低的音调则会使音频听起来更慢。
大致参数配置
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~