1. 程式人生 > 其它 >FPS專案腳步聲——Unity隨手記(2021.1.22)

FPS專案腳步聲——Unity隨手記(2021.1.22)

技術標籤:Unity隨手記unity

今天實現的內容:

製作腳步聲,學習了一下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值,這一點和老師做的不一樣。