Unity UI.Button not registering Pointer events - unity3d

I'm trying to learn Unity again and one of the many (seemingly easily) things I'm struggling with is trying to get my ButtonEvents script to fire when interacting with my Button UI component.
I'm trying to get my script to log to the console when either a PointerEnter, PointerExit or PointerClick event happens - but nothing gets logged to the Console when playing the scene.
I've noticed that if I placed this on a TextMeshPro canvas, the events work, but not when applied to by UI Button (created via UI -> Button - TextMeshPro)
This must be something simple that I'm missing not knowing about Unity Editor.
Thanks for any help!
Hierarchy (EventSystem component is included):
Inspector:
Scene:
Here is my ButtonEvents script:
using System;
using UnityEngine;
using UnityEngine.EventSystems;
namespace UI
{
public class ButtonEvents : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public static event Action<GameObject, PointerEventData> OnPointerEnterEvent;
public static event Action<GameObject, PointerEventData> OnPointerClickEvent;
public static event Action<GameObject> OnPointerExitEvent;
public void OnPointerEnter(PointerEventData pointerEventData)
{
OnPointerEnterEvent?.Invoke(gameObject, pointerEventData);
Debug.Log("OnPointerEnter");
}
public void OnPointerExit(PointerEventData pointerEventData)
{
OnPointerExitEvent?.Invoke(gameObject);
Debug.Log("OnPointerExit");
}
public void OnPointerClick(PointerEventData pointerEventData)
{
OnPointerClickEvent?.Invoke(gameObject, pointerEventData);
Debug.Log("OnPointerClick");
}
}
}

OK, so after exhausting other options, I created a new version of the Button - the only thing different I can see is that the new Button uses the Image component and now everything works - the events all seem fine in the Unity Editor Console.

Related

How to detect an air-tap without having to point something with the cursor/pointer?

I’m making a HoloLens 2 app using Unity and MRTK, I need to instantiate a gameObject in the coordinates of the user hand when the user performs an Air-tap gesture, I was trying to achieve this using IMixedRealityInputHandler, but the problem is that in order to detect the air-tap gesture, the user need to be pointing towards the gameObject that has the script to implements that interface attached,
Any idea about how can I detect the air-tap mid-air without the need of pointing something directly?
To listens for input events and disregarding what GameObject in focus, you can create a component registered global input handlers, more information please see:Register for global input events
To provide a more specific answer, I've provided test code below. This is based on the answer by Hernando.
...you can create a component registered global input handlers, more
information please see:Register for global input events
using Microsoft.MixedReality.Toolkit;
using Microsoft.MixedReality.Toolkit.Input;
using UnityEngine;
public class AirTapper : MonoBehaviour, IMixedRealityGestureHandler
{
private void OnEnable()
{
// Instruct Input System that we would like to receive all input events of type IMixedRealityGestureHandler
CoreServices.InputSystem?.RegisterHandler<IMixedRealityGestureHandler>(this);
}
private void OnDisable()
{
// Instruct Input System to disregard all input events of type IMixedRealityGestureHandler
CoreServices.InputSystem?.UnregisterHandler<IMixedRealityGestureHandler>(this);
}
public void OnGestureStarted(InputEventData eventData)
{
Debug.Log("Gesture started: " + eventData.MixedRealityInputAction.Description);
}
public void OnGestureUpdated(InputEventData eventData)
{
}
public void OnGestureCompleted(InputEventData eventData)
{
Debug.Log("Gesture completed: " + eventData.MixedRealityInputAction.Description);
}
public void OnGestureCanceled(InputEventData eventData)
{
}
}

what reference should I put inside Button void OnClick() in unity

When I start to play , it can't jump to the next scene .It also pumps out many error ,one error repeats many times , Coroutine couldn't be started because the the game object 'FadeOut' is inactive!It made me confused since the rawimage is all black and must be inactive before the function onclick.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class ToLoading : MonoBehaviour
{
public Button toLoad;
public RawImage fadeOut;
public Text loading;
// Start is called before the first frame update
void Start() //need to SetActive(false); ? if I set it false already in unity
{
}
// Update is called once per frame
void Update()
{
ButtonClicked();
}
public void ButtonClicked() //
{
fadeOut.gameObject.SetActive(true);
loading.gameObject.SetActive(true);
StartCoroutine(ToNextScene());
}
//going to do: fade out> 2 secoonds > to next scene
private IEnumerator ToNextScene()
{
yield return new WaitForSeconds(2);
SceneManager.LoadScene("SceneForMovingAround");
}
}
My question is : Should I put this script ToLoading to the fadeout rawimage ,or create an empty gameobject then put the script to it .Also , how to solve the problem -fade out error.And last , will it a problem about the code of scene part ?all of your help is appreciated, thanks!
Your ButtonClicked() method is executed every frame, which causes the unwanted behaviour your describe.
Remove the entire Update() method with its body from your file and run your game again.
Add gameObject.SetActive(false); to your ButtonClicked() method to deactivate the button upon clicking.
If you have attached the ButtonClicked() method to the OnClick() event in the inspector as you show in your screenshot then it should work as you would expect.

Unity, I have problem with DontDestroyOnLoad to keep tracking in different scence

im new in unity and i have a problem
I am making a game that have 2 scence(Main Menu Scence and Game Scence), i put my music on Main Menu scence. I make a empty game object and i attach audio source there(music) , and i also attach script like this :
First script
public static KeepTheMusicOn Instance;
void Awake()
{
if (!Instance)
Instance = this;
else
Destroy(this.gameObject);
DontDestroyOnLoad(this.gameObject);
}
With that script i can keep music play in second scence wihtout restart the music, and in the main menu scence i have settings that have button to mute the music , the button will run my second script .
Second Script:
public AudioSource mainMusic;
public void Update()
{
DontDestroyOnLoad(mainMusic);
}
public void MusicOnOff()
{
if (mainMusic.isPlaying)
{
mainMusic.Pause();
}
else
{
mainMusic.UnPause();
}
}
My problem is when i start the game so im in my main menu scence i can mute the music with the button, but when i go to game scence and i back to menu, the button dont do anything.
So that is my problem, i hope anyone can help me. Sorry for my bad english.
Sounds like when switching scenes you destroy the button. When you them go back to the main menu you destroy the duplicate instance of your audio controller thing => references configured in the Button are lost.
In your case since you use a public Singleton anyway you could as well (ab)use it and put a component on the Button itself instead (thus the reference can not get lost) and do something like e.g.
[RequireComponent(typeof(Button))]
public class MusicButton : MonoBehaviour
{
[SerializeField] private Button button;
private void Awake()
{
if(!button) button = GetComponemt<Button>();
// dynamically add the callback
// it won't appear in the editor but get called in onClick
button.onClick.AddListener(OnClicked);
}
private void OnClicked()
{
KeepTheMusicOn.Instance.MusicOnOff();
}
}
If you prefer seeing it in the editor you can ofcourse as well rove it from Awake, make the OnClicked public and reference it in the button's onClick event manually.

SyncVar not changing Bool on button press Unity 3d

This is my first networking project. I tried to follow some tutorials and this is what I'm running into: I'm trying to simply change a boolean when a button is clicked. The button is in one scene and the text object down here is in another scene. So i'm running the same network manager in two separate scenes. I realize this isn't conventional but it has to be this way for my project. All I'm looking for right now is for it to change the text, once I understand how that happened, I'm sure I can figure out the rest.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
public class textChanger : NetworkBehaviour
{
Text text;
[SyncVar]
bool change = false;
// Use this for initialization
void Start ()
{
text = gameObject.GetComponent<Text>();
}
// Update is called once per frame
void Update ()
{
if(change)
{
text.text = "it worked";
}
}
[Command]
public void CmdChangeText()
{
change = true;
}
}
If I set "change" to true with a keypress, the code operates exactly as it should, the text changes. But it's not working when i click the button from the other scene. I'm using Networking Hud and the two scenes are in fact connected. But the variable is not updating.
In the first picture, the "Text" gameObject is running the "Text Changer" script. And in the second picture, the button has the generic "Game Object" object running it too. You can see it referenced in the buttons onClick area that's calling the "CmdChangeText" method on the "Text Changer" script.
So in my head, everything looks like it should be working, but it's not. Can someone help?
From the Unity Documentation:
These variables will have their values sychronized from the server to clients
So if you try to set in on a client it won't work. It only can be done using a [Command] like you already did.
You should also check your console output. As far as I know In order to be able to call a Command method, the holding NetworkIdentity has to be set to LocalPlayerAuthority. I always had to put a special class for all commands on the Player object itself in order to make it work.
I know this is maybe not an answer but atleast a workaround:
Instead of waiting for the [SyncVar] you could just directly set the value using a [ClientRpc]:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
public class textChanger : NetworkBehaviour {
Text text;
private bool change = false;
// Use this for initialization
void Start () {
text = gameObject.GetComponent<Text>();
}
// Update is called once per frame
void Update () {
if(change)
{
text.text = "it worked";
}
}
[Command]
public void CmdChangeText()
{
// sets the value on the server
change = true;
RpcChangeText();
}
// This is executed on ALL clients
// SyncVar is no longer needed
[ClientRpc]
private void RpcChangeText()
{
change = true;
}
}

Cannot call IVirtualButtonEventHandler Vuforia 5.0.10

Im using Unity 4.7.0 and Vuforia 5.0.10, i cannot call the IVirtualButtonEventHandler.
using UnityEngine;
using System.Collections;
public class VBEventHandler : MonoBehaviour, IVirtualButtonEventHandler
{
}
I just came across this, hope you're still using Unity & Vuforia. You need to add using Vuforia to make the call.
using UnityEngine;
using System.Collections;
using Vuforia;
Register the Virtual Button:
To add a virtual button to an image target, add the VirtualButton element and its attributes to the ImageTarget element in the .xml file.
XML Attributes:
Name - a unique name for the button
Rectangle - defined by the four corners of the rectangle in the
target's coordinate space
Enabled - a boolean indicating whether the button should be enabled
by default
Sensitivity - HIGH, MEDIUM, LOW sensitivity to occlusion
After Registering Virtual Button Code is simple then:
using UnityEngine;
using System.Collections;
using Vuforia;
public class Custom_VirtualButton : MonoBehaviour, IVirtualButtonEventHandler
{
// Use this for initialization
void Start () {
// here it finds any VirtualButton Attached to the ImageTarget and register it's event handler and in the
//OnButtonPressed and OnButtonReleased methods you can handle different buttons Click state
//via "vb.VirtualButtonName" variable and do some really awesome stuff with it.
VirtualButtonBehaviour[] vbs = GetComponentsInChildren<VirtualButtonBehaviour>();
foreach (VirtualButtonBehaviour item in vbs)
{
item.RegisterEventHandler(this);
}
}
// Update is called once per frame
void Update () {
}
#region VirtualButton
public void OnButtonPressed(VirtualButtonAbstractBehaviour vb)
{
Debug.Log("Helllllloooooooooo");
}
public void OnButtonReleased(VirtualButtonAbstractBehaviour vb)
{
Debug.Log("Goooooodbyeeee");
}
#endregion //VirtualButton
}