Javascript змея игра яблочный респаун

1

Я сделал змеиную игру на 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>
  • 3
    Если вы вызываете свою функцию 15 раз в секунду, то проверяйте каждые 60 вызовов, съели ли яблоки или нет, а затем сбросьте счетчик.
  • 1
    Насколько я знаю, вы можете установить столько интервалов, сколько вы хотите в Javascript, и все они будут работать правильно ..
Теги:

2 ответа

1
Лучший ответ

Другой подход (уже упоминавшийся в комментариях) заключается в том, чтобы выразить ваш "максимальный возраст яблока" с точки зрения кадров, а не секунд.

Поскольку у вас уже есть основной игровой цикл в 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>
  • 0
    Вы помогли мне лучше понять, что я ищу, но даже когда я реализовал ваш код в этом, он все равно не работает, через 3 секунды яблоко просто сходит с ума и постоянно появляется везде, я действительно не могу выяснить, почему он это делает.
  • 0
    Вы удостоверились, что различие между кадрами и секундами . 3 кадра -> яблоко движется 5 раз в секунду. 3 * 15 = 45 кадров -> яблоко движется каждые 3 секунды.
Показать ещё 4 комментария
0

Вы можете иметь несколько интервалов в 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);

Ещё вопросы

Сообщество Overcoder
Наверх
Меню