10

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?

5 Answers 5

14

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");
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

That still requires an object. What if you need to detect whether a click was clicked anywhere on the screen? Say you have a context menu appearing right next to the cursor, which pops up when a user clicks on something. Seems like an incredibly common and trivial thing to do in a game. But now there is no way to make it disappear if the user clicks anywhere on the screen. And if we make the hack of having a giant invisible button behind the menu, that means the other UI elements won't be clickable while the menu is active.
4

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");
    }
 }

3 Comments

But it's not the new Input system. EventSystems is from the Unity UI package.
What is "the object"? I need to be able to detect whether a click was clicked anywhere on the screen. I'm implementing a context menu which appears next to the user's cursor (like when you right click in Windows or Mac). If they click anywhere, it should disappear. I could make "the object" be a giant invisible button that appears right behind the menu. But consider this: Now the other UI elements won't get the click event. If the user wanted to click one of those while the menu was active, it won't work for that click.
@Peyotle - InputSystemUIInputModule is in fact from the new Input System. Yes, the EventSystem is from the UI package, as is PhysicsRaycaster: the UI package has the Unity-supplied solution for what Kolja is doing manually. The new Input System is a replacement for UnityEngine.Input, not for the UI package. @pete - This is what the original question already had solved with Mouse.current.leftButton.isPressed - the question was in fact about clicking an object.
1

You can also just use

Mouse.current.leftButton.wasPressedThisFrame

With a Raycast and a object with a collider in world space it would look like this:

RaycastHit hit;
        Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
        if (Physics.Raycast(ray, out hit) && hit.transform.name == "TargetObjName")
        {
print("PointerOnObj");
            if (Mouse.current.leftButton.wasPressedThisFrame)
            {
                print("clicked");
            }
        }

Comments

0

For me, it seems the answer lies in the context type:

InputAction.CallbackContext

The way I did it was using the context "canceled" property. When it is false, that means the mouse press just occurred. When it is true, that means the mouse press has been caneceled (and then indicating a OnMouseUp event).

It seems it has a few properties to make this fit other use cases, such as a duration indicating how long the button was down etc.

Comments

0

For the 2D version of @Kolja's answer:

void Awake() 
{
    click = new InputAction(binding: "<Mouse>/leftButton");

    click.performed += ctx =>
    {
        Vector2 screenPos = Mouse.current.position.ReadValue();
        Vector2 worldPos = gameCamera.ScreenToWorldPoint(screenPos);

        // 2D raycast
        RaycastHit2D hit = Physics2D.Raycast(worldPos, Vector2.zero);

        if (hit.collider != null)
        {
            hit.collider.GetComponent<IClickable>()?.OnClick();
        }
    };

    click.Enable();
}

Rest of the logic is the same.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.