I have a couple of audio sources in a script, idea being that one is used for effects and the other for music. I am noticing that if an effect plays at the same time as another one, it actually stops the previous one from playing, probably because they are playing from the same audio source.
My question is, do I really have to instantiate a new audio source every time i want to play a new sound, just to make sure that one sound will not stop a currently playing one ? Is there a better way ?
The method that plays a sound effect(and the awake one) in my class are these :
void Awake() {
audioSource = GetComponents<AudioSource>()[0];
audioEffectsSource = GetComponents<AudioSource>()[1];
audioSource.volume = PlayerPrefsManager.getMasterVolume();
audioEffectsSource.volume = PlayerPrefsManager.getSFXMasterVolume();
}
public void playSoundEffect(AudioClip clip)
{
if(clip != null)
{
audioEffectsSource.clip = clip;
audioEffectsSource.volume = PlayerPrefsManager.getSFXMasterVolume();
audioEffectsSource.PlayOneShot(clip);
}
}
The script is attached to a musicmanager gameobject with 2 audiosources, one for music fx and one for sound tracks.
Related
Ok let me try and explain...
I am making a card game where it plays a sound effect when a card is added to a pile, but during the setup cards are rapidly added to different piles and it breaks if I use a single Audiosource
If I play it from a single audiosource it seems not to play them all or if it is it's playing them all at once.
vs
If I do it by having an audiosource on each pile and use that instance of it and hear the different effects played.
I am in the middle of rewriting the game as the first time was a dry run and didn't know what I was going to need and is a bit rough and came across this while trying to streamline the in game audio by having a GameAudioManager singleton to handle the audio.
Is there a reason for this and a solution?
Info
Sound Effect is a MP3 and 3kb
Delay between effects is 0.01f
Choice is yours actually...
Want them to play sequentially ? one audio source is enough and add pending clips to a queue and dequeue them as the currently playing one finishes.
Want them to play individually, separately as the event happens, regardless of whether another card was just added and its effect was still playing, then you use multiple audio sources.
Here's a starting point for a manager that plays audios individually as they're requested.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GameAudioManager : MonoBehaviour
{
// your singleton pattern here, so assuming you now have an instance.
public static GameAudioManager Instance;
// List holds available sources that we can use to play an audio clip.
List<AudioSource> availableSources = new List<AudioSource>();
// Immediately plays a clip, if a cached audio source available, uses it, if none, create new.
public static void AudioPlayOneShot(AudioClip clip, float volume, float pitch, bool loop)
{
Instance.StartCoroutine(Instance.StartPlayingOneShot(clip, volume, pitch, loop);
}
private IEnumerator StartPlayingOneShot(AudioClip clip, float volume, float pitch, bool loop)
{
AudioSource audioSource = GetAudioSource();
audioSource.playOnAwake = false;
audioSource.clip = clip;
audioSource.volume = volume;
audioSource.pitch = pitch;
audioSource.loop = loop;
audioSource.Play();
while (audioSource.isPlaying)
yield return null;
// Whenever this clip stops, add it back to available cache.
CacheAudioSource(audioSource);
}
private void CacheAudioSource(AudioSource audioSource)
{
audioSource.clip = null;
audioSource.playOnAwake = false;
availableSources.Add(audioSource);
}
/// <summary>
/// Gets an audio source from cached list or creates a new one if none available.
/// </summary>
/// <returns></returns>
private AudioSource GetAudioSource()
{
if (availableSources == null || availableSources.Count == 0)
return this.gameObject.AddComponent<AudioSource>();
else
{
AudioSource fromCache = availableSources[0];
availableSources.RemoveAt(0);
return fromCache;
}
}
}
Use like
GameAudioManager.AudioPlayOneShot(yourClip, yourVolume, yourPitch, loop);
The reason it wasn't working was that a AudioSource can only have one instance of itself playing so if it is playing already it is unable to start the new play.
The solution is to either instantiate them as needed or have it on each item and be able to play it from those individual AudioSources.
Hope this helps anyone else coming across this.
I am making a game now, it's almost done. now I am trying to control the audio on and off by button or toggle button.
The problem is, I put my audio source gameobject in the splashscreen that is in the 1st scene. and I put the audio or music button in the Setting scene which is inside the 3rd scene. I already make the c# script to control the audio but when I've tried to insert the AudioSource, but it can't since it's from a different scene. I've tried to put the AudioSource in the same scene but the audio didn't start except I go to settings scene first.
Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Music : MonoBehaviour
{
static Music instance = null;
public AudioSource Backsound;
private void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
public void backsoundOnOff()
{
AudioSource bgsound = Backsound.GetComponent<AudioSource>();
if (bgsound.mute = true){
bgsound.mute = false;
}
else {
bgsound.mute = true;
}
}
}
You have already solved half the problem by using GameObject.DontDestroyOnLoad
The object does indeed exist in both scenes. Now you just need to fetch it.
In the first scene where the created the object, Change the tag of the object. Instead of using one of the exiting tags, create a new tag for it called something such as "MenuMusic". Make sure you assign it after creating it, unity does not assign it automatically
Now, in the 3rd scene, in the game object that needs to access it, create a private field "_music"
in your Start function, add
void Start() {
_music = GameObject.FindGameObjectsWithTag("MenuMusic");
}
You will now have the same instance of Music from scene 1
I would highly recommend referencing the sound script that you have into some sort of game manager. Usually how i work is i have one generic script that controls a multitude of options that i usually call the GameManager. This sets player controls, visual options and sound. From here you can simply set bool whether the player wants the music on and off. If this option wants to change you can reference the GameManager at any point in any script.
//Game Manager code
public void SoundControl(bool soundOff)
{
If(soundOff == true)
{
//Sound Off Control
}else
{
//Sound on Control
}
}
//Reference to game Manager
GameManager manager;
public void TurnOffSound()
{
//Turn sound off through manager
manager =
GameObject.FindGameObjectWithTag("Manager").GetComponent<GameManager>
().SoundControl(true);
}
I find this to be the easiest way to control any options through one script that you can reference anywhere.
I have spent all day looking for a solution to this problem, and I simply can't find one. Using JavaScript in Unity 3D, I have a script where I want to play a sound when the player's velocity on the X axis reaches a certain point, and if it's not at that point, then the sound will be muted. And I believe I have all the structure right, it's just the line of code that says to mute the audio that won't work. I've tried all kinds of different combinations, and I get an error for each one.
The script looks like this:
#pragma strict
var playing = false;
var audioSource = GetComponent.<AudioSource>();
function Update () {
if (transform.GetComponent.<Rigidbody>().velocity.x <= 2.5 &&
transform.GetComponent.<Rigidbody>().velocity.x >= -2.5)
{
Mute();
} else {
Unmute();
}
}
function Mute () {
audioSource.mute = true;
}
function Unmute () {
audioSource.mute = false;
Sound();
}
function Sound () {
if (transform.GetComponent.<Rigidbody>().velocity.x >= 2.5 && playing ==
false)
{
playing = true;
GetComponent.<AudioSource>().Play();
yield WaitForSeconds(2);
playing = false;
}
if (transform.GetComponent.<Rigidbody>().velocity.x <= -2.5 &&
playing == false)
{
playing = true;
GetComponent.<AudioSource>().Play();
yield WaitForSeconds(2);
playing = false;
}
}
I've gotten all kinds of different errors, but the one I seem to be getting the most says "UnityException: GetComponentFastPath is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'motioncheck' on game object 'Ball'." I'm not sure what this means, since I'm still kinda a nub at JavaScript.
I feel like it shouldn't be this hard to just mute a sound. I'm going to assume that the answer to this is really simple and that I'm just really dumb. That's what usually seems to happen, lol.
In the mean time, I'm going to continue my rampage across the internet in search for answers to this problem.
Your mute code is fine.
"UnityException: GetComponentFastPath is not allowed to be called from
a MonoBehaviour constructor (or instance field initializer), call it
in Awake or Start instead. Called from MonoBehaviour 'motioncheck' on
game object 'Ball'." I'm not sure what this means, since I'm still
kinda a nub at JavaScript.
See this:
var audioSource = GetComponent.<AudioSource>();
That's a Unity API and you have to call their functions from inside a function. The Awake or Start function is appropriate for initializing component variables.
var audioSource : AudioSource;
function Start()
{
audioSource = GetComponent.<AudioSource>();
}
Note that Unityscript/Javascript is now discontinued. They no longer update the doc on this and you cannot create new scripts from the Editor anymore. It still works as for now but the compiler will be removed soon. Please learn and start using C# before its support is totally removed.
I have a mono .wav file that I'm trying to play as a PlayOneShot() AudioClip in my game using an AudioSource. The sound plays perfectly in the Unity editor but for some reason echos and leaves a lasting reverb in the game that never goes away. It's called using just a simple PlaySound function from here:
public static void PlaySound (string clip) {
switch (clip) {
case "death":
audioSrc.PlayOneShot (deathSound);
break;
case "move":
audioSrc.PlayOneShot (move);
break;
case "success":
audioSrc.PlayOneShot (success);
break;
}
}
And this AudioSource handles all other sounds perfectly. I don't know what I can even try to change because I'm not messing with any AudioSource options to begin with. Does Unity2d not handle mono sounds well?
I solved my own problem using information found here: https://answers.unity.com/questions/451895/distorted-audio-using-playoneshot.html
The problem was that the PlayOneShot was being called multiple times because the condition to play the noise was met for an extended period of time. To handle this I set a bool to false after it plays one time, and check to see if the bool is true before playing the sound to begin with.
You could do something like this:
public AudioClip[] otherSounds;
AudioSource audioSource;
void Start(){
audioSource = GetComponent<AudioSource>();
}
void Update() {
if(){
audioSource.clip = otherSounds[Index];
}
}
In my game, I have two scene.
What I want to achieve is if user navigates from one scene to another, background audio specific to each should be played from start(audio length=0)
But all my efforts are in vain.
I tried using 'Pause' Method of audioSound
I tried
create a new game object and assign this scene background score to it and play
destroy gameObject created for another scene if there was any
But it doesn't give the result that I want.
I searched for finding how to play audioClip from start and stop other audioClip playing but didn't find any.
I know I'm not supposed to ask for code on stack overflow but if anyone has achieved this or has some pseudo code request you to provide it
I'm not sure I understand your question properly, since it seems the simplest scenario for background music.
If you really want a change of audioclip in every scene, let's say Scene A must play Clip A and Scene B must play Clip B, and both clips should be played as soon as a scene is loaded, you just need to create a game object in both scenes with an Audio Source component, with the Play On Awake flag active, and then just assign the appropriate clip for the scene (i.e.: assign Clip A in the Audio Clip field of the Audio Source component of Scene A game object, and do the same with Clip B for Scene B).
That's pretty much it.
If you looking at the detail code then you can try this code.
First : Make a script "SoundFxScript.cs" // You can modified as you want
Insert this code :
public class SoundFxScript : MonoBehaviour {
//Background Music
public AudioSource Scene1_Sound;
public AudioSource Scene2_Sound;
// Use this for initialization
void Start () {
PlayBackgroundMusic ();
}
// Update is called once per frame
void Update () {
}
public void PlayBackgroundMusic() {
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene ().name == "Scene1") {
Scene1_SoundPlay();
} else if (UnityEngine.SceneManagement.SceneManager.GetActiveScene ().name == "Scene2") {
Scene2_SoundPlay();
}
}
public void Scene1_SoundPlay() {
Scene1_Sound.Play ();
Scene2_Sound.Stop ();
}
public void Scene2_SoundPlay() {
Scene1_Sound.Stop ();
Scene2_Sound.Play ();
}
// Step Fifth
public void LoadTheScene (string Scenename) {
UnityEngine.SceneManagement.SceneManager.LoadScene (Scenename);
sf.PlayBackgroundMusic ();
}
}
Second : Make Gameobject name = "SoundMusic" at the first scene and add component script SoundFxScript.cs. In gameobject "SoundMusic" you can add you background music for scene1 and scene2.
Third : Make a singleton file Singleton.cs
Insert this code :
public class Singleton : MonoBehaviour {
static Singleton instance = null;
void Start ()
{
if (instance != null)
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
instance = this;
}
}
Fourth : at gameobject "SoundMusic" add component script "Singleton.cs"
Fifth : How To Call In Another Scene (Load Scene). This method is inside SoundFxScript.cs
Example You have a method to call a load scene. Try this method :
Call it with : LoadTheScene("Scene2") // Call scene2
In here you can call your SoundFxscript.cs Component from any script you have.
Example :
SoundFxScript sf;
sf = GameObject.Find ("SoundMusic").GetComponent<SoundFxScript> ();
And you can use method LoadTheScene to load a new scene and the background music will RePlay again according to the what Scene is it.
That's All.