1.在角色对象上挂在animator组件,并将动作控制器与其关联
2.在角色对象上挂在audio source组件。
3.新建voice control脚本,编写代码如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Animations;
public class VoiceControl : MonoBehaviour
{public Animator animator;public float volumeThreshold = 0f; // 调整为一个更合理的阈值private string talkingParamName = "Talk";public AudioSource audioLocal;private string device;private IEnumerator coroWaitMic;private const float coroutineLoggingIfDebug = 5f; // debug log ERROR every 5 seconds while audiodevice errorconst int loopLength = 5;const int sampleRate = 16000;// Start is called before the first frame updatevoid Start(){// 设置初始动画状态为NotTalkingaudioLocal = GameObject.Find("xiaoyang").GetComponent<AudioSource>(); // 1 定位本地音频设备audioLocalif (Microphone.devices.Length <= 0){Debug.LogError("没有麦克风或麦克风权限未打开");throw new Exception("没有麦克风或麦克风权限未打开");}else{device = Microphone.devices[0];//获取麦克风名 }StartMicrophone(device);animator.SetBool(talkingParamName, false);}// Update is called once per framevoid Update(){float currentVolume = GetAverageAmplitude();Debug.Log($"Current Average Amplitude: {currentVolume}, Volume Threshold: {volumeThreshold}");// 根据音量大小切换Talk参数和动画状态// 根据当前音量大小决定是否切换动画状态if (currentVolume > volumeThreshold){animator.SetBool("Talk", true);Debug.Log("true执行");}else{animator.SetBool("Talk", false);Debug.Log("false执行");}}private void StartMicrophone(string mic){// Start and wait for the microphone to start recording dataif (coroWaitMic != null)StopCoroutine(coroWaitMic);coroWaitMic = WaitForMic(device);StartCoroutine(coroWaitMic);} // end StartMicrophone()IEnumerator WaitForMic(string mic){float timeCheck = Time.time;if (audioLocal == null){Debug.LogWarning("[WaitForMic()] - AudioSource is not present...bailing...");yield break;}audioLocal.clip = Microphone.Start(mic, true, loopLength, sampleRate);// Let the Microphone start filling the buffer prior to activating the AudioSource.while (!(Microphone.GetPosition(mic) > 0)){if (Time.time - timeCheck > coroutineLoggingIfDebug){Debug.Log("[WaitForMic()] - is waiting for the mic to record.");timeCheck = Time.time;}// Wait for Microphone to start gathering data.yield return null;}audioLocal.Play();audioLocal.loop = true;} // end WaitForMic() 录音设备开始录音private float GetAverageAmplitude(){float[] data = new float[sampleRate]; // 假设每次读取sampleRate个样本数据,实际项目中可以根据需要调整audioLocal.clip.GetData(data, 0); // 获取麦克风实时输入的数据float sumOfSquares = 0f;for (int i = 0; i < data.Length; i++){float sampleValue = Mathf.Abs(data[i]); // 取绝对值计算振幅sumOfSquares += Mathf.Pow(sampleValue, 2); // 将样本平方累加,用于计算均方根(RMS)}float averageAmplitude = Mathf.Sqrt(sumOfSquares / data.Length); // 计算均方根得到平均振幅大小Debug.Log($"Current Average Amplitude: {averageAmplitude}, Volume Threshold: {volumeThreshold}");return averageAmplitude;}
}
4.将动作控制器关联到脚本上
5.设置音量阈值,使得当达到某个音量值时切换动画
6.在动作控制器中设置不同的动作状态
(1)添加没说话时和说话时的状态并添加自循环,使动作能够重复播放
(2)新建布尔参数,用于控制状态
(3)设置Notalking→talking过渡动画的属性和出发布尔值的条件
(4)设置talking→Notalking过渡动画的属性和出发布尔值的条件