im making a simple little snake game and i found a bug that is hard to explain and/or recreate but in game when putting inputs in rapidly in such a way you should not die you will just randomly die.
Heres a link to game landons-snake-gamev45.tiiny.site
Heres the code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Landon's Snake Game</title>
<style>
#game-container {
position: relative;
width: 520px; /* Adjust width as necessary */
margin: auto;
}
canvas {
display: block;
border: 5px solid #009BFF;
margin: auto;
}
#speedMenu {
position: absolute;
top: 10px;
right: 10px;
z-index: 1;
}
</style>
</head>
<body>
<div id="game-container">
<canvas id="gameCanvas" width="520" height="520"></canvas>
<button id="pauseButton">Pause</button>
<select id="speedMenu">
<option value="1">Normal</option>
<option value="0.75">Slow</option>
<option value="1.55">Hard</option>
<option value="3">Extreme</option>
</select>
</div>
<script>
var
COLS = 26,
ROWS = 26,
EMPTY = 0,
SNAKE = 1,
FRUIT = 2,
POWER_UP = 3,
LEFT = 0,
UP = 1,
RIGHT = 2,
DOWN = 3,
KEY_LEFT = 37,
KEY_UP = 38,
KEY_RIGHT = 39,
KEY_DOWN = 40,
canvas,
ctx,
keystate,
frames,
score,
paused = false,
powerUpActive = false,
powerUpTimer = 0,
powerUpDuration = 30 * 60,
grid = {
width: null,
height: null,
_grid: null,
init: function(d, c, r) {
this.width = c;
this.height = r;
this._grid = [];
for (var x=0; x < c; x++) {
this._grid.push([]);
for (var y=0; y < r; y++) {
this._grid[x].push(d);
}
}
},
set: function(val, x, y) {
this._grid[x][y] = val;
},
get: function(x, y) {
return this._grid[x][y];
}
},
snake = {
direction: null,
last: null,
_queue: null,
init: function(d, x, y) {
this.direction = d;
this._queue = [];
this.insert(x, y);
},
insert: function(x, y) {
this._queue.unshift({x:x, y:y});
this.last = this._queue[0];
},
remove: function() {
return this._queue.pop();
}
};
function setFood() {
var empty = [];
for (var x=0; x < grid.width; x++) {
for (var y=0; y < grid.height; y++) {
if (grid.get(x, y) === EMPTY) {
empty.push({x:x, y:y});
}
}
}
var randpos = empty[Math.round(Math.random() * empty.length - 1)];
var spawnType = Math.random() < 0.075 ? POWER_UP : FRUIT;
grid.set(spawnType, randpos.x, randpos.y);
}
function main() {
canvas = document.getElementById("gameCanvas");
ctx = canvas.getContext("2d");
ctx.font = "12px Helvetica";
frames = 0;
keystate = {};
document.addEventListener("keydown", function(evt) {
keystate[evt.keyCode] = true;
if (evt.keyCode === 80) {
paused = !paused;
if (paused) {
document.getElementById("pauseButton").innerText = "Resume";
} else {
document.getElementById("pauseButton").innerText = "Pause";
}
}
});
document.addEventListener("keyup", function(evt) {
delete keystate[evt.keyCode];
});
document.getElementById("pauseButton").addEventListener("click", function() {
paused = !paused;
if (paused) {
document.getElementById("pauseButton").innerText = "Resume";
} else {
document.getElementById("pauseButton").innerText = "Pause";
}
});
var speedMenu = document.getElementById("speedMenu");
speedMenu.addEventListener("change", function() {
adjustSpeed(this.value);
});
init();
loop();
}
function init() {
score = 0;
powerUpActive = false;
powerUpTimer = 0;
keystate = {};
grid.init(EMPTY, COLS, ROWS);
var sp = {x: Math.floor(COLS / 2), y: ROWS - 1};
snake.init(UP, sp.x, sp.y);
grid.set(SNAKE, sp.x, sp.y);
setFood();
}
function loop() {
if (!paused) {
update();
draw();
}
window.requestAnimationFrame(loop, canvas);
}
function update() {
frames++;
if (powerUpActive) {
powerUpTimer++;
if (powerUpTimer >= powerUpDuration) {
powerUpActive = false;
powerUpTimer = 0;
}
}
var speedFactor = parseFloat(document.getElementById("speedMenu").value);
if (keystate[KEY_LEFT] && snake.direction !== RIGHT) {
snake.direction = LEFT;
}
if (keystate[KEY_UP] && snake.direction !== DOWN) {
snake.direction = UP;
}
if (keystate[KEY_RIGHT] && snake.direction !== LEFT) {
snake.direction = RIGHT;
}
if (keystate[KEY_DOWN] && snake.direction !== UP) {
snake.direction = DOWN;
}
if (frames % Math.floor(7 / speedFactor) === 0) {
var nx = snake.last.x;
var ny = snake.last.y;
switch (snake.direction) {
case LEFT:
nx--;
break;
case UP:
ny--;
break;
case RIGHT:
nx++;
break;
case DOWN:
ny++;
break;
}
if (0 > nx || nx > grid.width - 1 ||
0 > ny || ny > grid.height - 1 ||
grid.get(nx, ny) === SNAKE
) {
alert("Game Over! Your score is: " + score);
return init();
}
if (grid.get(nx, ny) === FRUIT || grid.get(nx, ny) === POWER_UP) {
if (grid.get(nx, ny) === POWER_UP) {
score *= 2;
powerUpActive = true;
powerUpTimer = 0;
} else {
score += powerUpActive ? 2 : 1;
}
snake.insert(nx, ny);
setFood();
} else {
var tail = snake.remove();
grid.set(EMPTY, tail.x, tail.y);
}
grid.set(SNAKE, nx, ny);
snake.insert(nx, ny);
}
}
function draw() {
var tw = canvas.width / grid.width;
var th = canvas.height / grid.height;
for (var x = 0; x < grid.width; x++) {
for (var y = 0; y < grid.height; y++) {
switch (grid.get(x, y)) {
case EMPTY:
ctx.fillStyle = "#fff";
break;
case SNAKE:
if (powerUpActive) {
var hue = (frames + x + y) % 360;
ctx.fillStyle = "hsl(" + hue + ", 100%, 50%)";
} else {
ctx.fillStyle = "#333";
}
break;
case FRUIT:
ctx.fillStyle = "#009BFF";
break;
case POWER_UP:
ctx.fillStyle = "#FF69B4"; // Pink square color
break;
}
ctx.fillRect(x * tw, y * th, tw, th);
}
}
ctx.fillStyle = "#000";
ctx.fillText("SCORE: " + score, 10, canvas.height - 10);
if (powerUpActive) {
ctx.fillText("POWER-UP ACTIVE", 10, canvas.height - 25);
}
}
main();
</script>
</body>
</html>