Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access the click (desktop) / tap (mobile) position using the new input system?

Tags:

c#

unity3d

I created a new Unity project and installed the package for the new Input system. Basically I just want to store the position of a click (desktop) / tap (mobile), that's it.

I know the old system provides solutions

  • https://docs.unity3d.com/ScriptReference/Input-mousePosition.html
  • https://docs.unity3d.com/ScriptReference/Touch-position.html

but I want to solve it with the new input system.

I started with this input map configuration (I will show the configuration for each selected item)

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

I created a new script logging each click/tap position

public class FooBar : MonoBehaviour
{
    public void Select(InputAction.CallbackContext context)
    {
        Vector2 selectPosition = context.ReadValue<Vector2>();
        Debug.Log($"Select position is: {selectPosition.x}|{selectPosition.y}");
    }
}

In the scene I created an empty gameobject and configured it in the inspector

enter image description here

Unfortunately when running the playmode I get these errors each time when moving the mouse around

enter image description here

This is the stacktrace of the first error message

enter image description here

and this is the stacktrace of the second error message

enter image description here

So I'm assuming my input map configuration is wrong.

Would someone mind helping me setting up an input configuration passing the click/tap position to the script?


So for a quick workaround I currently use this code with the old input system but I really don't like it ;)

    public sealed class SelectedPositionStateController : MonoBehaviour
    {
        private void Update()
        {
#if UNITY_ANDROID || UNITY_IOS
            if (UnityEngine.Input.touchCount > 0)
            {
                Touch touch = UnityEngine.Input.GetTouch(0);
                
                // do things with touch.position
            }
#elif UNITY_STANDALONE
            if (UnityEngine.Input.GetMouseButtonDown(0))
            {
                // do things with Input.mousePosition
            }
#endif
        }
        
        // !!! USE THIS CODE BECAUSE IT'S OBVIOUSLY BETTER !!!
        // 
        // public void SelectPosition(InputAction.CallbackContext context)
        // {
        //     Vector2 selectedPosition = context.ReadValue<Vector2>();
        //     
        //     // do things with selectedPosition
        // }
    }
like image 996
Question3r Avatar asked Jan 12 '21 10:01

Question3r


People also ask

How do I add touch input in unity?

Add the Multi-Touch Display component to MultiTouch and drag the UI text object into the Multi Touch Info Display slot. 8. Build and run your project on your physical or emulated Android device. Using as many fingers as you can, experiment with mixing the order in which you touch and lift fingers.

How do I get mouse position in unity?

In Unity, getting the mouse position on the screen is fairly straightforward. It's a property of the Input class so, to access it from a script, all you need to do is use Input. mousePosition, which returns the position of the mouse, in pixels, from the bottom left of the screen.


1 Answers

To achieve the desired outcome you will need 2 InputAction. One for the Click, and another for the Position.

Your MonoBehaviour will listen to the performed event of InputAction related to the Click and read the Position from the one related to Position.

The InputAction related to Position is optional; as you may catch it with the input system API.

  • Touchscreen.current.primaryTouch.position.ReadValue()
  • Mouse.current.position.ReadValue()

For your use case I suggest either:

  1. Serialize the InputAction directly in the MonoBehaviour
  2. Use an InputActionAsset and get the InputAction from there

OPTION 1 - Direct InputAction

Setup one InputAction for the Click, and another for the Position.
Then you might listen to the Click and catch the position from the Position.

public class InputWithAction : MonoBehaviour
{
    // --------------- FIELDS AND PROPERTIES --------------- //
    [SerializeField] private InputAction _click;
    [SerializeField] private InputAction _pos;

    // --------------- INITIALIZATION --------------- //
    private void Process(InputAction.CallbackContext callback)
    {
        //get the value from the position
        Debug.Log($"Input action: {_pos.ReadValue<Vector2>()}");
        //use the items below if you want to get the input directly
#if UNITY_ANDROID || UNITY_IOS
        //gets the primary touch position using the new input system
        Debug.Log(Touchscreen.current.primaryTouch.position.ReadValue());
#elif UNITY_STANDALONE
        //gets the current mouse position using the new input system
        Debug.Log(Mouse.current.position.ReadValue());
#endif
    }

    // --------------- LISTENER SETUP --------------- //
    private void OnEnable()
    {
        _click.Enable();
        _pos.Enable();
        _click.performed += Process;
    }

    private void OnDisable()
    {
        _click.performed -= Process;
        _click.Disable();
        _pos.Disable();
    }
}

The Click action requires 2 bindings.

  • Add a Bidning with the + button => set the Path as: Mouse/Left Button
  • Add a Bidning with the + button => set the Path as: TouchScreen/Primary Touch/Tap

The Position requires 2 bindings.

  • Add a Bidning with the + button => set the Path as: Mouse/Position
  • Add a Bidning with the + button => set the Path as: TouchScreen/Primary Touch/Position

Your component will look like this:

enter image description here

OPTION 2 - The InputActionAsset

  1. Create the InputMapAsset.
    From the Editor: Assets -> Create -> InputActions. Call it "YourMap"

  2. Remove all the actions and then add 2 actions.

A. "Click" action Action Type: Button
Binding Mouse => Mouse/LeftButton
Binding TouchScreen => TouchScreen/Primary Touch/Tap

B. "Position" action Action Type: Value
Binding Mouse => Mouse/Position
Binding TouchScreen => TouchScreen/Primary Touch/Position

It will look like this:

enter image description here

You can reference "YourMap" as InputActionAsset as a field of your MonoBehaviour and catch the InputAction with the FindAction method, using the string names ("Click" and "Position").

    public class InputWithMap : MonoBehaviour
    {
        // --------------- FIELDS AND PROPERTIES --------------- //
        [SerializeField] private InputActionAsset _inputMap;
        private InputAction _click;
        private InputAction _pos;

        private void Start()
        {
            //enable is required only if you're not using PlayerInput anywhere else
            _inputMap.Enable();

            _click = _inputMap.FindAction("Click");
            _pos   = _inputMap.FindAction("Position");

            //listen from clicks
            _click.performed += Process;
        }

        // --------------- INITIALIZATION --------------- //
        private void Process(InputAction.CallbackContext callback)
        {
            //get the value from the position
            Debug.Log($"Input action: {_pos.ReadValue<Vector2>()}");
        }

        private void OnDestroy() { _click.performed -= Process; }
    }

A FEW CONSIDERATIONS

  • The new input system was designed so that designers might do everything with PlayerInput class, without coding. The result wouldn't be as performant as the solutions offered above.
  • I setup the mouse/touch to catch one click. You might catch also hold, double click or scroll adding Interactions to the Bindings.
  • In theory you might achieve the same result using just one InputAction for the Touch Screen using ReadOnlyArray<TouchControl> from TouchScreen class, but in that case Mouse and Touch would have a different setup. Read more for Mouse and Touch support.
like image 196
Jack Mariani Avatar answered Oct 21 '22 01:10

Jack Mariani