The problem is that if you press the keys fast enough, you can trigger a multiple call of the event within one frame. Thus, if the snake goes down, it can turn to the right, and then up into the same frame, thereby changing direction and eating itself. I suggest two ways to solve this problem:
The first is to set the flag when changing direction, that is:
if allowedDirections.indexOf(newDirection) > -1 and !turnedThisFrame Snake.direction = newDirection turnedThisFrame = true
and then in your code that fires each frame, set turnedThisFrame to false .
Secondly, rework how you deal with keystrokes. This is often the approach that I take. Save the map that the keys are pressed on (say keysDown ), and attach a function that sets keysDown[e.which] = true to keydown and another function that sets keysDown[e.which] = false to keyup. Then you can check which keys are pressed in the code that launches each frame and act accordingly.
Here are some details about how I implemented the second solution in the current project. The following code appears in my onload handler:
do -> keysDown = [] $(document).keydown (e) -> keysDown.push e.which $(document).keyup (e) -> keysDown = _.without keysDown, e.which window.isPressed = (keyCode) -> keyCode in keysDown
The do -> construct do -> used to create a function and call it immediately, which has a beneficial effect on keeping keysDown in closure for handlers and isPressed , while avoiding contamination of the main area onload Callback.
Then, at the beginning of my tick function (which runs once for each frame and processes the game logic, draws a screen, etc.), I would have something like this:
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
The directionToKey map will be just the opposite of your keysToDirections .
Note that this means that the keys listed first in allowedDirections will take precedence, i.e. if you go right and press both up and down in the same frame, up will happen no matter what the first press.
An added benefit to this second method: you donβt need to change the key handler callbacks when switching between, say, a menu screen and a game. You have another tick function that checks that it is pressed.