如何使用新的输入系统访问点击(桌面)/点击(移动)位置?

Posted

技术标签:

【中文标题】如何使用新的输入系统访问点击(桌面)/点击(移动)位置?【英文标题】:How to access the click (desktop) / tap (mobile) position using the new input system? 【发布时间】:2021-04-17 06:27:59 【问题描述】:

我创建了一个新的 Unity 项目并为新的输入系统安装了包。基本上我只想存储点击(桌面)/点击(移动)的位置,就是这样。

我知道旧系统提供解决方案

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

但我想用新的输入系统解决它。

我从这个输入映射配置开始(我将显示每个选定项的配置)

我创建了一个记录每个点击/点击位置的新脚本

public class FooBar : MonoBehaviour

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

在场景中我创建了一个空的游戏对象并在检查器中配置它

不幸的是,在运行播放模式时,每次移动鼠标时都会出现这些错误

这是第一条错误信息的堆栈跟踪

这是第二条错误消息的堆栈跟踪

所以我假设我的输入地图配置是错误的。

有人介意帮我设置一个输入配置,将点击/点击位置传递给脚本吗?


因此,为了快速解决问题,我目前将此代码与旧输入系统一起使用,但我真的不喜欢它;)

    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
        // 
    

【问题讨论】:

你删除your previous question但现在使用我给你的代码有什么特殊原因吗? .... @derHugo 是的,您提供的解决方案在一种情况下是正确的,但该解决方案与我发布的错误无关。因此,即使使用您的代码也可以重现此错误 你试过context.control.ReadValue&lt;Vector2&gt;()context.ReadValue()吗?仍然,如果我的解决方案是正确的并帮助了你..你为什么要关闭这个问题呢? 对 question3r 公平地说,新的和“改进的”输入系统将使任何试图使用它的人达到理智的边缘。超越。 @derHugo 我不明白为什么那个老问题(实际上是答案)被关闭了 【参考方案1】:

不确定这是否适合您,但您可以尝试一下。所以我创建了两种方法:一种用于鼠标移动,一种用于鼠标单击。当鼠标移动时,我记录它的位置并在点击时 - Debug.Log 这个位置。

public class InputDebug : MonoBehaviour

    Vector2 lastInput;

    public void Move(InputAction.CallbackContext callbackContext)
    
        lastInput = callbackContext.ReadValue<Vector2>();
    

    public void Click(InputAction.CallbackContext callbackContext)
    
        Debug.Log(lastInput);
    

输入映射如下所示:

OnMove

点击

UPD:它也适用于移动设备

【讨论】:

感谢您的帮助。问题在于手机没有“鼠标位置”或类似的东西。因此,当单击/点击时,我需要一种方法来检测点击/点击位置,而无需存储移动时的最后鼠标位置:) 谢谢但抱歉 @Question3r 我为移动支持添加了新绑定。它就像在 PC 上一样工作。看看吧。【参考方案2】:

要达到预期的结果,您需要 2 个InputAction。一个用于点击,另一个用于位置。

您的MonoBehaviour 将侦听与单击相关的InputActionperformed 事件,并从与位置相关的事件中读取位置。

Position 相关的InputAction 是可选的;因为您可以使用输入系统 API 捕捉到它。

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

对于您的用例,我建议:

    直接在MonoBehaviour中序列化InputAction 使用InputActionAsset 并从那里获取InputAction

选项 1 - 直接输入动作

为点击设置一个InputAction,为位置设置另一个。 然后您可能会听到 Click 并从 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();
    

Click 动作需要 2 个绑定。

使用 + 按钮添加投标 => 将路径设置为:鼠标/左键 使用 + 按钮添加投标 => 将路径设置为:TouchScreen/Primary Touch/Tap

该职位需要 2 个绑定。

使用 + 按钮添加投标 => 将路径设置为:鼠标/位置 使用 + 按钮添加 Bidning => 将路径设置为:TouchScreen/Primary Touch/Position

您的组件将如下所示:

选项 2 - InputActionAsset

    创建InputMapAsset。 从编辑器:Assets -> Create -> InputActions。称它为“YourMap”

    删除所有动作,然后添加 2 个动作。

A. “点击”动作 动作类型:按钮 绑定鼠标 => 鼠标/左键 绑定 TouchScreen => TouchScreen/Primary Touch/Tap

B. “定位”动作 操作类型:值 绑定鼠标 => 鼠标/位置 绑定 TouchScreen => TouchScreen/Primary Touch/Position

看起来像这样:

您可以将“YourMap”作为InputActionAsset 引用为MonoBehaviour 的一个字段,并使用FindAction 方法捕获InputAction,使用字符串名称(“Click”和“位置”)。

    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; 
    

几个考虑

新的输入系统的设计使设计人员可以使用PlayerInput 类完成所有操作,而无需编码。结果不会像上面提供的解决方案那样高效。 我将鼠标/触摸设置为单击一次。您还可以按住、双击或滚动将Interactions 添加到Bindings。 理论上,您可以使用TouchScreen 类中的ReadOnlyArray&lt;TouchControl&gt; 对触摸屏使用一个InputAction 来获得相同的结果,但在这种情况下,鼠标和触摸将具有不同的设置。阅读更多关于 Mouse 和 Touch 支持的信息。

【讨论】:

嗯,这听起来有点像您也可以简单地使用Input.mousePositionInput.GetTouch(0).position ...那么这个新系统的全部目的是什么? ^^ 这对我来说看起来不错。但是有没有办法将所有代码移到编辑器设计器中?因为目前没有优势……我希望有一个通用的平台解决方案。我丑陋的解决方法代码更小,但是是的,它在更新循环中运行。但是还是…… 希望从callback 参数中简单地读取点击/点击位置,仅此而已 由于要求很高,我使用 InputActionAsset 添加了解决方案,而不是直接使用 InputAction。我不喜欢依赖字符串,但这是另一种解决方案。无论如何你想听按钮回调,所以它没有鼠标位置。您可以直接获取它,也可以使用地图中的另一个输入操作(我在代码中提供了这两个选项)。 我大大编辑了答案。现在只有 InputAction 的解决方案也不需要基于平台的分离。 @derHugo,您可以使用代码或 InputAction 获取位置,但您无法从按下鼠标按钮的回调中获取它,因为它只有按钮按下事件。您可能会使用触摸屏,但在这种情况下,您需要将实现与#if 分开。

以上是关于如何使用新的输入系统访问点击(桌面)/点击(移动)位置?的主要内容,如果未能解决你的问题,请参考以下文章

Android系统,如何设置某个应用程序不允许访问网络?

如何在Windows 8/8.1系统中设置VPN

win10为啥我无法更改账户名称

如何开启电脑的远程服务?

苹果系统下如何格式化移动硬盘

如何开启远程访问权限