Я впервые пишу игру на холсте 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
}
}
Как это может выглядеть при использовании: