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

文章目录

  • 单脚步声
  • 多脚步声,跳跃落地音效
  • 播放不同材质的多脚步声
  • 完结

单脚步声

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/339372.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

上位机图像处理和嵌入式模块部署(qt图像处理)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 很多人一想到图像处理&#xff0c;本能的第一反应就是opencv&#xff0c;这也没有错。但是呢&#xff0c;这里面还是有一个问题的&#xff0c;不知…

利用Anaconda安装pytorch和paddle深度学习环境+pycharm安装后不能调用pytorch和paddlepaddle框架

问题现象&#xff1a; 之前安装后不能在添加pytorch和paddlepaddle框架 原因&#xff08;疑似&#xff09;&#xff1a; 在终端中显示pytorch和paddle在C盘但是安装是安装在J盘 解决办法&#xff1a; 卸载、删除文件重新安装后可以看到文件位置在J盘中 但是选择时还是显示C…

JavaEE中什么是Web容器?

Web容器&#xff08;也称为Servlet引擎&#xff09;是一个用于执行Java Servlet和JSP的服务器端环境。它负责管理和执行在其上运行的Web应用程序。 Tomcat是Web容器 Apache Tomcat 是一个流行的开源的Web容器&#xff0c;它实现了Java Servlet和JavaServer Pages&#xff08;…

Linux中的软件包管理器yum

目录 1.什么是软件包 2.关于 rzsz 3.查看软件包 4.如何安装软件 5.如何卸载软件 1.什么是软件包 ● 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. ● 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理…

《WebKit 技术内幕》之五(3): HTML解释器和DOM 模型

3 DOM的事件机制 基于 WebKit 的浏览器事件处理过程&#xff1a;首先检测事件发生处的元素有无监听者&#xff0c;如果网页的相关节点注册了事件的监听者则浏览器会将事件派发给 WebKit 内核来处理。另外浏览器可能也需要处理这样的事件&#xff08;浏览器对于有些事件必须响应…

【GitHub项目推荐--智能家居项目】【转载】

如果你具备硬件、软件知识&#xff0c;这个项目肯定符合你的胃口。 物美智能是一套软硬件结合的开源项目&#xff0c;该系统可助你快速搭建自己的智能家居系统。你可以学习到设备的集成和软硬件交互。 PC 端或者手机与服务端通信&#xff0c;单片机可以接受遥控设备和服务器的…

【C++干货基地】namespace超越C语言的独特魅力(文末送书)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

【后端】深入浅出Node.js

文章目录 1.Node简介1.1 诞生历程1.2 阻塞IO和异步IO 【后端目录贴】 1.Node简介 1.1 诞生历程 Node特点 事件驱动、非阻塞I/O node和chrome浏览器区别 除了HTML、WebKit和显卡这些UI相关技术没有支持外&#xff0c;Node结构与Chrome十分相似&#xff0c;他们都是基于事件驱动…

echarts dataZoom实现左右滑动与放大缩小 并精确控制显示几条数据

//Xdata是横轴的长度&#xff08;若x轴80条数据&#xff0c;默认显示最新的20条&#xff09; var start Xdata.length - 20; var end Xdata.length - 1; dataZoom: [ type: slider, show: true, startValue: dataZoomStart, endValue: dataZoomEnd, dataBackground: { ar…

【UEFI基础】EDK网络框架(UDP4)

UDP4 UDP4协议说明 UDP的全称是User Datagram Protocol&#xff0c;它不提供复杂的控制机制&#xff0c;仅利用IP提供面向无连接的通信服务。它将上层应用程序发来的数据在收到的那一刻&#xff0c;立即按照原样发送到网络。 UDP报文格式&#xff1a; 各个参数说明如下&…

Spring Boot3.2.2整合MyBatis Plus3.5.5

目录 1.前置条件 2.导坐标 3.配置数据源 4.配置mapper扫描路径 5.MyBatis Plus代码生成器整合 1.导坐标 2.编写代码生成逻辑 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动 2.导坐标 <dependency><groupId>com.baomid…

《WebKit 技术内幕》之六(1): CSS解释器和样式布局

《WebKit 技术内幕》之六&#xff08;1&#xff09;&#xff1a;CSS解释器和样式布局 CSS解释器和规则匹配处于DOM树建立之后&#xff0c;RenderObject树之前&#xff0c;CSS解释器解释后的结果会保存起来&#xff0c;然后RenderObject树基于该结果来进行规范匹配和布局计算。当…

NodeJs 第二十章 代理

在计算机网络中&#xff0c;代理是一种中间服务&#xff0c;能够代理用户与网络资源之间的通信。代理服务器可以缓存网页内容、过滤网络流量或隐藏用户的真实IP地址等功能。 在日常开发中&#xff0c;我们接触最多的是客户端发送ajax到服务端。但是服务端并不是 node &#xf…

搭建DNS 服务

安装DNS 服务 [rootlocalhost ~]# yum install bind -y Complete! [rootlocalhost ~]# DNS 配置文件 [rootlocalhost ~]# vim /etc/named.conf [rootlocalhost ~]# cat -n /etc/named.conf 1 // ... 12 options { 13 #listen-on port 53 { 127.0.0.1; }; 14 list…

【蓝桥杯冲冲冲】动态规划初步[USACO2006 OPEN] 县集市

蓝桥杯备赛 | 洛谷做题打卡day13 文章目录 蓝桥杯备赛 | 洛谷做题打卡day13题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示样例说明数据规模与约定 思路&#xff1a;方程&#xff1a; 题解代码我的一些话 [USACO2006 OPEN] 县集市 The County Fair 题目描述 每年…

说说你对归并排序的理解?如何实现?应用场景?

一、是什么 归并排序&#xff08;Merge Sort&#xff09;是建立归并操作上的一种有效&#xff0c;稳定的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用 将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序&#xff0c;再使…

几个简单好用Python库,让你工作效率翻倍

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python是一门强大的编程语言&#xff0c;不仅可以进行软件开发&#xff0c;还可以通过各种优秀的第三方库来提高工作效率。本文将介绍几个简单而好用的Python库&#xff0c;它们可以帮助你在各种领域提高工作效率…

02不吉利日期,noi练习题,小学生编程

02:不吉利日期 总时间限制: 1000ms 内存限制: 65536kB 描述 在国外&#xff0c;每月的13号和每周的星期5都是不吉利的。特别是当13号那天恰好是星期5时&#xff0c;更不吉利。已知某年的一月一日是星期w&#xff0c;并且这一年一定不是闰年&#xff0c;求出这一年所有13号…

设计模式—行为型模式之观察者模式

设计模式—行为型模式之观察者模式 观察者模式(Observer Pattern)&#xff1a;定义对象间的一种一对多依赖关系&#xff0c;使得每当一个对象状态发生改变时&#xff0c;其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅&#xff08;Publish/Subscribe&#…

Qt应用开发(安卓篇)——Hello Qt On Android

一、前言 这一篇从实际出发&#xff0c;讲述如何创建、编译和部署Qt On Android项目。 二、ADB调试 ADB的全称为Android Debug Bridge&#xff0c;就是起到调试桥的作用&#xff0c;主要用于连接计算机与Android 设备&#xff0c;以便进行调试和数据传输。ADB 可以实现以下主要…