Doris232 发表于 2022-10-12 08:30

Unity XR Interaction Toolkit 模拟 GetKey vs GetKeyDown

Get Key New Input System

虽然网上有铺天盖地的关于 Unity New Input System 的教程,以及之前我也写过几篇,但是不可否认, GetKey, GetKeyDown 和 GetKeyUp 在一些场景非常好用。

[*]GetKey:只要按键被按着,就会返回 true
[*]GetKeyDown: 被按下的那一刻,返回 true
[*]GetKeyUp:按下,但当松开的那一刻,返回 true
这个让使用 New Input System 的人苦恼,比如能看到很多这类问题:What's the equivalent of GetKey in the new unity input system?
但是最近发现了几个方法,首先是这篇Input in Unity made easy (complete guide to the new system) 里面提到了 Input System equivalents for Get Key and Get Key Down:
Input System equivalents for Get Key and Get Key Down
Using Unity’s old Input Manager, working out if a key was pressed once or if it was held down (for movement for example) was done by checking for Get Key for a held button or Get Key Down for a single press.
In the new Input System, you would typically do this by setting the Action Type, which decides how the Action will be triggered. For example, a Button Action Type will typically only be triggered once, the equivalent of Get Key Down, while a Value Action Type gets triggered continuously as the control value changes, the equivalent to Get Key in the old system.给出了答案,在新的 Input System 中我们经常会设置 Action Type,但是 Button Action 只会被 trigger 一次,就是 Get Key Down 的时候,那么如果我们想要连续的输入,我们可以换成 Value type,然后就会有连续的数值。
实际上我在 XR Interaction Toolkit 获取 Oculus Quest Joystick 的数据 中尝试解决一个类似的问题,就是 Joystick 给的是连续的数据,而我只想要首次被 trigger 的数据,我不想要 button ,因为 Joystick 给的数据是 Vector2, 然后我可以看这个数据是炒作还是超右,最终是通过 Binding Propety - Interactions 来解决了这个。
比如之前看到别人设置的 Hand Prefab 里面也是这样设置,然后达到 hand animation 的效果:
private void GripPressed(InputAction.CallbackContext context)
{
    handAnimator.SetFloat("Grip", context.ReadValue<float>());   
}
another way

另外,在 Unity XR Input 中还看到了另一种方法,假设我就只有 get key 这个,用来模拟 get key down 和 get key up 感觉也不是特别难,可能我还需要一个 wasPressed, isPressed 等 bool 就能完成,看看官方是怎么做的:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR;


public class PrimaryButtonEvent : UnityEvent<bool> { }

public class PrimaryButtonWatcher : MonoBehaviour
{
    public PrimaryButtonEvent primaryButtonPress;

    private bool lastButtonState = false;

    ....

    void Update()
    {
      bool tempState = false;
      foreach (var device in devicesWithPrimaryButton)
      {
            bool primaryButtonState = false;
            tempState = device.TryGetFeatureValue(CommonUsages.primaryButton, out primaryButtonState) // did get a value
                        && primaryButtonState // the value we got
                        || tempState; // cumulative result from other controllers
      }

      if (tempState != lastButtonState) // Button state changed since last frame
      {
            primaryButtonPress.Invoke(tempState);
            lastButtonState = tempState;
      }
    }
}
关键点:
代码的注释写的很清楚,关键就是在这几句:
bool tempState = false;
      foreach (var device in devicesWithPrimaryButton)
      {
            bool primaryButtonState = false;
            tempState = device.TryGetFeatureValue(CommonUsages.primaryButton, out primaryButtonState) // did get a value
                        && primaryButtonState // the value we got
                        || tempState; // cumulative result from other controllers
      }
那实际上这个 tempState != lastButtonState 实际上包含了,从没有动作 → 按下,或者从按下→松开,所以里面针对 tempState == true 写下 if 那就是 getKeyDown, 针对 tempState == false 写下 if 就是 getKeyUp。
参考:

[*]Input in Unity made easy (complete guide to the new system)
[*]What is the difference between Getkey and Getkeydown (C#)
页: [1]
查看完整版本: Unity XR Interaction Toolkit 模拟 GetKey vs GetKeyDown