Files
Ultimate-Fishing-Simulator-…/Assets/Scripts/Assembly-CSharp/FootstepSound.cs
2026-03-04 09:37:33 +08:00

147 lines
3.7 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(AudioSource))]
public class FootstepSound : MonoBehaviour
{
[Serializable]
public struct MeshSurface
{
public string tag;
public AudioClip clip;
}
[Header("Foot Transforms (final IK)")]
public Transform leftFoot;
public Transform rightFoot;
[Header("Raycast / Detection")]
public float raycastDistance = 0.15f;
public float downwardSpeedThreshold = -0.03f;
public float footstepCooldown = 0.2f;
[Header("Terrain → AudioClips (index = Terrain Layer)")]
public AudioClip[] terrainLayerClips;
[Header("Mesh → AudioClips (by Tag)")]
public List<MeshSurface> meshSurfaces = new List<MeshSurface>();
[Header("Physics Mask for Raycast")]
public LayerMask terrainAndMeshMask = -1;
private AudioSource _src;
private Vector3 _prevLeft;
private Vector3 _prevRight;
private bool _wasLeftGrounded;
private bool _wasRightGrounded;
private float _nextLeftTime;
private float _nextRightTime;
private void Awake()
{
_src = GetComponent<AudioSource>();
_src.playOnAwake = false;
_src.spatialBlend = 1f;
if ((bool)leftFoot)
{
_prevLeft = leftFoot.position;
}
if ((bool)rightFoot)
{
_prevRight = rightFoot.position;
}
}
private void LateUpdate()
{
if ((bool)leftFoot)
{
HandleFoot(leftFoot, ref _prevLeft, ref _wasLeftGrounded, ref _nextLeftTime);
}
if ((bool)rightFoot)
{
HandleFoot(rightFoot, ref _prevRight, ref _wasRightGrounded, ref _nextRightTime);
}
}
private void HandleFoot(Transform foot, ref Vector3 prevPos, ref bool wasGrounded, ref float nextAllowedTime)
{
Vector3 position = foot.position;
Vector3 vector = (position - prevPos) / Time.deltaTime;
RaycastHit hitInfo;
bool flag = Physics.Raycast(position + Vector3.up * 0.02f, Vector3.down, out hitInfo, raycastDistance, terrainAndMeshMask, QueryTriggerInteraction.Ignore);
if (!wasGrounded && flag && vector.y < downwardSpeedThreshold && Time.time >= nextAllowedTime)
{
PlayFootstep(in hitInfo);
nextAllowedTime = Time.time + footstepCooldown;
}
wasGrounded = flag;
prevPos = position;
}
private void PlayFootstep(in RaycastHit hit)
{
AudioClip audioClip = null;
audioClip = ((Physics.OverlapSphere(hit.point, 0.1f, LayerMask.GetMask("Water")).Length != 0) ? GetMeshClip("Water") : ((!hit.collider.TryGetComponent<Terrain>(out var component)) ? GetMeshClip(hit.collider.tag) : GetTerrainClip(component, hit.point)));
if (!(audioClip == null))
{
_src.pitch = UnityEngine.Random.Range(0.93f, 1.07f);
_src.PlayOneShot(audioClip);
}
}
private AudioClip GetTerrainClip(Terrain terrain, Vector3 worldPoint)
{
TerrainData terrainData = terrain.terrainData;
if (terrainData == null || terrainData.alphamapLayers == 0)
{
return null;
}
Vector3 vector = worldPoint - terrain.transform.position;
float num = Mathf.Clamp01(vector.x / terrainData.size.x);
float num2 = Mathf.Clamp01(vector.z / terrainData.size.z);
int x = Mathf.Clamp(Mathf.RoundToInt(num * (float)(terrainData.alphamapWidth - 1)), 0, terrainData.alphamapWidth - 1);
int y = Mathf.Clamp(Mathf.RoundToInt(num2 * (float)(terrainData.alphamapHeight - 1)), 0, terrainData.alphamapHeight - 1);
float[,,] alphamaps = terrainData.GetAlphamaps(x, y, 1, 1);
int num3 = 0;
float num4 = 0f;
for (int i = 0; i < alphamaps.GetLength(2); i++)
{
float num5 = alphamaps[0, 0, i];
if (num5 > num4)
{
num4 = num5;
num3 = i;
}
}
if (num3 >= terrainLayerClips.Length)
{
return null;
}
return terrainLayerClips[num3];
}
private AudioClip GetMeshClip(string tag)
{
foreach (MeshSurface meshSurface in meshSurfaces)
{
if (meshSurface.tag == tag)
{
return meshSurface.clip;
}
}
return null;
}
}