GameObject Audio On Mouse Click

Ok so I have a cube, made in unity. When I click on that cube Id like for an audio sample to play. I have this code but sound doesnt happen, any idea what im missing? I tried looking but I keep seeing this same basic code. There is an audio source on the cube as well.

var Trigger : AudioClip;

function OnMouseDown(){
     if (Input.GetButtonDown ("Fire1")) {
     audio.Play();
     Debug.Log("audio is working");
     }
}

To play music from one cube, then the cube has to finish playing before you can click it to play again :

#pragma strict

var Trigger : AudioClip;
var isPlayingAudio : boolean = false;

function OnMouseDown()
{
    if (!isPlayingAudio)
    {
    	isPlayingAudio = true;
	    audio.clip = Trigger;
	    audio.Play();
	    Debug.Log("audio is Playing");
	    Invoke( "AudioIsFinished", Trigger.length );
    }
}

function AudioIsFinished() 
{
    Debug.Log("audio is Stopped");
	isPlayingAudio = false;
}

To Do what you are suggesting of only having one audio but multiple cubes, I would do it totally differently :

  • On one script, raycast from the mouse position.
  • If music is not playing :
  • for the cube that has been hit, assign an audioclip based on its name, and play it.
  • Set boolean to isPlaying true so that no other cubes can play anything.
  • same as above to reset the boolean to allow cubes to become playable again.

Did all that make sense?


Alternative 2 :

Actually, I finished it sooner than I thought! Scenario :

Multiple cubes are in the scene. When a cube is clicked, audio is played. No other cube can be clicked until the audio is finished.

There are some rules to make this work.

  • name your cubes in this format : trackNN e.g. track01 track07 track10 track11 track19 track75 track99 . You can use a capitol T, but the number must be between 00 and 99. You must start at Track01, or it will break. If you dont use 0 in front of single digits it will break . So Track07 is fine, track14 also fine, track1 or Track5 will make it break.
  • Create an empty gameObject. Attach the below script. (An AudioSource will be added when the script is attached). Let’s call it AudioManager
  • Make all your music cubes children of AudioManager (drag and drop them on the empty object).
  • In the Inspector of AudioManager, drop your sounds into musicTracks ( it will appear as Music Tracks ).
  • Important : you must have the same amount of clips as there are cubes, or it will break . The audio must be in the correct order e.g. for music cube 1 (called track01) the first audio in musicTracks will be associated with it. cube track02 is the second audio in musicTracks , etc.

If I have made this not too confusing, you should have no problems inplementing this. The good news is as long as you start your naming with track01 to track10, you can keep adding up to 99 cubes! just make the new cube a child of the AudioManager and drop the sound in the inspector.

Ok finally here’s the new script :

#pragma strict
@script RequireComponent( AudioSource );

public var musicTracks : AudioClip[];

private var musicManager : Transform;
private var musicCubes : Transform[];

var isPlayingAudio : boolean = false;

function Start() 
{
	audio.Stop(); // incase PlayOnAwake is ticked
	
	// check there is music in the Inspector
	if ( musicTracks.Length == 0 )
	{
		Debug.Log( " musicTracks are missing ..." );
	}
	
	// load all Music Cubes into array
	SetupArrays();
}

function Update() 
{
	if ( Input.GetMouseButtonDown(0) && !isPlayingAudio )
	{
		CheckForMusicCube();
	}
}

function SetupArrays() 
{
	musicManager = this.transform;
	
	musicCubes = new Transform[ musicManager.childCount ];
	
	var i : int = 0;
	for ( var theTrack in musicManager )
	{
		musicCubes[i++] = theTrack as Transform;
	}
}

function CheckForMusicCube()
{
	// raycast to find next clicked cube
	var ray : Ray = Camera.main.ScreenPointToRay( Input.mousePosition );
	var hit : RaycastHit;
	
	if ( Physics.Raycast( ray, hit, 1000 ) )
	{
		//Debug.Log( "Ray Hit " + hit.collider.gameObject.name );		
		var theName : String = hit.collider.gameObject.name;
		
		//var theSubName : String = theName.Substring( 0, 5 );		
		//Debug.Log( theName + " : " + theSubName );		
		if ( theName.Substring( 0, 5 ) == "track" || theName.Substring( 0, 5 ) == "Track" )
		{
			//Debug.Log( theName.Substring( 5, 2 ) + " : " + parseInt( theName.Substring( 5, 2 ) ) );			
			// get clip from array based on clicked cube
		    var nextClipIndex : int = parseInt( theName.Substring( 5, 2 ) ) - 1;
		    var nextClip : AudioClip = musicTracks[ nextClipIndex ];
		    audio.clip = nextClip;
		    
	    	isPlayingAudio = true;
		    audio.Play();
		    //Debug.Log("audio is Playing");
		    Invoke( "AudioIsFinished", nextClip.length );
		}
	}
}

function AudioIsFinished() 
{
    //Debug.Log("audio is Stopped");
	isPlayingAudio = false;
}

I have left lots of Debugs in there ready to be uncommented, for troubleshooting if needed. Constructive feedback is welcome. Have Fun =]


Alternative 3 :

If you want to just stop the current audio and play the new audio, you can modify the second example like this :

#pragma strict
@script RequireComponent( AudioSource );
 
public var musicTracks : AudioClip[];
 
private var musicManager : Transform;
private var musicCubes : Transform[];


function Start() 
{
	audio.Stop(); // incase PlayOnAwake is ticked
	audio.loop = false; // incase loop is ticked
	
	// check there is music in the Inspector
	if ( musicTracks.Length == 0 )
	{
		Debug.Log( " musicTracks are missing ..." );
	}
	
	// load all Music Cubes into array
	SetupArrays();
}


function Update() 
{
	if ( Input.GetMouseButtonDown(0) )
	{
		CheckForMusicCube();
	}
}

function SetupArrays()
{
	musicManager = this.transform;
	
	musicCubes = new Transform[ musicManager.childCount ];
	
	var i : int = 0;
	for ( var theTrack in musicManager )
	{
		musicCubes[ i ] = theTrack as Transform;
		i ++;
	}
}

function CheckForMusicCube()
{
	// raycast to find next clicked cube
	var ray : Ray = Camera.main.ScreenPointToRay( Input.mousePosition );
	var hit : RaycastHit;
	
	if ( Physics.Raycast( ray, hit, 1000 ) )
	{
		//Debug.Log( "Ray Hit " + hit.collider.gameObject.name );
		var theName : String = hit.collider.gameObject.name;
		
		//var theSubName : String = theName.Substring( 0, 5 );
		//Debug.Log( theName + " : " + theSubName );
		
		if ( theName.Substring( 0, 5 ) == "track" || theName.Substring( 0, 5 ) == "Track" )
		{
			audio.Stop(); // stop the current track
			
			//Debug.Log( theName.Substring( 5, 2 ) + " : " + parseInt( theName.Substring( 5, 2 ) ) );
			
			// get clip from array based on clicked cube
			var nextClipIndex : int = parseInt( theName.Substring( 5, 2 ) ) - 1;
			var nextClip : AudioClip = musicTracks[ nextClipIndex ];
			audio.clip = nextClip;
			
			audio.Play(); // play the new track
		}
	}
}

Alternative 4 :

Here is how to check if the selected cube is the same as the last selected cube, if so then do nothing.

#pragma strict
@script RequireComponent( AudioSource );
 
public var musicTracks : AudioClip[];
 
private var musicManager : Transform;
private var musicCubes : Transform[];

private var lastHitCube : GameObject;


function Start() 
{
	audio.Stop(); // incase PlayOnAwake is ticked
	audio.loop = false; // incase loop is ticked
	
	// check there is music in the Inspector
	if ( musicTracks.Length == 0 )
	{
		Debug.Log( " musicTracks are missing ..." );
	}
	
	// load all Music Cubes into array
	SetupArrays();
}


function Update() 
{
	if ( Input.GetMouseButtonDown(0) )
	{
		CheckForMusicCube();
	}
}

function SetupArrays()
{
	musicManager = this.transform;
	
	musicCubes = new Transform[ musicManager.childCount ];
	
	var i : int = 0;
	for ( var theTrack in musicManager )
	{
		musicCubes[ i ] = theTrack as Transform;
		i ++;
	}
}

function CheckForMusicCube()
{
	// raycast to find next clicked cube
	var ray : Ray = Camera.main.ScreenPointToRay( Input.mousePosition );
	var hit : RaycastHit;
	
	if ( Physics.Raycast( ray, hit, 1000 ) )
	{
		// Check if this is not the current selected cube
		if ( hit.collider.gameObject != lastHitCube )
		{
			//Debug.Log( "Ray Hit " + hit.collider.gameObject.name );
			var theName : String = hit.collider.gameObject.name;
			
			//var theSubName : String = theName.Substring( 0, 5 );
			//Debug.Log( theName + " : " + theSubName );
			
			if ( theName.Substring( 0, 5 ) == "track" || theName.Substring( 0, 5 ) == "Track" )
			{
				// this is now the lastHitCube
				lastHitCube = hit.collider.gameObject;
				
				audio.Stop(); // stop the current track
				
				//Debug.Log( theName.Substring( 5, 2 ) + " : " + parseInt( theName.Substring( 5, 2 ) ) );
				
				// get clip from array based on clicked cube
				var nextClipIndex : int = parseInt( theName.Substring( 5, 2 ) ) - 1;
				var nextClip : AudioClip = musicTracks[ nextClipIndex ];
				audio.clip = nextClip;
				
				audio.Play(); // play the new track
			}
		}
	}
}

1: Get rid of Input.GetButtonDown You dont need it. That might be the problem. further explaination below

2: Make sure you have a Collider attached to the cube

Why are you using a variable for the AudioClip when you dont use it?

3: Make sure you have an audioClip attached to the cube

4: The silly question, did you apply the script to the cube

Why you need to get rid of Input.GetButtonDown: What the script does now is it checks if you clicked your mouse while hovering over the object the script is attached to, but because you have another if statement checking if you clicked with the mouse youll need to click twice in 1 frame. So thats probably your problem. If that doesnt work, use the other 3 checks.

So this is what I was talking about:

//Start code
#pragma strict
private var play = false;

function Update(){

    if(play){
        audio.Play();
    }
}

function OnMouseDown(){

    play = true;
    yield WaitForSeconds(audio.clip.lenght);
    play = false;

}

This should work fine. I havent tested it though.