【问题标题】:Detect only a specific Keyboard combination in Unity仅检测 Unity 中的特定键盘组合
【发布时间】:2020-12-24 02:40:23
【问题描述】:

在我的游戏中,我需要检查特定的键盘组合,比如 Left Shift + B。 如果我正常使用 if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.B)) { Debug.Log("correct"); }

只要有这两个控件,它就会接受所有内容,所以 Left Shift + B、Left Shift + C + B、Left Shift + 任何键盘按钮,老实说 + B 也会返回 true。

我的问题是,如果只有这两个被按下,我是否能以某种方式检测到,我已经尝试在 KeyCode 中使用 foreach char c 并检测该 Input 是否是我的 B,然后将 bool 设置为正确或错误,但这并没有真正起作用. 有什么想法吗?

【问题讨论】:

  • 很遗憾地说确实没有一个好的方法可以做到这一点。每次更新都遍历每个键以检查它是否被按下,这将表现得非常糟糕。您可以通过仅考虑映射到游戏中某些内容的键来减少这种情况。不过,我觉得这样的控制方案可能会非常令人沮丧,所以我会仔细考虑你是否真的想要这样做。

标签: c# unity3d


【解决方案1】:

Event.currentOnGUI

虽然通常不再经常使用它,但您可以使用Event.current 检查OnGUI 中的输入。

每次按下按键时,将其存储在当前按下的按键列表中。当此键上升时,将其从列表中删除。然后您可以简单地检查列表是否包含相应的键以及长度是否与预期的键数量匹配。

public HashSet<KeyCode> currentlyPressedKeys = new HashSet<KeyCode>();

private void OnGUI()
{
    if (!Event.current.isKey) return;

    if (Event.current.keyCode != KeyCode.None)
    {
        if (Event.current.type == EventType.KeyDown)
        {
            currentlyPressedKeys.Add(Event.current.keyCode);
        }
        else if (Event.current.type == EventType.KeyUp)
        {
            currentlyPressedKeys.Remove(Event.current.keyCode);
        }
    }

    // Shift is actually the only Key which is not treated as a
    // EventType.KeyDown or EventType.KeyUp so it has to be checked separately
    // You will not be able to check which of the shift keys is pressed!
    if (!Event.current.shift)
    {
        return;
    }

    // As said shift is check on another way so we want only 
    // exactly 1 key which is KeyCode.B
    if (currentlyPressedKeys.Count == 1 && currentlyPressedKeys.Contains(KeyCode.B))
        Debug.Log("Only Shift + B");
}

必须在OnGUI 中完成,因为一个帧中可能有多个事件。这是独占的,只会在按下 Shift + B 时触发。

如果您宁愿将其放在场景中的某个位置并设置值 static

public class KeysManager : MonoBehaviour
{
    public static bool ShiftPressed;
    public static HashSet<KeyCode> currentlyPressedKeys = new HashSet<KeyCode>();

    private void OnGUI()
    {
        if (!Event.current.isKey) return;

        if (Event.current.keyCode != KeyCode.None)
        {
            if (Event.current.type == EventType.KeyDown)
            {
                currentlyPressedKeys.Add(Event.current.keyCode);
            }
            else if (Event.current.type == EventType.KeyUp)
            {
                currentlyPressedKeys.Remove(Event.current.keyCode);
            }
        }

        ShiftPressed = Event.current.shift;
    }
}

然后你可以像以前一样使用类似的东西

private void Update()
{
    if (KeysManager.ShiftPressed && KeysManager.currentlyPressedKeys.Count == 1 && KeysManager.currentlyPressedKeys.Contains(KeyCode.B))
    {
        Debug.Log("Only Shift + B exclusively should trigger this");
    }
}

使用Input.GetKey 遍历所有KeyCode

或者,您可以按照评论检查所有可能的键。

但是,这可能是也可能不是关于性能的问题。您必须对其进行测试并确定它在您的特定情况下是否可以接受。

using System.Linq;

...

// will store all buttons except B and LeftShift
KeyCode[] otherKeys;

private void Awake ()
{
    // This simply returns an array with all values of KeyCode
    var allKeys = (KeyCode[])Enum.GetValues(typeof(KeyCode));

    // This uses Linq Where in order to only keep entries that are different from
    // KeyCode.B and KeyCode.LeftShift
    // ToArray finally converts the IEnumerable<KeyCode> into a KeyCode[]
    otherKeys = allKeys.Where(k => k != KeyCode.B && k != KeyCode.LeftShift).ToArray();
}

private void Update()
{
    if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.B) && !AnyOtherKeyPressed())
    {
        // Happens while ONLY LeftShift + B is pressed
    }
}

// Return true if any other key
// is pressed except B and LeftShift
private bool AnyOtherKeyPressed()
{
    foreach (var keyCode in otherKeys)
    {
        if(Input.GetKey(keyCode)) return true;
    }

    return false;
}

也许我们太担心了,这并不重要(我不相信,但只是理论上 ^^)你甚至可以将它提升一个层次并使其更灵活。

[Serializable]
public class KeyCombo
{
    // Note I'll be lazy here .. you could create a custom editor 
    // for making sure each keyCode is unique .. but another time
    public List<KeyCode> keyCodes = new List<KeyCode>();

    // This will show an event in the Inspector so you can add callbacks to your keyCombos
    // this is the same thing used in e.g. Button onClick
    public UnityEvent whilePressed;

    // Here all other keyCodes will be stored
    [HideInInspector] public KeyCode[] otherKeys;

    // Return true if any other key
    // is pressed except B and LeftShift
    public bool AnyOtherKeyPressed()
    {
        foreach (var keyCode in otherKeys)
        {
            if (Input.GetKey(keyCode)) return true;
        }

        return false;
    }
}

public List<KeyCombo> keyCombos = new List<KeyCombo>();

private void Awake()
{
    // This simply returns an array with all values of KeyCode
    var allKeys = (KeyCode[])Enum.GetValues(typeof(KeyCode));

    foreach (var keyCombo in keyCombos)
    {
        // This uses Linq Where in order to only keep entries that are different from
        // the ones listed in keyCodes
        // ToArray finally converts the IEnumerable<KeyCode> into a KeyCode[]
        keyCombo.otherKeys = allKeys.Where(k => !keyCombo.keyCodes.Contains(k)).ToArray();
    }
}

private void Update()
{
    foreach (var keyCombo in keyCombos)
    {
        if (keyCombo.keyCodes.All(Input.GetKey) && !keyCombo.AnyOtherKeyPressed())
        {
            keyCombo.whilePressed.Invoke();
        }
    }
}

有了这个,您现在可以添加多个 KeyCombo 并单独检查它们 - 但是请注意,每个额外的 keyCombo 也意味着对所有其他键进行一次额外的迭代,所以......它远非完美。

【讨论】:

  • 嘿!感谢您的评论!我尝试制作一种方法,根据输入键返回真或假布尔值,但不幸的是我失败了。那是因为我错误地理解了“返回”。现在,当我阅读您的脚本时,我了解到“返回”实际上结束了该方法,因此它始终会正确返回,我迫不及待地想尝试将其添加到我的游戏中,谢谢!
【解决方案2】:

如果您正在使用Alt + Q 等组合击键,则可以使用Event.current.modifiers。类似这样的东西

        if (!Event.current.isKey || Event.current.keyCode == KeyCode.None) return;
        switch (Event.current.type) {
            case EventType.KeyDown:
                if (Event.current.modifiers == EventModifiers.Alt) {

                    switch (Event.current.keyCode) {
                        case KeyCode.Q:
                            break;
                        default:
                            break;
                    }
                }
                break;
            default:
                break;
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-19
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 2021-07-25
    相关资源
    最近更新 更多