I'm trying to make a toolbar system in my game but I can’t find a ways to detect a mouse click on a UI element only or to detect if it's over it, the regular detect system isn’t working.
I tried:
void OnMouseDown()
{
Debug.Log(“yay”);
}
But the message is never logged.
You can use EventSystems interfaces on your UI elements:
IPointerClickHandler
IPointerEnterHandler
IPointerExitHandler
For example in your case:
public class test : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Click");
}
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("Enter");
}
public void OnPointerExit(PointerEventData eventData)
{
Debug.Log("Exit");
}
}
Make sure your Scene has an EventSystem to make it works.
IsPointOverGameObject
The UI can be distinguished through the methods in the link above.
You can use it like below.
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (EventSystem.current.IsPointerOverGameObject())
{
Debug.Log("Clicked UI");
}
else
{
Debug.Log("Clicked Not UI");
}
}
}
Related
This is my code, I saw a lot of tutorial and made the same thing but it's not working,
the button is pressed when camera detects the target without using my hand
public GameObject cannon;
public GameObject btn;
// Start is called before the first frame update
void Start()
{
btn.GetComponent<VirtualButtonBehaviour>().RegisterOnButtonPressed(onButtonPressed);
btn.GetComponent<VirtualButtonBehaviour>().RegisterOnButtonReleased(onButtonReleased);
}
public void onButtonPressed(VirtualButtonBehaviour vb)
{
Debug.Log("clicked");
cannon.SetActive(true);
}
public void onButtonReleased(VirtualButtonBehaviour vb)
{
Debug.Log("released");
cannon.SetActive(false);
}
I am trying to build a input system from the ground up and it gave me this error. I've gone over the tutorial many time but still can't find the error.
Here's my code :
public class InputManager : MonoBehaviour
{
private PlayerInput playerInput;
private PlayerInput.OnFootActions onFoot;
void Awake()
{
playerInput = new PlayerInput();
onFoot = playerInput.OnFoot;
}
// Update is called once per frame
void Update()
{
}
private void OnEnable()
{
onFoot.Enable();
}
private void OnDisable()
{
onFoot.Disable();
}
}
Unity has a new inputsystem where the old OnMouseDown() {} no longer works.
In the migration guide they mention replacing this with Mouse.current.leftButton.isPressed.
And in other forum posts they mention using an InputAction.
The problem is that these options detect mouse clicks anywhere in the scene, instead of just on the object:
public InputAction clickAction;
void Awake() {
clickAction.performed += ctx => OnClickedTest();
}
void OnClickedTest(){
Debug.Log("You clicked anywhere on the screen!");
}
// this doesn't work anymore in the new system
void OnMouseDown(){
Debug.Log("You clicked on this specific object!");
}
How can I detect mouse clicks on a specific gameObject with the new input system in Unity?
With this code somewhere in your scene:
using UnityEngine.InputSystem;
using UnityEngine;
public class MouseClicks : MonoBehaviour
{
[SerializeField]
private Camera gameCamera;
private InputAction click;
void Awake()
{
click = new InputAction(binding: "<Mouse>/leftButton");
click.performed += ctx => {
RaycastHit hit;
Vector3 coor = Mouse.current.position.ReadValue();
if (Physics.Raycast(gameCamera.ScreenPointToRay(coor), out hit))
{
hit.collider.GetComponent<IClickable>()?.OnClick();
}
};
click.Enable();
}
}
You can add an IClickable Interface to all GameObjects that want to respond to clicks:
public interface IClickable
{
void OnClick();
}
and
using UnityEngine;
public class ClickableObject : MonoBehaviour, IClickable
{
public void OnClick()
{
Debug.Log("somebody clicked me");
}
}
Make sure you have a an EventSystem with an InputSystemUIInputModule in the scene and a PhysicsRaycaster or Physics2DRaycaster on your Camera, and then use the IPointerClickHandler interface on the object with a collider on itself or its children:
using UnityEngine;
using UnityEngine.EventSystems;
public class MyClass : MonoBehaviour, IPointerClickHandler {
public void OnPointerClick (PointerEventData eventData)
{
Debug.Log ("clicked");
}
}
Basically, I am designing a game where I need a canvas image element to respond quickly and move along when it is dragged. So for that, I am implementing IDragHandler interface. But the method OnDrag gets called after a delay of about half second.
public class InputHandler : MonoBehaviour, IDragHandler
{
public void OnDrag(PointerEventData eventData)
{
// this gets logged after about 500 milliseconds
Debug.Log("mouse dragged");
}
}
I've attached this script on the same image element that I want to move along with the drag. This element has raycast target on and the graphic raycast component is enabled for its parent canvas. The image element falls behind the touch point initially but catch up later on because of which it feels like there is some lag in the input. Is there a way to remove/minimize this delay?
The lag might be due to the DragThreshold that is active by default. You can disable it this way:
public class OnDragScript : MonoBehaviour, IDragHandler, IInitializePotentialDragHandler
{
public void OnDrag(PointerEventData ped)
{
transform.Translate(ped.delta);
}
public void OnInitializePotentialDrag(PointerEventData ped)
{
ped.useDragThreshold = false;
}
}
Although I am not finding any delay. Perhaps you should start with 3 functions (begin, drag and end) to find out what exactly is happening.
Also, the IDragHandler works only for canvas elements. So your pointer should be within the boundaries of UI element while you begin your drag.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class InputHandler : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
public void OnDrag(PointerEventData eventData)
{
Debug.Log("OnDrag");
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("Drag Begin");
}
public void OnEndDrag(PointerEventData eventData)
{
print("Drag End");
}
}
I have a prefab representing a room. I have a unity event that is fired when a player enters, I have an event listener that changes the state of the room when the event is raised. it also changes the state of any copies of the prefab instead of the room that triggered the event.
How do I narrow the scope of an event to only the instance of the gameobject that triggers the event?
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
RoomEnter.Raise();
}
public class GameEventListener : MonoBehaviour
{
[Tooltip("Event to register with.")]
public GameEvent Event;
[Tooltip("Response to invoke when Event is raised.")]
public UnityEvent Response;
private void OnEnable()
{
Event.RegisterListener(this);
}
private void OnDisable()
{
Event.UnregisterListener(this);
}
public void OnEventRaised()
{
Response.Invoke();
}
}
public class GameEvent : ScriptableObject
{
/// The list of listeners that this event will notify if it is raised.
private readonly List<GameEventListener> eventListeners =
new List<GameEventListener>();
public void Raise()
{
for(int i = eventListeners.Count -1; i >= 0; i--)
eventListeners[i].OnEventRaised();
}
public void RegisterListener(GameEventListener listener)
{
if (!eventListeners.Contains(listener))
eventListeners.Add(listener);
}
public void UnregisterListener(GameEventListener listener)
{
if (eventListeners.Contains(listener))
eventListeners.Remove(listener);
}
}
Why use event? When the player enter, just call the method of THIS room.
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
GetComponent<GameEventListener>().OnEventRaised();
}
}