projectEli/Assets/NeoFPS/Core/MotionGraphs/Behaviours/FootstepAudioBehaviour.cs

261 lines
9.4 KiB
C#
Raw Normal View History

2022-11-07 01:28:33 +00:00
#if !NEOFPS_FORCE_QUALITY && (UNITY_ANDROID || UNITY_IOS || UNITY_TIZEN || (UNITY_WSA && NETFX_CORE) || NEOFPS_FORCE_LIGHTWEIGHT)
#define NEOFPS_LIGHTWEIGHT
#endif
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NeoFPS.Constants;
using NeoFPS.CharacterMotion;
using NeoFPS.CharacterMotion.Parameters;
using NeoSaveGames.Serialization;
namespace NeoFPS.CharacterMotion.Behaviours
{
[MotionGraphElement("Audio/FootstepAudio", "FootstepAudioBehaviour")]
[HelpURL("https://docs.neofps.com/manual/motiongraphref-mgb-footstepaudiobehaviour.html")]
public class FootstepAudioBehaviour : MotionGraphBehaviour
{
[SerializeField, Tooltip("The surface audio library for the slide audio clips.")]
private SurfaceAudioData m_AudioData = null;
[SerializeField, Tooltip("The direction to cast in to get the surface type.")]
private Direction m_CastDirection = Direction.Down;
[SerializeField, Tooltip("The direction vector for the ray to cast when detecting surface type.")]
private Vector3 m_CastVector = Vector3.down;
[SerializeField, Tooltip("The direction vector parameter for the ray to cast when detecting surface type. If none is selected, defaults to character down.")]
private VectorParameter m_VectorParameter = null;
[SerializeField, Tooltip("The interval between steps. Higher numbers mean the steps are further apart.")]
private float m_StepInterval = 3f;
[SerializeField, Tooltip("The speed below which no footstep audio will be played.")]
private float m_MinimumSpeed = 0.01f;
[SerializeField, Tooltip("The maximum speed that the actual speed will be clamped to. Prevents rapid fire footsteps.")]
private float m_MaximumSpeed = 10f;
[SerializeField, Range (0.05f, 2f), Tooltip("The downward raycast length for the ground surface test.")]
private float m_MaxRayDistance = 1f;
private static readonly NeoSerializationKey k_CycleKey = new NeoSerializationKey("cycle");
private ICharacterAudioHandler m_AudioHandler = null;
private RaycastHit m_Hit = new RaycastHit();
private float m_StepCycle = 0f;
private FpsSurfaceMaterial m_LastSurfaceId = FpsSurfaceMaterial.Default;
public enum Direction
{
Down,
InverseGroundNormal,
LocalVector,
WorldVector,
WorldParameter,
WorldParameterInverse,
LocalParameter,
LocalParameterInverse
}
public override void OnValidate()
{
// Check minimum speed
if (m_MinimumSpeed < 0f)
m_MinimumSpeed = 0f;
// Clamp values
m_MaximumSpeed = Mathf.Clamp (m_MaximumSpeed, m_MinimumSpeed + 0.01f, 25f);
m_StepInterval = Mathf.Clamp(m_StepInterval, 0.1f, 10f);
}
public override void OnEnter()
{
// Get audio handler
if (m_AudioHandler == null)
m_AudioHandler = controller.localTransform.GetComponent<ICharacterAudioHandler>();
m_StepCycle = 0f;
}
public override void OnExit()
{
}
public override void Update()
{
if (m_AudioHandler == null || m_AudioData == null)
return;
float speed = controller.characterController.velocity.magnitude;
if (speed > m_MinimumSpeed)
{
// Cap speed
if (speed > m_MaximumSpeed)
speed = m_MaximumSpeed;
// Update step cycle & play audio on step
m_StepCycle += (speed * Time.deltaTime) / m_StepInterval;
while (m_StepCycle > 1f)
{
m_StepCycle -= 1f;
PlayAudio (GetGroundSurface ());
}
}
}
FpsSurfaceMaterial GetGroundSurface()
{
Space space = Space.World;
FpsSurfaceMaterial result = m_LastSurfaceId;
// Get charactercontroller info
var cc = controller.characterController;
#if NEOFPS_LIGHTWEIGHT
// Get raycast direction
Vector3 direction = Vector3.down;
switch (m_CastDirection)
{
case Direction.InverseGroundNormal:
if (cc.isGrounded)
direction = -cc.groundNormal;
break;
case Direction.LocalVector:
direction = m_CastVector;
space = Space.Self;
break;
case Direction.WorldVector:
direction = m_CastVector;
break;
case Direction.WorldParameter:
if (m_VectorParameter != null)
direction = m_VectorParameter.value.normalized;
break;
case Direction.WorldParameterInverse:
if (m_VectorParameter != null)
direction = -m_VectorParameter.value.normalized;
break;
case Direction.LocalParameter:
if (m_VectorParameter != null)
{
direction = m_VectorParameter.value.normalized;
space = Space.Self;
}
break;
case Direction.LocalParameterInverse:
if (m_VectorParameter != null)
{
direction = -m_VectorParameter.value.normalized;
space = Space.Self;
}
break;
}
#else
// Get raycast direction
Vector3 direction = Vector3.zero;
switch (m_CastDirection)
{
case Direction.Down:
direction = Vector3.down;
space = Space.Self;
break;
case Direction.InverseGroundNormal:
if (cc.isGrounded)
direction = -cc.groundNormal;
else
{
direction = Vector3.down;
space = Space.Self;
}
break;
case Direction.LocalVector:
direction = m_CastVector;
space = Space.Self;
break;
case Direction.WorldVector:
direction = m_CastVector;
break;
case Direction.WorldParameter:
if (m_VectorParameter != null)
direction = m_VectorParameter.value.normalized;
else
direction = -controller.characterController.up;
break;
case Direction.WorldParameterInverse:
if (m_VectorParameter != null)
direction = -m_VectorParameter.value.normalized;
else
direction = -controller.characterController.up;
break;
case Direction.LocalParameter:
if (m_VectorParameter != null)
direction = m_VectorParameter.value.normalized;
else
direction = Vector3.down;
space = Space.Self;
break;
case Direction.LocalParameterInverse:
if (m_VectorParameter != null)
direction = -m_VectorParameter.value.normalized;
else
direction = Vector3.down;
space = Space.Self;
break;
}
#endif
var radius = cc.radius;
var normalisedHeight = radius / cc.height;
// Raycast for surface type
if (cc.RayCast(normalisedHeight, direction * (m_MaxRayDistance + radius), space, out m_Hit, PhysicsFilter.Masks.BulletBlockers, QueryTriggerInteraction.Ignore))
{
// Get surface ID from ray hit
Transform t = m_Hit.transform;
if (t != null)
{
BaseSurface s = t.GetComponent<BaseSurface>();
if (s != null)
result = s.GetSurface(m_Hit);
else
result = FpsSurfaceMaterial.Default;
}
m_LastSurfaceId = result;
}
return result;
}
void PlayAudio(FpsSurfaceMaterial surface)
{
float volume = 1f;
AudioClip clip = m_AudioData.GetAudioClip(surface, out volume);
if (clip != null)
m_AudioHandler.PlayClip(clip, FpsCharacterAudioSource.Feet, volume);
}
public override void WriteProperties(INeoSerializer writer)
{
base.WriteProperties(writer);
writer.WriteValue(k_CycleKey, m_StepCycle);
}
public override void ReadProperties(INeoDeserializer reader)
{
base.ReadProperties(reader);
reader.TryReadValue(k_CycleKey, out m_StepCycle, m_StepCycle);
}
public override void CheckReferences(IMotionGraphMap map)
{
m_VectorParameter = map.Swap(m_VectorParameter);
base.CheckReferences(map);
}
}
}