FPS專案腳步聲——Unity隨手記(2021.1.22)
阿新 • • 發佈:2021-01-23
今天實現的內容:
製作腳步聲,學習了一下ScriptableObject的原理。指令碼聲音資源採用ScriptableObject的方式儲存應用。當角色著地並正在發生位移時,播放腳步聲。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "FPS/Footstep Audio Data")]
public class FootstepAudioData : ScriptableObject
{
public List<FootstepAudio> footstepAudios = new List<FootstepAudio>();
}
[System.Serializable]
public class FootstepAudio
{
// 用於標記踩在什麼表面上
public string Tag;
// 聲音片段列表
public List<AudioClip> AudioClips = new List<AudioClip>();
// 聲音間隔
public float walkVoiceInterval;
//public float sprintingVoiceInterval;
//public float CrouchingVoiceInterval;
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerFootstepListener : MonoBehaviour
{
public FootstepAudioData footstepAudioData;
public AudioSource footstepAudioSource;
private CharacterController characterController;
private Transform footstepTransform;
private float timePassed = 0;
private FPCharacterControllerMovement movement;
// 角色移動或者發生較大幅度位移時 播放腳步聲
// 根據角色踩踏的不同材質播放不同的聲音
// 具體實現方式採用Physics API
private void Start()
{
characterController = GetComponent<CharacterController>();
footstepTransform = transform;
movement = GetComponent<FPCharacterControllerMovement>();
}
private void FixedUpdate()
{
// 角色處於地面
if(characterController.isGrounded)
{
// 角色正在移動
if(characterController.velocity.normalized.sqrMagnitude > 0.1f)
{
// 設定下一次播放的時間
timePassed += Time.deltaTime;
// 播放移動聲音
if(Physics.Linecast(footstepTransform.position,
footstepTransform.position + Vector3.down * characterController.height,
out RaycastHit temp_hitInfo)) //檢測當前踩踏在什麼地面上
{
#if UNITY_EDITOR
Debug.Log(temp_hitInfo.collider.tag);
Debug.DrawRay(footstepTransform.position,
-footstepTransform.up * characterController.height, Color.red);
#endif
// 對於所有型別的腳步聲
foreach (var temp_audioElement in footstepAudioData.footstepAudios)
{
// 找到匹配的型別
if (temp_hitInfo.collider.CompareTag(temp_audioElement.Tag))
{
// 用於儲存實際要用的聲音播放間隔
float temp_VoiceInterval = 0;
if (movement.m_isSprinting && movement.m_isCrouched) //是否在蹲下時衝刺
{
temp_VoiceInterval = temp_audioElement.walkVoiceInterval;
}
else if(movement.m_isCrouched) //是否蹲下
{
temp_VoiceInterval = temp_audioElement.walkVoiceInterval * 2;
}
else if (movement.m_isSprinting) //是否在衝刺
{
temp_VoiceInterval = temp_audioElement.walkVoiceInterval / 2;
}
else // 那就只是在走了
{
temp_VoiceInterval = temp_audioElement.walkVoiceInterval;
}
Debug.Log(temp_VoiceInterval);
// 如果到了下一次播放時間
if (timePassed >= temp_VoiceInterval)
{
// 獲取這個型別腳步聲的素材總數
int temp_audioCount = temp_audioElement.AudioClips.Count;
// 隨機獲取一個
int temp_audioIndex = UnityEngine.Random.Range(0, temp_audioCount);
// 獲取到對應的聲音片段
AudioClip temp_footstepAudioClip = temp_audioElement.AudioClips[temp_audioIndex];
// 播放音效
footstepAudioSource.clip = temp_footstepAudioClip;
footstepAudioSource.Play();
timePassed = 0;
// 找到了就行了 直接跳出迴圈
break;
}
}
}
}
}
}
}
}
FootstepAudioData負責用於生成儲存音效資源的ScriptableObject,PlayerFootstepListener用於角色所處地面的判斷,找到對應的音效,隨機獲取音效,並播放音效。音效有播放間隔,來勉強達到聽起來還算真實的效果嗎,還實現了不同的運動狀態對應不同的音效播放間隔。
BUG以及缺陷:
有時會莫名其妙的檢測不出地面的Tag。但其實是我的射線檢測寫錯了,檢測的end點應該為角色往下的點,而不是原點往下。以上程式碼以改正為正確的。
蹲下時沒有腳步聲了。應該是射線檢測不到地面了。
最大的缺陷,這個音效真的很難聽,算了,學會功能的實現就好。
值得注意的:
如何判斷移動狀態?我直接引用了之前的移動控制指令碼,指令碼中有描述運動狀態的bool值,這一點和老師做的不一樣。