You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
11 KiB
C#

4 years ago
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
using UnityEditorInternal;
using UnityEditor;
#endif
namespace MalbersAnimations.Utilities
{
[AddComponentMenu("Malbers/Utilities/Effects - Audio/Animator Event Sound")]
public class AnimatorEventSounds : MonoBehaviour, IAnimatorListener
{
public List<EventSound> m_EventSound;
public AudioSource _audioSource;
protected Animator anim;
public bool debug;
void Start()
{
anim = GetComponent<Animator>(); //Get the reference for the animator
if (_audioSource == null) //if there's no audio source add one..
_audioSource = gameObject.AddComponent<AudioSource>();
_audioSource.volume = 0;
}
public virtual void DisableSoundEvent(string SoundName)
{
EventSound SoundEvent = m_EventSound.Find(item => item.name == SoundName);
if (SoundEvent != null) SoundEvent.active = false;
}
public virtual void EnableSoundEvent(string SoundName)
{
EventSound SoundEvent = m_EventSound.Find(item => item.name == SoundName);
if (SoundEvent != null) SoundEvent.active = true;
}
public virtual void PlaySound(AnimationEvent e)
{
if (e.animatorClipInfo.weight < 0.1) return; // if is too small the weight of the animation clip do nothing
if (debug) Debug.Log($"Play Audio: Clip - [{e.animatorClipInfo.clip.name}]",e.animatorClipInfo.clip);
var SoundEvent = m_EventSound.Find(item => item.name == e.stringParameter && item.active == true);
if (SoundEvent != null)
{
SoundEvent.VolumeWeight = e.animatorClipInfo.weight;
if (anim) _audioSource.pitch = anim.speed; //Match the AnimatorSpeed with the Sound Pitch
if (_audioSource.isPlaying) //If the Audio is already Playing play the one that has more weight
{
if (SoundEvent.VolumeWeight * SoundEvent.volume > _audioSource.volume)
{
SoundEvent.PlayAudio(_audioSource);
}
}
else
{
SoundEvent.PlayAudio(_audioSource);
}
}
}
public virtual void PlaySound(string sound)
{
var SoundEvent = m_EventSound.Find(item => item.name == sound && item.active == true);
if (SoundEvent != null)
{
SoundEvent.VolumeWeight = 1;
if (_audioSource.isPlaying) //If the Audio is already Playing play the one that has more weight
{
if (SoundEvent.volume > _audioSource.volume)
SoundEvent.PlayAudio(_audioSource);
}
else
{
SoundEvent.PlayAudio(_audioSource);
}
}
}
public virtual void PlaySoundForever(string sound)
{
var SoundEvent = m_EventSound.Find(item => item.name == sound && item.active == true);
if (SoundEvent != null)
{
SoundEvent.VolumeWeight = 1;
StartCoroutine(C_Playforever(SoundEvent));
}
}
public virtual void StopPlaying(string sound)
{
var SoundEvent = m_EventSound.Find(item => item.name == sound && item.active == true);
if (SoundEvent != null && SoundEvent.source != null)
{
if (SoundEvent.source.isPlaying)
SoundEvent.source.Stop();
}
StopAllCoroutines();
}
IEnumerator C_Playforever(EventSound E_sound)
{
if (E_sound.interval <= 0)
{
yield return null;
}
else
{
var timeInterval = new WaitForSeconds(E_sound.interval);
while (true)
{
E_sound.PlayAudio(_audioSource);
yield return timeInterval;
}
}
yield return null;
}
public virtual bool OnAnimatorBehaviourMessage(string message, object value) => this.InvokeWithParams(message, value);
}
[System.Serializable]
public class EventSound
{
[Tooltip("Name of the Sound you will call on the Animation Event")]
public string name = "Name Here";
public float volume = 1;
public float pitch = 1;
public bool active = true;
[Tooltip("Interval Time to play a sound forever. Remember to call [PlaySoundForever]")]
public float interval = 0f;
public AudioSource source;
public AudioClip[] Clips;
/// <summary>Weight of the sound depeding of the Animation Weight</summary>
public float VolumeWeight { get; internal set; }
public void PlayAudio(AudioSource audio)
{
if (source == null) source = audio;
if (source == null) return; //Do nothing if the audio is empty
if (Clips == null || Clips.Length == 0) return; //Do nothing if there's no clips
source.spatialBlend = 1; //Set the sound to 3D
source.clip = Clips[Random.Range(0, Clips.Length)]; //Set a random clip to the audio Source
source.pitch = pitch; //Depending the animator speed modify the pitch
source.volume = Mathf.Clamp01(volume * VolumeWeight); //Depending the weight of the animation clip modify the volume
source.Play(); //Play the Audio
}
}
#if UNITY_EDITOR
[CanEditMultipleObjects, CustomEditor(typeof(AnimatorEventSounds))]
public class AnimEventSoundEditor : Editor
{
private ReorderableList list;
private SerializedProperty m_EventSound, debug;
private AnimatorEventSounds M;
private void OnEnable()
{
M = ((AnimatorEventSounds)target);
m_EventSound = serializedObject.FindProperty("m_EventSound");
debug = serializedObject.FindProperty("debug");
list = new ReorderableList(serializedObject, m_EventSound, true, true, true, true);
list.drawElementCallback = DrawElementCallback;
list.drawHeaderCallback = HeaderCallbackDelegate;
list.onAddCallback = OnAddCallBack;
}
public override void OnInspectorGUI()
{
serializedObject.Update();
MalbersEditor.DrawDescription("Receive animations events from the animations clips to play sounds using the method: PlaySound(string Name)");
EditorGUI.BeginChangeCheck();
{
EditorGUILayout.BeginVertical(MTools.StyleGray);
{
list.DoLayoutList();
if (list.index != -1)
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
SerializedProperty Element = m_EventSound.GetArrayElementAtIndex(list.index);
EditorGUILayout.LabelField("[" + M.m_EventSound[list.index].name + "]", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(Element.FindPropertyRelative("interval"));
EditorGUILayout.PropertyField(Element.FindPropertyRelative("Clips"), new GUIContent("Clips", "AudioClips"), true);
EditorGUILayout.PropertyField(Element.FindPropertyRelative("source"), new GUIContent("Internal Source", "AudioSource"));
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
}
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(serializedObject.FindProperty("_audioSource"), new GUIContent("Global Source", "AudioSource"), true);
}
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndVertical();
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Animation Event Sound");
// EditorUtility.SetDirty(target);
}
serializedObject.ApplyModifiedProperties();
}
void HeaderCallbackDelegate(Rect rect)
{
Rect R_1 = new Rect(rect.x + 28, rect.y, (rect.width) / 3 + 25, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(R_1, "Name");
Rect R_2 = new Rect(rect.x + (rect.width) / 3 + 65, rect.y, (rect.width) / 3, EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(R_2, "Volume");
Rect R_3 = new Rect(rect.x + ((rect.width) / 3) * 2 + 40, rect.y, ((rect.width) / 3), EditorGUIUtility.singleLineHeight);
EditorGUI.LabelField(R_3, "Pitch");
Rect R_4 = new Rect(rect.width, rect.y, 25, EditorGUIUtility.singleLineHeight);
MalbersEditor.DrawDebugIcon(R_4, debug);
}
void DrawElementCallback(Rect rect, int index, bool isActive, bool isFocused)
{
var element = m_EventSound.GetArrayElementAtIndex(index);
var name = element.FindPropertyRelative("name");
var active = element.FindPropertyRelative("active");
var volume = element.FindPropertyRelative("volume");
var pitch = element.FindPropertyRelative("pitch");
rect.y += 2;
Rect R_0 = new Rect(rect.x - 3, rect.y, 10, EditorGUIUtility.singleLineHeight);
Rect R_1 = new Rect(rect.x + 15, rect.y, (rect.width) / 3 + 55 - 15, EditorGUIUtility.singleLineHeight);
Rect R_2 = new Rect(rect.x + (rect.width) / 3 + 61, rect.y, (rect.width) / 3 - 30, EditorGUIUtility.singleLineHeight);
Rect R_3 = new Rect(rect.x + ((rect.width) / 3) * 2 + 35, rect.y, ((rect.width) / 3) - 35, EditorGUIUtility.singleLineHeight);
EditorGUI.PropertyField(R_0, active, GUIContent.none);
EditorGUI.PropertyField(R_1, name, GUIContent.none);
EditorGUI.PropertyField(R_2, volume, GUIContent.none);
EditorGUI.PropertyField(R_3, pitch, GUIContent.none);
}
void OnAddCallBack(ReorderableList list)
{
if (M.m_EventSound == null)
{
M.m_EventSound = new System.Collections.Generic.List<EventSound>();
}
M.m_EventSound.Add(new EventSound());
}
}
#endif
}