Проблема в том, что, если вы нажмете клавиши достаточно быстро, возможно вызвать многократный обратный вызов события в течение одного кадра.Таким образом, если змея идет вниз, она может повернуть направо, а затем вверх в том же кадре, изменяя направление и съедая себя.Я предложу два способа решения этой проблемы:
Первый - установить флаг при изменении направления, например:
if allowedDirections.indexOf(newDirection) > -1 and !turnedThisFrame
Snake.direction = newDirection
turnedThisFrame = true
, а затем в вашем коде, который запускается каждыйframe, установите turnedThisFrame
на false
.
Второе - это переделать то, как вы справляетесь с нажатиями клавиш.Это часто подход, который я использую.Сохраните карту, на которой нажаты клавиши (скажем, keysDown
), и свяжите функцию, которая устанавливает keysDown[e.which] = true
на нажатие клавиши, и другую функцию, которая устанавливает keysDown[e.which] = false
на нажатие клавиши.Затем вы можете проверить, какие клавиши нажимаются в коде, выполняющем каждый кадр, и действовать соответствующим образом.
Вот некоторые подробности о том, как я реализовал второе решение в текущем проекте.Следующий код появляется в моем обработчике загрузки:
do ->
keysDown = []
$(document).keydown (e) ->
keysDown.push e.which
$(document).keyup (e) ->
keysDown = _.without keysDown, e.which
window.isPressed = (keyCode) -> keyCode in keysDown
Конструкция do ->
используется для создания функции и немедленного ее вызова, что имеет полезный эффект, заключающийся в сохранении keysDown
в закрытии для обработчиков иisPressed
, избегая при этом загрязнения основной области обратного вызова onload
.
Затем, в начале моей функции tick
(которая запускается один раз за кадр и обрабатывает игровую логику, рисование экрана и т. Д.).) У меня было бы что-то вроде этого:
switch Snake.direction
when UP, DOWN
allowedDirections = [LEFT, RIGHT]
when LEFT, RIGHT
allowedDirections = [UP, DOWN]
for direction in allowedDirections
if isPressed(directionToKey[direction])
Snake.direction = newDirection
break
Карта directionToKey
была бы просто противоположностью вашей keysToDirections
.
Обратите внимание, что это означает, что ключи, перечисленные первыми в allowedDirections
будет иметь приоритет, т. Е. Если вы идете направо и нажимаете вверх и вниз в одном и том же кадре, вверх произойдет независимо от того, какое нажатие было первым.
Дополнительное преимущество этого второго метода: вы не делаетеПри переключении между, скажем, экраном меню и игрой приходится менять обратные вызовы обработчика клавиш.У вас просто есть другая функция tick
, проверяющая, что было нажато.