单脚步声
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; }
播放不同材质的多脚步声
获取人物移动状态
public class PlayerState : Singleton<PlayerState> { [Header("判断人物状态")] public bool isMove;//是否在移动 public bool isWalking;//是否正在行走 public bool isRuning; //是否正在奔跑 public bool isCrouching; //是否正在下蹲 private void Update() { isMove = MovementScript.Instance.isGround && MovementScript.Instance.moveDirection.sqrMagnitude > 0; isRuning = MovementScript.Instance.isRun && isMove; isCrouching = MovementScript.Instance.isCrouching; isWalking = !isRuning && !isCrouching && isMove; } }
脚步声控制
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; // 声音源组件 //该属性控制音频的播放速度,1.0 表示正常速度,小于 1.0 表示慢速播放,大于 1.0 表示快速播放。 public float PitchRun, PitchWalk, PitchCrouch; // 创建一个列表用于存储之前选择过的音效索引 private List<int> playedIndexes = new List<int>(); void Update() { if (PlayerState.Instance.isRuning) AS.pitch = PitchRun; //则设置为奔跑音调 else if(PlayerState.Instance.isWalking){ AS.pitch = PitchWalk; }else{ AS.pitch = PitchCrouch; } if (PlayerState.Instance.isMove) { 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 (AS.isPlaying) { // AS.Stop(); } 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.Stop(); // 停止播放声音 go = 0; // 重置go变量 } }
解释:
go 的这个逻辑保证了只有在需要重新设置音频剪辑时才会执行,避免了声音的混叠和中断。如果去除这个逻辑,可能会导致声音播放不正常。
AS.pitch是用来控制音频的音调(pitch)的属性。该属性控制音频的播放速度,1.0 表示正常速度,小于 1.0 表示慢速播放,大于 1.0 表示快速播放。
通过改变音调,可以实现音频的加速或减速播放。较高的音调会使音频听起来更快,而较低的音调则会使音频听起来更慢。
大致参数配置