Я сделал змеиную игру на JavaScript, и она отлично работает. То, что я хочу воплотить в эту игру, состоит в том, что если змея не ела яблоко через 5 или 10 секунд, яблоко снова появляется в другом месте. Хотя очевидно, что я должен использовать setInterval
, он не работает, потому что у меня уже есть установленный интервал, который вызывает функцию игры 15 раз в секунду. Я не могу найти способ отложить эту функцию перемещения яблока по своему желанию. Любая помощь будет принята с благодарностью.
Вот мой код для игры:
window.onload = function() {
canv = document.getElementById("gc");
ctx = canv.getContext("2d");
document.addEventListener("keydown", keyPush);
setInterval(game, 1000 / 15);
}
px = py = 10;
gs = tc = 20;
ax = ay = 15;
xv = yv = 0;
trail = [];
tail = 5;
function game() {
px += xv;
py += yv;
if (px < 0) {
px = tc - 1;
}
if (px > tc - 1) {
px = 0;
}
if (py < 0) {
py = tc - 1;
}
if (py > tc - 1) {
py = 0;
}
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canv.width, canv.height);
ctx.fillStyle = "lime";
for (var i = 0; i < trail.length; i++) {
ctx.fillRect(trail[i].x * gs, trail[i].y * gs, gs - 2, gs - 2);
if (trail[i].x == px && trail[i].y == py) {
tail = 5;
}
}
trail.push({
x: px,
y: py
});
while (trail.length > tail) {
trail.shift();
}
if (ax == px && ay == py) {
tail++;
ax = Math.floor(Math.random() * tc);
ay = Math.floor(Math.random() * tc);
}
ctx.fillStyle = "red";
ctx.fillRect(ax * gs, ay * gs, gs - 2, gs - 2);
}
function keyPush(evt) {
switch (evt.keyCode) {
case 37:
xv = -1;
yv = 0;
break;
case 38:
xv = 0;
yv = -1;
break;
case 39:
xv = 1;
yv = 0;
break;
case 40:
xv = 0;
yv = 1;
break;
}
}
<canvas id="gc" width="400" height="400"></canvas>
Другой подход (уже упоминавшийся в комментариях) заключается в том, чтобы выразить ваш "максимальный возраст яблока" с точки зрения кадров, а не секунд.
Поскольку у вас уже есть основной игровой цикл в 15 кадров в секунду, вы можете использовать эту частоту кадров для создания вашей яблочной логики:
В игровом состоянии (в вашем случае глобальная область):
var appleAge = 0;
var fps = 15;
var maxAppleAgeSeconds = 3;
var maxAppleAgeFrames = maxAppleAgeSeconds * fps;
В game
функции:
if (/* hits apple */) {
tail++;
/* make new apple */
appleAge = 0;
} else {
appleAge++;
if (appleAge > maxAppleAgeFrames) {
/* make new apple */
appleAge = 0;
}
}
Некоторые общие рекомендации:
var
(или, если вы используете более современные языковые функции let
и const
)Используйте больше функций, чтобы сделать ваш код более легким для чтения, понимания и обслуживания. Например:
// Hard to understand what this does...
ax = Math.floor(Math.random() * tc);
ay = Math.floor(Math.random() * tc);
// Easier to understand:
function moveAppleToRandomLocation() {
ax = Math.floor(Math.random() * tc);
ay = Math.floor(Math.random() * tc);
}
// elsewhere:
moveAppleToRandomLocation();
Изменения в фрагменте:
// TODO: fix var. declarations
window.onload = function() {
canv = document.getElementById("gc");
ctx = canv.getContext("2d");
document.addEventListener("keydown", keyPush);
setInterval(game, 1000 / 15);
}
px = py = 10;
gs = tc = 20;
ax = ay = 15;
xv = yv = 0;
trail = [];
tail = 5;
// New:
var fps = 15;
var maxAppleAgeSeconds = 5;
var appleAge = 0;
var maxAppleAgeFrames = fps * maxAppleAgeSeconds;
function game() {
px += xv;
py += yv;
if (px < 0) {
px = tc - 1;
}
if (px > tc - 1) {
px = 0;
}
if (py < 0) {
py = tc - 1;
}
if (py > tc - 1) {
py = 0;
}
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canv.width, canv.height);
ctx.fillStyle = "lime";
for (var i = 0; i < trail.length; i++) {
ctx.fillRect(trail[i].x * gs, trail[i].y * gs, gs - 2, gs - 2);
if (trail[i].x == px && trail[i].y == py) {
tail = 5;
}
}
trail.push({
x: px,
y: py
});
while (trail.length > tail) {
trail.shift();
}
appleAge++;
if (ax == px && ay == py) {
tail++;
ax = Math.floor(Math.random() * tc);
ay = Math.floor(Math.random() * tc);
appleAge = 0;
} else if (appleAge > maxAppleAgeFrames) {
ax = Math.floor(Math.random() * tc);
ay = Math.floor(Math.random() * tc);
appleAge = 0;
}
ctx.fillStyle = "red";
ctx.fillRect(ax * gs, ay * gs, gs - 2, gs - 2);
}
function keyPush(evt) {
switch (evt.keyCode) {
case 37:
xv = -1;
yv = 0;
break;
case 38:
xv = 0;
yv = -1;
break;
case 39:
xv = 1;
yv = 0;
break;
case 40:
xv = 0;
yv = 1;
break;
}
}
<canvas id="gc" width="400" height="400"></canvas>
Вы можете иметь несколько интервалов в javascript и будете работать нормально, см. Ниже фрагмент, например.. Так что в вашем случае вы можете добавить что-то вроде этого:
let gameInterval = setInterval(game, 1000/15);
let appleInterval = setInterval(() => { /* your apple function goes here */}, 1000/5);
let a = setInterval(() => {console.log("every 2 seconds")}, 2000);
let b = setInterval(() => {console.log("every 3 seconds")}, 3000);