【Unity小技巧】3D人物移动脚步和跳跃下落音效控制

文章目录

单脚步声

csharp 复制代码
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();
    }
}

多脚步声,跳跃落地音效

csharp 复制代码
[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;
}

播放不同材质的多脚步声

csharp 复制代码
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是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

相关推荐
虾球xz12 分钟前
游戏引擎学习第61天
java·学习·游戏引擎
Camllia3737 分钟前
《CS2》报错dxgi.dll缺失怎么办?《CS2》游戏提示dxgi.dll缺失要怎么解决?
游戏
葡萄架子2 小时前
用Python写炸金花游戏
windows·python·游戏
失舵之舟-3 小时前
【3DGS文献阅读】Splatter Image: Ultra-Fast Single-View 3D Reconstruction
3d·三维重建·nerf·3dgs·3d guassian·三维高斯溅射
两水先木示4 小时前
【Unity3D】Jobs、Burst并行计算裁剪Texture3D物体
unity·jobs·burst
la_vie_est_belle10 小时前
《Cocos Creator游戏实战》非固定摇杆实现原理
游戏·cocos creator·游戏开发·cocos·非固定摇杆
Thomas_YXQ10 小时前
Unity3D Huatuo技术原理剖析详解
unity·unity3d·游戏开发·性能调优·热更新
火云洞红孩儿12 小时前
基于AI IDE 打造快速化的游戏LUA脚本的生成系统
c++·人工智能·inscode·游戏引擎·lua·游戏开发·脚本系统
虾球xz13 小时前
游戏引擎学习第59天
学习·游戏引擎
zh路西法13 小时前
【C++决策和状态管理】从状态模式,有限状态机,行为树到决策树(二):从FSM开始的2D游戏角色操控底层源码编写
c++·游戏·unity·设计模式·状态模式