- Home /
Easier Way To Add Sound Via GUI?
Basically, I want to add a 'click' sound every time someone clicks on a GUI button. Now I have a lot of buttons, so I don't want to be doing stuff like:
if(GUI.Button(Rect ......
playAudioClip ...
... for every button
Is there a way to define every 'OnButtonDown' to play the click sound? I was thinking about the Input.GetButtonDown(0) // or Fire1 but that just means that no matter where I click - it will make the sound.
Any ideas?
Answer by Statement · Dec 11, 2010 at 12:38 AM
Super simple function decoration
Here is a super simple way to play sound when pressing a button:
var buttonClip : AudioClip;
function OnGUI ( ) { if ( Play( GUILayout.Button( "Press me!" ) ) ) Debug.Log( "Pressed button" ); }
function Play (value : boolean) : boolean { if ( value )
audio.PlayOneShot( buttonClip );
return value;
}
It works by padding the call to GUILayout.Button with a call to Play. If the button return true, the sound is played, and the value is then transparently sent to the if test.
C# Extension Method Version Fun
In C# you can make use of extension methods that can give a slightly different syntax than the JS one.
public class Sound : MonoBehaviour { public AudioClip buttonClip;
void OnGUI ( )
{
if ( GUILayout.Button( "Press me!" ).Play( buttonClip ) )
Debug.Log( "Pressed button" );
}
}
It works by adding an extension method to the bool type. This way you can call Play on any boolean value. Beware that this can easily pollute the namespace, so I tend to put these kind of extensions in a separate namespace which I manually import when I want to use them.
To use them, I just include the namespace:
using GUISounds;
And the code could look something like this.
namespace GUISounds { public static class SoundExtension { static AudioSource audio;
public static bool Play ( this bool value, AudioClip clip )
{
if ( !clip || !value ) return value;
EnsureAudioExists( );
audio.PlayOneShot( clip );
return value;
}
public static void DestroyAudio ( )
{
if ( audio )
{
GameObject.Destroy( audio.gameObject );
}
}
public static void CreateAudio ( )
{
GameObject audioObject = new GameObject( "GUISounds Audio Extension" );
audio = audioObject.AddComponent<AudioSource>( );
}
private static void EnsureAudioExists ( )
{
if ( !audio )
{
CreateAudio( );
}
}
}
}
You can see the C# backend became quite verbose since it has to handle temporary objects to play the sound. The advantage (and disadvantage?) is that you can use Play( clip ) on any boolean value! However, be careful with using extension methods too much on common types such as booleans - it will just pollute your namespace. Again, put them in a namespace so you can choose which scripts can make use of the extensions.
You can easily adopt the JS version to C#, but not the other way around. In the end both techniques work similarly; You check the value of a boolean and pass it on, but decorating the call with a sound play. This is more reusable than the answer by skovacs1 where code duplication can lead to a maintainability issue. You can use any version of GUI.Button, GUILayout.Button or any other call that return a boolean. You can easily see how you can extend other unity functions following the same principle.
Answer by skovacs1 · Dec 10, 2010 at 11:19 PM
You could wrap GUI.Button within functions which add and play your sound:
static function SoundButton (sound : AudioClip, position : Rect, text : String) : boolean { if(GUI.Button(position, text)) { audio.PlayOneShot(sound); return true; } return false; }
static function SoundButton (sound : AudioClip, position : Rect, image : Texture) : boolean { if(GUI.Button(position, image)) { audio.PlayOneShot(sound); return true; } return false; }
static function SoundButton (sound : AudioClip, position : Rect, content : GUIContent) : boolean { if(GUI.Button(position, content)) { audio.PlayOneShot(sound); return true; } return false; }
static function SoundButton (sound : AudioClip, position : Rect, text : String, style : GUIStyle) : boolean { if(GUI.Button(position, text, style)) { audio.PlayOneShot(sound); return true; } return false; }
static function SoundButton (sound : AudioClip, position : Rect, image : Texture, style : GUIStyle) : boolean { if(GUI.Button(position, image, style)) { audio.PlayOneShot(sound); return true; } return false; }
static function SoundButton (sound : AudioClip, position : Rect, content : GUIContent, style : GUIStyle) : boolean { if(GUI.Button(position, content, style)) { audio.PlayOneShot(sound); return true; } return false; }
You could then call if(SoundButton(....))
You could even go so far as to extend the GUI class to include them.
How do you extend the GUI class? Is this a JS specific feature or can I do this in C# also?
In C#, if the class was declared with the partial keyword, you could further define it with the partial keyword, but since that likely isn't the case, you would be deriving from the GUI class, (which js does with the keyword "extends" and C# does with a colon ":").
Your answer
Follow this Question
Related Questions
Audio Question 2 Answers
play an audio clip from a GUI button 1 Answer
Rewind button works but not fast forward button? 1 Answer
New GUI and Inventory problem. 1 Answer
Play Sound when GUI button is pressed. 7 Answers