Post by jgiroux on Aug 21, 2016 16:20:54 GMT
Battle Music Add-On
Hello all, together with Chronicman, we have offered you a much updated version of the original (Thanks to chronicman for his additions)
What it does: Allow the user to play background music that will change to Danger music when within a specified threshold of distance between player and gameobject Tag, and crossfade back into background music when player get far enough away from danger.
can also be used for audible Alerts upon getting too close to a enemy (by turning off Loop mode for the battle music and using a Alert sound instead of combat music).
First, create a new script and call it CombatMusicAddOn and open it. Copy/Paste the following code and save/build.
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Invector;
//edited by Chronicman//
[RequireComponent(typeof(SphereCollider))]
//end of edit
public class CombatMusicAddOn : MonoBehaviour
{
//edited by Chronicman//
public static CombatMusicAddOn combatMusic;
[Tooltip("Uses the senor to detect enemies NOTE: this may trigger some unexpected events")]
public bool using_Sensor;
[Tooltip("The radius of the sphere collider i.e dection of enimies")]
public float Radius = 20;
private SphereCollider Sensor;
//end of edit
public AudioClip BackgroundMusic; //calm audio clip to play when safe
[HideInInspector]
public AudioSource _calmAudioSource; //cache to our audioSource component
public bool KeepMusicAlive;
public List<Combatinfo> CombatMusic = new List<Combatinfo>();
private int cnt;
public List<GameObject> enemies = new List<GameObject>();// Added by chronicman
[System.Serializable]
public class Combatinfo
{
public string Identifier;
public bool LoopOn;
public AudioClip dangerClip; //danger audio clip to play when enemies are near
[HideInInspector]
public AudioSource _dangerAudioSource; //cache to our audioSource component
[HideInInspector]
public Transform _transform; //cache to our transform component
public string enemyTag; //enemy tag to scan for
public float safeRange; //how far is safe from enemies?
[HideInInspector]
public float timer; //for counting seconds
[HideInInspector]
public float frameTime; //length of a frame at 15fps
[Range(0.01f, 30f)]
public float crossfadeTime; //how many seconds to fade between clips
[Range(1, 100)]
public float volume; //volume to play audio at
}
//use this to initialize component references and script variables
void Awake()
{
for ( cnt = 0; cnt < CombatMusic.Count; cnt++)
{
CombatMusic[cnt]._transform = transform; //cache our transform component
//setup one audioSource to play the calm audio with
_calmAudioSource = gameObject.AddComponent<AudioSource>();
_calmAudioSource.clip = BackgroundMusic;
_calmAudioSource.loop = true;
_calmAudioSource.volume = CombatMusic[cnt].volume;
//setup one audioSource to play the danger audio with
CombatMusic[cnt]._dangerAudioSource = gameObject.AddComponent<AudioSource>();
CombatMusic[cnt]._dangerAudioSource.clip = CombatMusic[cnt].dangerClip;
if (CombatMusic[cnt].LoopOn == true)
{
CombatMusic[cnt]._dangerAudioSource.loop = true;
}
CombatMusic[cnt]._dangerAudioSource.volume = 0.0f;
CombatMusic[cnt].timer = 0.0f; //default timer to 0.0f
}
}
void Start()
{
// edited by chronicman
combatMusic = GetComponent<CombatMusicAddOn>();
if (using_Sensor)
{
Sensor = gameObject.GetComponent<SphereCollider>();
Sensor.radius = Radius;
Sensor.isTrigger = true;
}
else
{
Sensor = gameObject.GetComponent<SphereCollider>();
Sensor.enabled = false;
}
// end of edit
for (int cnt = 0; cnt < CombatMusic.Count; cnt++)
{
_calmAudioSource.Play(); //begin playing background music
CombatMusic[cnt].frameTime = 1.0f / 15.0f; //time of one frame at 15fps in seconds
}
}
// edited by chronicman
public void CheckStatus()
{
if (enemies != null)
{
InvokeRepeating("SoundCheck", 1.0f, 1.0f / 15.0f); //instead of using update, just call this every 15 frames
}
else
{
// do nothing
}
}
//end of edit
private void SoundCheck()
{
if (enemies != null)
{
for ( cnt = 0; cnt < CombatMusic.Count; cnt++)
{
//GameObject[] enemies = GameObject.FindGameObjectsWithTag(CombatMusic[cnt].enemyTag); //get a list of all game objects tagged with the enemy tag
bool safe = Array.FindIndex(enemies.ToArray(), x => Vector3.Distance(x.transform.position, CombatMusic[cnt]._transform.position) < CombatMusic[cnt].safeRange) < 0;
if (safe)
{
if (CombatMusic[cnt].timer > 0.0f)
{//timer is used to crossfade the two audio sources
CombatMusic[cnt].timer -= CombatMusic[cnt].frameTime;
if (CombatMusic[cnt].timer <= 0.0f)
{
_calmAudioSource.volume = CombatMusic[cnt].volume;
CombatMusic[cnt]._dangerAudioSource.volume = 0.0f;
CombatMusic[cnt].timer = 0.0f;
}
}
}
else
{
if (CombatMusic[cnt].timer < CombatMusic[cnt].crossfadeTime)
{//timer is used to crossfade the two audio sources
CombatMusic[cnt].timer += CombatMusic[cnt].frameTime;
if (CombatMusic[cnt].timer >= CombatMusic[cnt].crossfadeTime)
{
CombatMusic[cnt]._dangerAudioSource.volume = CombatMusic[cnt].volume;
CombatMusic[cnt]._dangerAudioSource.Play();
if (KeepMusicAlive == false)
{
_calmAudioSource.volume = 0.0f;
}
CombatMusic[cnt].timer = CombatMusic[cnt].crossfadeTime;
}
}
}
if (CombatMusic[cnt].timer != (safe ? 0.0f : CombatMusic[cnt].crossfadeTime))
{//we're crossfading
float crossfade = CombatMusic[cnt].timer / CombatMusic[cnt].crossfadeTime;
_calmAudioSource.volume = crossfade * CombatMusic[cnt].volume;
CombatMusic[cnt]._dangerAudioSource.volume = (1.0f - crossfade) * CombatMusic[cnt].volume;
}
}
}
else
{
CancelInvoke("SoundCheck");
enemies.Clear();
}
}
//edited by chronicman
void OnTriggerEnter(Collider other)
{
if (using_Sensor)
{
for (cnt = 0; cnt < CombatMusic.Count; cnt++)
{
if (other.tag == CombatMusic[cnt].enemyTag)
{
if (enemies.Contains(other.gameObject))
{
// do nothing
}
else
{
enemies.Add(other.gameObject);
CheckStatus();
}
}
}
}
}
void OnTriggerExit(Collider other)
{
if (using_Sensor)
{
for (cnt = 0; cnt < CombatMusic.Count; cnt++)
{
if (other.tag == CombatMusic[cnt].enemyTag)
{
if (enemies.Contains(other.gameObject))
{
enemies.Remove(other.gameObject);
CheckStatus();
}
else
{
// do nothing
}
}
}
}
}
//end of edit
}
STEPS
1) add script to Player Controller.
2) enable senor if you wish to use OnTriggerEnter & OnTiggerExit to find enemies, if false you must attach the BattleMusicAddonAI script on AI. Note BattleMusicAddonAI is below
3) add your Background music to the field "Background Music"
4) Do you want this background music to continue playing behind the Damage Music? (good for when you want to trigger Alert Sounds rather than combat music) if so, make sure "Keep Music Alive" is checked
5) Under Combat Music add how many you'd like (in case you have various Tags you'd like different combat audio to work with)
a) Identifier = Just a name that helps you identify each element (rather than element 0, element 1, etc) has no effect on gameplay or script itself.
b) Loop On = do you want a single one shot sound on enemy approach, or loop your audio?
c) Danger Clip = this is the audio that will play when an enemy or object(defined by Tag) gets near player
d) Enemy Tag = Put Tag of object you want to trigger combat sound.
e) Safe Range = how close to object before combat sound starts
f) Crossfade Time = How long(in seconds) that the two audios (background music and combat music) will crossfade
g) Volume = Volume of combat music
** Battle Music Add-On **
First, create a new script and call it CombatMusicAddOnAI and open it. Copy/Paste the following code and save/build.
using UnityEngine;
using System.Collections;
using Invector;
public class CombatMusicAddonAI : MonoBehaviour {
[HideInInspector]
public vCharacter iChar; // reference to the AI
[Tooltip("Using update to check health to remove AI from list")]
public bool using_Update; // using update to check health
[Tooltip("Using slide to check health to remove AI from list **NOTE you must use On value change located on the slider and call the method HealthUpdate**")]
public bool using_Slider;// using slider to check health
bool isAlive = true;
void Start ()
{
iChar = GetComponent<vCharacter>();
Invoke("lateStart", 0.1f);
}
void lateStart()
{
CombatMusicAddOn.combatMusic.enemies.Add(gameObject);
CombatMusicAddOn.combatMusic.CheckStatus();// checkes to see in any enemies are in list if so keep repeating.
}
void Update ()
{
if (using_Update)
{
if (iChar.currentHealth < 1 && isAlive)
{
CombatMusicAddOn.combatMusic.enemies.Remove(gameObject);//removes enemy from list
CombatMusicAddOn.combatMusic.CheckStatus();// checkes to see in any enemies are in list if so keep repeating.
}
}
}
public void HealthUpdate()
{
if (using_Slider)
{
if (iChar.currentHealth < 1 && isAlive)
{
CombatMusicAddOn.combatMusic.enemies.Remove(gameObject);//removes enemy from list
CombatMusicAddOn.combatMusic.CheckStatus();// checkes to see in any enemies are in list if so keep repeating.
}
}
}
}
** STEPS *************
1) add script to AI
2) choose method of monitoring AI health.(For removal of enemy in list)
Update will be called every frame, checking the AIs health to know when to remove its self from the list. This is pretty heavy so I added another way but you can use update if you like.
OnValueChanged will be called only when the health slider value changes i.e when hes damaged or regeneration procs. Simply locate the AI slider and select it , there will be a method called OnValueChanged click the + symbol and drag the AI into the slot under runtime.There will be a options list beside click that and search for BattleMusicAddonAI then select the UpdateHealth function and your finished. Enjoy
** CHANGE LEVEL/SCENE TRIGGER **********
Note: I added this script to fix the bug while changing scenes. You welcome to use it or your own and just call CombatMusicAddOn.combatMusic.enemies.Clear(); before you change scene or else you will get an error.
First, create a new script and call it CombatMusicAddonLevelTrigger and open it. Copy/Paste the following code and save/build.
using UnityEngine;
using System.Collections;
#if UNITY_5_3
using UnityEngine.SceneManagement;
#endif
public class CombatMusicAddonLevelTrigger : MonoBehaviour
{
[Tooltip("Name of the level you wish to load")]
public string levelName;
private CombatMusicAddOn combatMusic;
public static CombatMusicAddonLevelTrigger LevelTrigger;
void Start ()
{
combatMusic = CombatMusicAddOn.combatMusic;
LevelTrigger = GetComponent<CombatMusicAddonLevelTrigger>();
}
public void LoadLevel (string levelName)
{
combatMusic.enemies.Clear();
#if UNITY_5_3
SceneManager.LoadScene(levelName);
#else
Application.LoadLevel(levelName);
#endif
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
combatMusic.enemies.Clear();
#if UNITY_5_3
SceneManager.LoadScene(levelName);
#else
Application.LoadLevel(levelName);
#endif
}
}
}
** STEPS *********
1) attach script onto game object in scene
2) add a collider and set it to trigger
3) call CombatMusicAddonLevelTrigger .LevelTrigger.LoadLevel("myLevelName");
as always, feel free to use however you wish, if you have any questions feel free to ask either one of us, hope this can help someone out.