I am going to recognize few imageTargets and I would like to play sound with onClick(button). This button is on canvas and it is always on top during the app lifetime. So You can see it always. Behind this button You can see camera view and recognize markers.
F.e I have two markers: Dog and Cow. Dog has assigned audio - bark. Cow has assigned audio - muu.
When I recognize Cow -> click the button and it should give me muu sound, but when I recognize Dog, the same button, when clicked should give me bark sound. Here is a problem. I cannot resolve it. I think I should write a script for this button to play sound onClick for appropriate marker, but I do not know how to tell button that now I can see Cow and another time I can see Dog.
I made a script which plays sound when image is recognized, but I would like to do it with button.
If something is not clear enough - let me know and I will write it better or again.
So far in my "Default trackable event handler" it’s worth it:
using UnityEngine;
using Vuforia;
public class DefaultTrackableEventHandlerEng : MonoBehaviour, ITrackableEventHandler
{
//------------Begin Sound----------
public AudioSource soundTarget;
public AudioClip clipTarget;
private AudioSource[] allAudioSources;
//function to stop all sounds
void StopAllAudio()
{
allAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
foreach (AudioSource audioS in allAudioSources)
{
audioS.Stop();
}
}
//function to play sound
void playSound(string ss)
{
clipTarget = (AudioClip)Resources.Load(ss);
soundTarget.clip = clipTarget;
soundTarget.loop = false;
soundTarget.playOnAwake = false;
soundTarget.Play();
}
//-----------End Sound------------
#region PROTECTED_MEMBER_VARIABLES
protected TrackableBehaviour mTrackableBehaviour;
protected TrackableBehaviour.Status m_PreviousStatus;
protected TrackableBehaviour.Status m_NewStatus;
#endregion // PROTECTED_MEMBER_VARIABLES
#region UNITY_MONOBEHAVIOUR_METHODS
protected virtual void Start()
{
mTrackableBehaviour = GetComponent<TrackableBehaviour>();
if (mTrackableBehaviour)
mTrackableBehaviour.RegisterTrackableEventHandler(this);
//Register / add the AudioSource as object
soundTarget = (AudioSource)gameObject.AddComponent<AudioSource>();
}
protected virtual void OnDestroy()
{
if (mTrackableBehaviour)
mTrackableBehaviour.UnregisterTrackableEventHandler(this);
}
#endregion // UNITY_MONOBEHAVIOUR_METHODS
#region PUBLIC_METHODS
/// <summary>
/// Implementation of the ITrackableEventHandler function called when the
/// tracking state changes.
/// </summary>
///
public void OnTrackableStateChanged(
TrackableBehaviour.Status previousStatus,
TrackableBehaviour.Status newStatus)
{
m_PreviousStatus = previousStatus;
m_NewStatus = newStatus;
if (newStatus == TrackableBehaviour.Status.DETECTED ||
newStatus == TrackableBehaviour.Status.TRACKED ||
newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
{
Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " found");
if (mTrackableBehaviour.TrackableName == "1")
{
playSound("audio/1_eng");
}
if (mTrackableBehaviour.TrackableName == "2")
{
playSound("audio/2_eng");
}
if (mTrackableBehaviour.TrackableName == "3")
{
playSound("audio/3_eng");
}
OnTrackingFound();
}
else if (previousStatus == TrackableBehaviour.Status.TRACKED &&
newStatus == TrackableBehaviour.Status.NO_POSE)
{
Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost");
StopAllAudio();
OnTrackingLost();
}
else
{
// For combo of previousStatus=UNKNOWN + newStatus=UNKNOWN|NOT_FOUND
// Vuforia is starting, but tracking has not been lost or found yet
// Call OnTrackingLost() to hide the augmentations
OnTrackingLost();
}
}
#endregion // PUBLIC_METHODS
#region PROTECTED_METHODS
protected virtual void OnTrackingFound()
{
var rendererComponents = GetComponentsInChildren<Renderer>(true);
var colliderComponents = GetComponentsInChildren<Collider>(true);
var canvasComponents = GetComponentsInChildren<Canvas>(true);
// Enable rendering:
foreach (var component in rendererComponents)
component.enabled = true;
// Enable colliders:
foreach (var component in colliderComponents)
component.enabled = true;
// Enable canvas':
foreach (var component in canvasComponents)
component.enabled = true;
}
protected virtual void OnTrackingLost()
{
var rendererComponents = GetComponentsInChildren<Renderer>(true);
var colliderComponents = GetComponentsInChildren<Collider>(true);
var canvasComponents = GetComponentsInChildren<Canvas>(true);
// Disable rendering:
foreach (var component in rendererComponents)
component.enabled = false;
// Disable colliders:
foreach (var component in colliderComponents)
component.enabled = false;
// Disable canvas':
foreach (var component in canvasComponents)
component.enabled = false;
}
#endregion // PROTECTED_METHODS
}
So if I understand you correctly your code basically works fine but instead of directly playing the according sound for the recognized target you instead want to only play it if a button is clicked, right?
You could simply add a method PlayCurrentSound
and reference it in the onClick
:
// SET THIS NAME INSTEAD OF DIRECTLY PLAYING IT
private string currentSoundName;
// THIS IS THE METHOD CALLED BY THE BUTTON
public void PlayCurrentSound()
{
if(!string.IsNullOrWhiteSpace(currentSoundName)) playSound(currentSoundName);
}
and instead in OnTrackableStateChanged
only change the value of currentSoundName
instead of directly replaying it
public void OnTrackableStateChanged(TrackableBehaviour.Status previousStatus, TrackableBehaviour.Status newStatus)
{
m_PreviousStatus = previousStatus;
m_NewStatus = newStatus;
if (newStatus == TrackableBehaviour.Status.DETECTED ||
newStatus == TrackableBehaviour.Status.TRACKED ||
newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
{
Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " found");
// HERE BETTER USE A SWITCH INSTEAD
switch(mTrackableBehaviour.TrackableName)
{
case "1":
currentSoundName = "audio/1_eng";
break;
case "2":
currentSoundName = "audio/2_eng";
break;
case "3":
currentSoundName = "audio/3_eng";
break;
default:
currentSoundName = "";
break;
}
// OR ALTERNATIVELY IF YOU ANYWAY WANT TO
// SET THE NAME FOR ALL POSSIBLE NAMES YOU COULD EVEN GO
currentSoundName = string.Format("audio/{0}_eng", mTrackableBehaviour.TrackableName);
OnTrackingFound();
}
else if (previousStatus == TrackableBehaviour.Status.TRACKED &&
newStatus == TrackableBehaviour.Status.NO_POSE)
{
Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost");
StopAllAudio();
// RESET currentSoundName
currentSoundName = "";
OnTrackingLost();
}
else
{
// For combo of previousStatus=UNKNOWN + newStatus=UNKNOWN|NOT_FOUND
// Vuforia is starting, but tracking has not been lost or found yet
// Call OnTrackingLost() to hide the augmentations
OnTrackingLost();
// RESET currentSoundName
currentSoundName = "";
}
}
However there are some other tiny things I would change as well:
soundTarget.loop = false;
soundTarget.playOnAwake = false;
this can already be done on game start, only once and should not get repeated everytime. So do it in:
private void Awake()
{
soundTarget.loop = false;
soundTarget.playOnAwake = false;
}
than
clipTarget = (AudioClip)Resources.Load(ss);
loads (maybe) the same sound over and over again from the Resources ... not very efficient. You rather might want to keep the reference once loaded like
private Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>();
void playSound(string ss)
{
if(clips.ContainsKey(ss) && clip[ss] != null)
{
clipTarget = clips[ss];
else
{
clip = (AudioClip)Resources.Load(ss);
if(clipTarget == null)
{
Debug.LogError("Couldn't get clip for " + ss, this);
return;
}
clips.Add(ss, clipTarget);
}
soundTarget.clip = clipTarget;
soundTarget.Play();
}
You also might want to use soundTarget.PlayOneShot(clipTarget)
instead. The difference is that PlayOneShot
plays the whole sound and allows concurrent sounds while Play
interrupts the current sound and starts a new one (depends on your needs).