Обнаружение только определенной комбинации клавиш в Unity - PullRequest
1 голос
/ 26 сентября 2019

В моей игре мне нужно проверить определенную комбинацию клавиш, скажем, Сдвиг влево + B .Если я сделаю это нормально с if(Input.GetKey(KeyCode.LeftShift) && Input.GetKey(KeyCode.B)) { Debug.Log("correct"); }

, он будет принимать все, если у него есть эти два элемента управления, так что, если честно, левый Shift + B, левый Shift + C + B, левый Shift + любая кнопка клавиатуры+ B также вернет true.

Мой вопрос заключается в том, что если я смогу каким-то образом определить, были ли нажаты ТОЛЬКО эти два, я уже попытался перейти к foreach char c в KeyCode и определить, был ли этот ввод моим B, а затем установить bool.исправить или ложь, но это на самом деле не работает.Есть идеи?

1 Ответ

1 голос
/ 26 сентября 2019

Event.current и OnGUI

Хотя обычно он не используется так часто, вы можете проверить ввод в OnGUI, используя Event.current.

Каждый раз, когда клавиша нажимается, сохраняйте ее в списке нажатых клавиш.Когда этот ключ идет вверх, удалите его из списка.Затем вы можете просто проверить, содержит ли список соответствующие ключи и соответствует ли длина ожидаемому количеству ключей.

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

Теперь вы можете добавить несколько KeyCombos и проверить их по отдельности - однако имейте в видучто каждый дополнительный keyCombo также означает одну дополнительную итерацию по всем остальным ключам, так что ... это далеко от совершенства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...