Класс для обработки ввода с клавиатуры / мыши

Я впервые пишу игру на холсте html5. Для начала я решил создать приведенный ниже класс, чтобы я мог проверять входные данные в каждом цикле обновления. Класс может обнаруживать события нажатия клавиш / мыши вниз / вверх и отслеживать положение мыши. Я планирую добавить прокрутку мыши, если понадобится, позже.

Все мнения / предложения приветствуются!

Объяснение

После инициализации класс будет прослушивать события нажатия клавиш / мыши вверх / вниз и записывать их в state имущество. state имеет формат {[inputname]: {[press], [trigger], [release]}}. Это записи Date.now() при последнем нажатии / срабатывании / отпускании входа. press обновляется только при первом нажатии кнопки. trigger обновляется каждый раз, когда вызывается нажатие клавиши мыши / клавиши (обратите внимание, что только события нажатия клавиши повторяются, когда клавиша уже нажата). state также магазины mousePosition: {x, y}.

Ключи объекта, представляющие каждую кнопку, имеют формат `mouse${[MouseEvent.button]}` или `key${[KeyboardEvent.code]}`. Я храню часто используемые ключи как статические, но намерение состоит в том, чтобы позволить пользователям настраивать свои собственные элементы управления, поэтому для установки значений по умолчанию необходимы только «часто используемые» ключи.

использование

  • Инициализировать с помощью new Input(target). target это часть DOM, которую вы хотите прослушивать для ввода (по умолчанию document).

  • Чтобы проверить ввод, используйте check(...) а также mousePosition() методы. check принимает 3 аргумента — hash, type, buttonState и возвращает логическое значение.

    hash это входное представление, как указано выше.
    type является Input.START или Input.CURRENT. START проверяет, был ли вход нажат / запущен / отпущен, начиная с этого кадра. CURRENT просто проверяет, нажата / отпущена ли в данный момент ввод (примечание CURRENT нажатие такое же, как CURRENT срабатывает).
    buttonState является Input.PRESS, Input.TRIGGER или Input.RELEASE — в каком бы состоянии вы ни проверяли вход.

    Например. чтобы проверить, вызвал ли этот кадр нажатие клавиши возврата, вызовите .check(Input.KEYENTER, Input.START, Input.TRIGGER).

  • После проверки входов, doneCheck() нужно вызывать каждый кадр. Внутри класс отслеживает Date.now() каждый раз его вызывают. Таким образом можно избежать двойной обработки входных данных.

Код

class Input {
    static START = 0
    static CURRENT = 1

    static PRESS = 0
    static TRIGGER = 1
    static RELEASE = 2

    static MOUSE = 'mouse'
    static KEY = 'key'

    static MOUSELEFT = `${Input.MOUSE}${0}`
    static MOUSEMIDDLE = `${Input.MOUSE}${1}`
    static MOUSERIGHT = `${Input.MOUSE}${2}`
    static KEYDOWN = `${Input.KEY}${'ArrowDown'}`
    static KEYLEFT = `${Input.KEY}${'ArrowLeft'}`
    static KEYRIGHT = `${Input.KEY}${'ArrowRight'}`
    static KEYUP = `${Input.KEY}${'ArrowUp'}`
    static KEYENTER = `${Input.KEY}${'Enter'}`
    static KEYSPACE = `${Input.KEY}${'Space'}`
    
    constructor(target = document) {
        this.doneCheck()
        this.state = {mousePosition: {}}
        Object.entries({
            'keydown': e => this.press(e, Input.KEY, e.code),
            'keyup': e => this.release(e, Input.KEY, e.code),
            'mousedown': e => this.press(e, Input.MOUSE, e.button),
            'mouseup': e => this.release(e, Input.MOUSE, e.button),
            'mousemove': e => this.mouseMove(e, e.x, e.y),
        }).forEach(([eventType, func]) => target.addEventListener(eventType, e => func(e)))
    }
    
    //Input
    press(e, type, input) {
        const hash = `${type}${input}`
        this.state[hash] = this.state[hash] || {[Input.PRESS]: 0, [Input.TRIGGER]: 0, [Input.RELEASE]: 0}
        this.state[hash][Input.TRIGGER] = Date.now()
        if (this.state[hash][Input.RELEASE] >= this.state[hash][Input.PRESS]) this.state[hash][Input.PRESS] = this.state[hash][Input.TRIGGER]
    }

    release(e, type, input) {
        const hash = `${type}${input}`
        this.state[hash] = this.state[hash] || {[Input.PRESS]: 0, [Input.TRIGGER]: 0, [Input.RELEASE]: 0}
        this.state[hash][Input.RELEASE] = Date.now()
    }
    
    mouseMove(e, x, y) {
        this.state.mousePosition.x = x
        this.state.mousePosition.y = y
    }
    
    //Check
    check(
        hash,
        type = Input.START, //START, CURRENT
        buttonState = Input.PRESS, //PRESS, TRIGGER, RELEASE
    ) {
        return (type === Input.START && this.state[hash] && this.checked < this.state[hash][buttonState]) ||
        (type === Input.CURRENT && (buttonState === Input.PRESS) === (this.state[hash] && this.state[hash][Input.RELEASE] < this.state[hash][Input.PRESS]))
    }
    
    doneCheck() {
        this.checked = Date.now()
    }
    
    mousePosition() {
        return this.state.mousePosition
    }
}

Как это может выглядеть при использовании:

введите описание изображения здесь

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *