I want a simple UI navigation sound to play when the player selects different items in the menu. My menu UI is built with buttons, so the simple solution is this: add a script to the buttons with ISelectHandler and use the function OnSelect to play a sound.
Easy peasey, now I just slap that script on all my buttons and they all play the sound when that item gets selected.
Well the first issue I ran into is that when my menus open they play that select sound instead of the menu open sound. This is because when a menu opens I have to tell the event system what button to have selected so that keyboard/controller navigation will actually work.
I got around this by adding a bool for “don’tSound” into the button sounder script. When a menu opens, before telling the event system to select its starting item, it checks for the buttonSounder and enables that bool, and then the buttonSounder, if it sees that bool enabled, doesn’t sound on the next OnSelect.
Okay, so far so good.
But the problem I’m facing now is this: if the player uses a mouse and directly clicks on a button, it plays the OnSelect sound. This quickly grows annoying because I hear the select sound play for just a moment before we play the sound for opening the next menu or closing that menu or whatever the case may be. Honestly, no matter what the function that may be called next, if I directly click on a button I don’t want the selection sound to play because that’s just meant for navigation.
I can’t find an acceptable way to get the select sound to not play when clicking on a button. I tried adding the interface for OnPointerClick so I could have that just immediately stop playing the select noise, but this doesn’t get called right away. With some debug logs I’ve revealed that OnSelect gets called, it runs the commands associated with that button, and THEN OnPointerClick gets called. I will literally be in a new menu trying to play a menu-open sound before OnPointerClick gets called.
What the hell, Event System?
I tried using OnSubmit but this doesn’t get called when I click a button directly.
So I’m at a loss here. How can I stop or cancel my select sound when I click on a button?
If I understand, you’re having controls that allow you to move your “selection” up and down, maybe by using the up and down arrows. Then, you also allow mouse usage which allows you to mouse over a button and click on it. My suggestion would be to have your method of selecting something control the sfx for the selection. So, up and down arrows would play the audio instead for example vs the button onSelect playing the audio sound. You could still have the audio sfx on the button with a method you could call. So, when you hit down, it moves the selection, checks if that item has an script on it to play an audio, and tell it to play it.
Hopefully that makes sense. That may be better than trying to counter the audio that plays on selection. Note that this could even address your other issue of when the menu firsts opens, even though you’ve handle that, this could handle both of your cases.
That would be a good suggestion if I were creating my own navigation system.
However, I’m using the one that comes built in to Unity.
These are just buttons placed on a canvas, completely default to Unity’s UI and Event systems.
To enable keyboard/controller navigation, I have a script that assigns a button to be selected when the menu opens. After that you can navigate through buttons with a keyboard or mouse.
But buttons also work with mouse input, and quite frankly, my menus need to support both because my game supports both.
But I need some way to make buttons sound when you select them with a controller but not when you directly click them.
OnSelect includes eventData, so you could do this. In this case, when OnSelect runs, it checks if the left mouse button is clicked as well. So, if you detect the left mouse button click, don’t play your audio. If it doesn’t detect the mouse click, play your audio. Or whatever you want. You can also detect key presses as well with the GetButtonDown to detect if the up or down arrow is hit instead.
That almost works. What is the code I need to call when I’ve switched to the new input system?
For some reason the documentation isn’t pulling up BaseEventData.
No clue if it’s any different. I know the OnSelect method which is part of the ISelectHandler interface. This requires the Using UnityEngine.EventSystems; I’m not sure if what input system matters.
You still failed to provide additional details on how you’re currently handling the OnSelect code. Instead of pointing out if it matters or not, it would be more helpful to see how your current Select code works. I’m trying to help, but I’m certainly not able to look up everything with the new system as I haven’t used it beyond FPS controls.
Do you have to implement an OnSelect method? Does that take a parameter?
It’s nothing fancy. This is the whole script right now:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class ButtonSounder : MonoBehaviour, ISelectHandler
{
[HideInInspector]
public bool bQuietThisOne;
[Tooltip("alternate sounds to play, If empty, will play the default sound. Otherwise, will randomly pick one of these.")]
public AudioClip[] overrideSounds;
public void OnSelect(BaseEventData eventData)
{
//Debug.Log("Select!");
if (bQuietThisOne)
{
bQuietThisOne = false;
return;
}
/*
if (eventData.currentInputModule.input.GetMouseButtonDown(0)) // This doesn't work with the new input system
{
Debug.Log("MOUSE BUTTON");
return;
}
*/
if (overrideSounds.Length < 1)
{
GameManager.HUD.PlayUINavigateSound();
}
else
{
GameManager.HUD.PlayCustomSound(overrideSounds[Random.Range(0, overrideSounds.Length)], false);
}
}
/*
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("PointerClick!");
}
public void OnSubmit(BaseEventData eventData)
{
Debug.Log("Submit!");
}
*/
}
But of as I said, the OnPointerClick gets called after the new menu opens, and the eventData code suggested earlier gives me the error I posted, presumably because I’m using the New Input system instead of the default one.