Разные звуки, разные цели изображения и одна кнопка. Vuforia (Unity3d)

#c# #unity3d #vuforia

#c# #unity3d #vuforia

Вопрос:

Я собираюсь распознать несколько целей изображения, и я хотел бы воспроизвести звук с помощью onClick (кнопка). Эта кнопка находится на холсте и всегда находится сверху в течение всего срока службы приложения. Чтобы вы могли видеть это всегда. За этой кнопкой вы можете видеть вид камеры и распознавать маркеры.

Например, у меня есть два маркера: собака и корова. Собака присвоила звук — лай. Cow назначил audio — muu.

Когда я узнаю корову -> нажимаю кнопку, и она должна издавать звук muu, но когда я узнаю собаку, та же кнопка при нажатии должна издавать звук лая. Вот проблема. Я не могу это решить. Я думаю, мне следует написать скрипт для этой кнопки, чтобы воспроизводить звук при нажатии на соответствующий маркер, но я не знаю, как сообщить кнопке, что теперь я могу видеть корову, а в другой раз — собаку.

Я создал скрипт, который воспроизводит звук при распознавании изображения, но я хотел бы сделать это с помощью button.

Если что-то недостаточно понятно — дайте мне знать, и я напишу это лучше или заново.

Пока что в моем «отслеживаемом обработчике событий по умолчанию» это того стоит:

 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 amp;amp;
                 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
}
  

Ответ №1:

Итак, если я вас правильно понял, ваш код в основном работает нормально, но вместо непосредственного воспроизведения соответствующего звука для распознанной цели вы хотите воспроизводить его только при нажатии кнопки, верно?

Вы могли бы просто добавить метод PlayCurrentSound и ссылаться на него в 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);
}
  

и вместо этого в OnTrackableStateChanged только измените значение currentSoundName вместо его прямого воспроизведения

 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 amp;amp;
             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 = "";
    }
}
  

Однако есть некоторые другие мелочи, которые я бы также изменил:

 soundTarget.loop = false;
soundTarget.playOnAwake = false;
  

это уже можно сделать при запуске игры, только один раз и не следует повторять каждый раз. Так что делайте это в:

 private void Awake()
{
    soundTarget.loop = false;
    soundTarget.playOnAwake = false;
}
  

чем

 clipTarget = (AudioClip)Resources.Load(ss);
  

загружает (возможно) один и тот же звук снова и снова из ресурсов… не очень эффективно. Возможно, вы захотите сохранить ссылку после загрузки, например

 private Dictionary<string, AudioClip> clips = new Dictionary<string, AudioClip>();

void playSound(string ss)
{
    if(clips.ContainsKey(ss) amp;amp; 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();
}
  

Вы также можете захотеть использовать soundTarget.PlayOneShot(clipTarget) вместо этого. Разница в том, что PlayOneShot воспроизводится весь звук целиком и разрешаются одновременные звуки, в то время как Play прерывается текущий звук и запускается новый (зависит от ваших потребностей).

Комментарии:

1. Пожалуйста, посмотрите добавленный код в конце. Функция onclick PlayCurrentSound () по какой-то причине не видит, и редактор ругается на строковый метод. Слишком много белого пространства. Не ругайте, только начал осваивать Unity3d и c# 🙂

2. извините, это должно быть !string.IsNullOrWhiteSpace(currentSoundName) это не отображается, поскольку есть ошибки компилятора, и Unity пока не обновила доступные методы